@ckeditor/ckeditor5-table 44.3.0 → 45.0.0-alpha.1

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 (374) hide show
  1. package/LICENSE.md +1 -1
  2. package/build/table.js +2 -2
  3. package/build/translations/af.js +1 -1
  4. package/build/translations/ar.js +1 -1
  5. package/build/translations/ast.js +1 -1
  6. package/build/translations/az.js +1 -1
  7. package/build/translations/be.js +1 -0
  8. package/build/translations/bg.js +1 -1
  9. package/build/translations/bn.js +1 -1
  10. package/build/translations/bs.js +1 -1
  11. package/build/translations/ca.js +1 -1
  12. package/build/translations/cs.js +1 -1
  13. package/build/translations/da.js +1 -1
  14. package/build/translations/de-ch.js +1 -1
  15. package/build/translations/de.js +1 -1
  16. package/build/translations/el.js +1 -1
  17. package/build/translations/en-au.js +1 -1
  18. package/build/translations/en-gb.js +1 -1
  19. package/build/translations/eo.js +1 -1
  20. package/build/translations/es-co.js +1 -1
  21. package/build/translations/es.js +1 -1
  22. package/build/translations/et.js +1 -1
  23. package/build/translations/eu.js +1 -1
  24. package/build/translations/fa.js +1 -1
  25. package/build/translations/fi.js +1 -1
  26. package/build/translations/fr.js +1 -1
  27. package/build/translations/gl.js +1 -1
  28. package/build/translations/gu.js +1 -1
  29. package/build/translations/he.js +1 -1
  30. package/build/translations/hi.js +1 -1
  31. package/build/translations/hr.js +1 -1
  32. package/build/translations/hu.js +1 -1
  33. package/build/translations/hy.js +1 -1
  34. package/build/translations/id.js +1 -1
  35. package/build/translations/it.js +1 -1
  36. package/build/translations/ja.js +1 -1
  37. package/build/translations/jv.js +1 -1
  38. package/build/translations/kk.js +1 -1
  39. package/build/translations/km.js +1 -1
  40. package/build/translations/kn.js +1 -1
  41. package/build/translations/ko.js +1 -1
  42. package/build/translations/ku.js +1 -1
  43. package/build/translations/lt.js +1 -1
  44. package/build/translations/lv.js +1 -1
  45. package/build/translations/ms.js +1 -1
  46. package/build/translations/nb.js +1 -1
  47. package/build/translations/ne.js +1 -1
  48. package/build/translations/nl.js +1 -1
  49. package/build/translations/no.js +1 -1
  50. package/build/translations/oc.js +1 -1
  51. package/build/translations/pl.js +1 -1
  52. package/build/translations/pt-br.js +1 -1
  53. package/build/translations/pt.js +1 -1
  54. package/build/translations/ro.js +1 -1
  55. package/build/translations/ru.js +1 -1
  56. package/build/translations/si.js +1 -1
  57. package/build/translations/sk.js +1 -1
  58. package/build/translations/sl.js +1 -1
  59. package/build/translations/sq.js +1 -1
  60. package/build/translations/sr-latn.js +1 -1
  61. package/build/translations/sr.js +1 -1
  62. package/build/translations/sv.js +1 -1
  63. package/build/translations/th.js +1 -1
  64. package/build/translations/ti.js +1 -1
  65. package/build/translations/tk.js +1 -1
  66. package/build/translations/tr.js +1 -1
  67. package/build/translations/tt.js +1 -1
  68. package/build/translations/ug.js +1 -1
  69. package/build/translations/uk.js +1 -1
  70. package/build/translations/ur.js +1 -1
  71. package/build/translations/uz.js +1 -1
  72. package/build/translations/vi.js +1 -1
  73. package/build/translations/zh-cn.js +1 -1
  74. package/build/translations/zh.js +1 -1
  75. package/ckeditor5-metadata.json +64 -6
  76. package/dist/index-content.css +50 -25
  77. package/dist/index-editor.css +115 -16
  78. package/dist/index.css +226 -60
  79. package/dist/index.css.map +1 -1
  80. package/dist/index.js +3128 -2275
  81. package/dist/index.js.map +1 -1
  82. package/dist/translations/af.js +1 -1
  83. package/dist/translations/af.umd.js +1 -1
  84. package/dist/translations/ar.js +1 -1
  85. package/dist/translations/ar.umd.js +1 -1
  86. package/dist/translations/ast.js +1 -1
  87. package/dist/translations/ast.umd.js +1 -1
  88. package/dist/translations/az.js +1 -1
  89. package/dist/translations/az.umd.js +1 -1
  90. package/dist/translations/be.d.ts +8 -0
  91. package/dist/translations/be.js +5 -0
  92. package/dist/translations/be.umd.js +11 -0
  93. package/dist/translations/bg.js +1 -1
  94. package/dist/translations/bg.umd.js +1 -1
  95. package/dist/translations/bn.js +1 -1
  96. package/dist/translations/bn.umd.js +1 -1
  97. package/dist/translations/bs.js +1 -1
  98. package/dist/translations/bs.umd.js +1 -1
  99. package/dist/translations/ca.js +1 -1
  100. package/dist/translations/ca.umd.js +1 -1
  101. package/dist/translations/cs.js +1 -1
  102. package/dist/translations/cs.umd.js +1 -1
  103. package/dist/translations/da.js +1 -1
  104. package/dist/translations/da.umd.js +1 -1
  105. package/dist/translations/de-ch.js +1 -1
  106. package/dist/translations/de-ch.umd.js +1 -1
  107. package/dist/translations/de.js +1 -1
  108. package/dist/translations/de.umd.js +1 -1
  109. package/dist/translations/el.js +1 -1
  110. package/dist/translations/el.umd.js +1 -1
  111. package/dist/translations/en-au.js +1 -1
  112. package/dist/translations/en-au.umd.js +1 -1
  113. package/dist/translations/en-gb.js +1 -1
  114. package/dist/translations/en-gb.umd.js +1 -1
  115. package/dist/translations/en.js +1 -1
  116. package/dist/translations/en.umd.js +1 -1
  117. package/dist/translations/eo.js +1 -1
  118. package/dist/translations/eo.umd.js +1 -1
  119. package/dist/translations/es-co.js +1 -1
  120. package/dist/translations/es-co.umd.js +1 -1
  121. package/dist/translations/es.js +1 -1
  122. package/dist/translations/es.umd.js +1 -1
  123. package/dist/translations/et.js +1 -1
  124. package/dist/translations/et.umd.js +1 -1
  125. package/dist/translations/eu.js +1 -1
  126. package/dist/translations/eu.umd.js +1 -1
  127. package/dist/translations/fa.js +1 -1
  128. package/dist/translations/fa.umd.js +1 -1
  129. package/dist/translations/fi.js +1 -1
  130. package/dist/translations/fi.umd.js +1 -1
  131. package/dist/translations/fr.js +1 -1
  132. package/dist/translations/fr.umd.js +1 -1
  133. package/dist/translations/gl.js +1 -1
  134. package/dist/translations/gl.umd.js +1 -1
  135. package/dist/translations/gu.js +1 -1
  136. package/dist/translations/gu.umd.js +1 -1
  137. package/dist/translations/he.js +1 -1
  138. package/dist/translations/he.umd.js +1 -1
  139. package/dist/translations/hi.js +1 -1
  140. package/dist/translations/hi.umd.js +1 -1
  141. package/dist/translations/hr.js +1 -1
  142. package/dist/translations/hr.umd.js +1 -1
  143. package/dist/translations/hu.js +1 -1
  144. package/dist/translations/hu.umd.js +1 -1
  145. package/dist/translations/hy.js +1 -1
  146. package/dist/translations/hy.umd.js +1 -1
  147. package/dist/translations/id.js +1 -1
  148. package/dist/translations/id.umd.js +1 -1
  149. package/dist/translations/it.js +1 -1
  150. package/dist/translations/it.umd.js +1 -1
  151. package/dist/translations/ja.js +1 -1
  152. package/dist/translations/ja.umd.js +1 -1
  153. package/dist/translations/jv.js +1 -1
  154. package/dist/translations/jv.umd.js +1 -1
  155. package/dist/translations/kk.js +1 -1
  156. package/dist/translations/kk.umd.js +1 -1
  157. package/dist/translations/km.js +1 -1
  158. package/dist/translations/km.umd.js +1 -1
  159. package/dist/translations/kn.js +1 -1
  160. package/dist/translations/kn.umd.js +1 -1
  161. package/dist/translations/ko.js +1 -1
  162. package/dist/translations/ko.umd.js +1 -1
  163. package/dist/translations/ku.js +1 -1
  164. package/dist/translations/ku.umd.js +1 -1
  165. package/dist/translations/lt.js +1 -1
  166. package/dist/translations/lt.umd.js +1 -1
  167. package/dist/translations/lv.js +1 -1
  168. package/dist/translations/lv.umd.js +1 -1
  169. package/dist/translations/ms.js +1 -1
  170. package/dist/translations/ms.umd.js +1 -1
  171. package/dist/translations/nb.js +1 -1
  172. package/dist/translations/nb.umd.js +1 -1
  173. package/dist/translations/ne.js +1 -1
  174. package/dist/translations/ne.umd.js +1 -1
  175. package/dist/translations/nl.js +1 -1
  176. package/dist/translations/nl.umd.js +1 -1
  177. package/dist/translations/no.js +1 -1
  178. package/dist/translations/no.umd.js +1 -1
  179. package/dist/translations/oc.js +1 -1
  180. package/dist/translations/oc.umd.js +1 -1
  181. package/dist/translations/pl.js +1 -1
  182. package/dist/translations/pl.umd.js +1 -1
  183. package/dist/translations/pt-br.js +1 -1
  184. package/dist/translations/pt-br.umd.js +1 -1
  185. package/dist/translations/pt.js +1 -1
  186. package/dist/translations/pt.umd.js +1 -1
  187. package/dist/translations/ro.js +1 -1
  188. package/dist/translations/ro.umd.js +1 -1
  189. package/dist/translations/ru.js +1 -1
  190. package/dist/translations/ru.umd.js +1 -1
  191. package/dist/translations/si.js +1 -1
  192. package/dist/translations/si.umd.js +1 -1
  193. package/dist/translations/sk.js +1 -1
  194. package/dist/translations/sk.umd.js +1 -1
  195. package/dist/translations/sl.js +1 -1
  196. package/dist/translations/sl.umd.js +1 -1
  197. package/dist/translations/sq.js +1 -1
  198. package/dist/translations/sq.umd.js +1 -1
  199. package/dist/translations/sr-latn.js +1 -1
  200. package/dist/translations/sr-latn.umd.js +1 -1
  201. package/dist/translations/sr.js +1 -1
  202. package/dist/translations/sr.umd.js +1 -1
  203. package/dist/translations/sv.js +1 -1
  204. package/dist/translations/sv.umd.js +1 -1
  205. package/dist/translations/th.js +1 -1
  206. package/dist/translations/th.umd.js +1 -1
  207. package/dist/translations/ti.js +1 -1
  208. package/dist/translations/ti.umd.js +1 -1
  209. package/dist/translations/tk.js +1 -1
  210. package/dist/translations/tk.umd.js +1 -1
  211. package/dist/translations/tr.js +1 -1
  212. package/dist/translations/tr.umd.js +1 -1
  213. package/dist/translations/tt.js +1 -1
  214. package/dist/translations/tt.umd.js +1 -1
  215. package/dist/translations/ug.js +1 -1
  216. package/dist/translations/ug.umd.js +1 -1
  217. package/dist/translations/uk.js +1 -1
  218. package/dist/translations/uk.umd.js +1 -1
  219. package/dist/translations/ur.js +1 -1
  220. package/dist/translations/ur.umd.js +1 -1
  221. package/dist/translations/uz.js +1 -1
  222. package/dist/translations/uz.umd.js +1 -1
  223. package/dist/translations/vi.js +1 -1
  224. package/dist/translations/vi.umd.js +1 -1
  225. package/dist/translations/zh-cn.js +1 -1
  226. package/dist/translations/zh-cn.umd.js +1 -1
  227. package/dist/translations/zh.js +1 -1
  228. package/dist/translations/zh.umd.js +1 -1
  229. package/lang/contexts.json +8 -1
  230. package/lang/translations/af.po +28 -0
  231. package/lang/translations/ar.po +28 -0
  232. package/lang/translations/ast.po +28 -0
  233. package/lang/translations/az.po +28 -0
  234. package/lang/translations/be.po +296 -0
  235. package/lang/translations/bg.po +28 -0
  236. package/lang/translations/bn.po +28 -0
  237. package/lang/translations/bs.po +28 -0
  238. package/lang/translations/ca.po +28 -0
  239. package/lang/translations/cs.po +28 -0
  240. package/lang/translations/da.po +28 -0
  241. package/lang/translations/de-ch.po +28 -0
  242. package/lang/translations/de.po +28 -0
  243. package/lang/translations/el.po +28 -0
  244. package/lang/translations/en-au.po +28 -0
  245. package/lang/translations/en-gb.po +28 -0
  246. package/lang/translations/en.po +28 -0
  247. package/lang/translations/eo.po +28 -0
  248. package/lang/translations/es-co.po +28 -0
  249. package/lang/translations/es.po +28 -0
  250. package/lang/translations/et.po +28 -0
  251. package/lang/translations/eu.po +28 -0
  252. package/lang/translations/fa.po +28 -0
  253. package/lang/translations/fi.po +28 -0
  254. package/lang/translations/fr.po +28 -0
  255. package/lang/translations/gl.po +28 -0
  256. package/lang/translations/gu.po +28 -0
  257. package/lang/translations/he.po +28 -0
  258. package/lang/translations/hi.po +28 -0
  259. package/lang/translations/hr.po +28 -0
  260. package/lang/translations/hu.po +28 -0
  261. package/lang/translations/hy.po +28 -0
  262. package/lang/translations/id.po +28 -0
  263. package/lang/translations/it.po +28 -0
  264. package/lang/translations/ja.po +28 -0
  265. package/lang/translations/jv.po +28 -0
  266. package/lang/translations/kk.po +28 -0
  267. package/lang/translations/km.po +28 -0
  268. package/lang/translations/kn.po +28 -0
  269. package/lang/translations/ko.po +28 -0
  270. package/lang/translations/ku.po +28 -0
  271. package/lang/translations/lt.po +28 -0
  272. package/lang/translations/lv.po +28 -0
  273. package/lang/translations/ms.po +28 -0
  274. package/lang/translations/nb.po +28 -0
  275. package/lang/translations/ne.po +28 -0
  276. package/lang/translations/nl.po +28 -0
  277. package/lang/translations/no.po +28 -0
  278. package/lang/translations/oc.po +28 -0
  279. package/lang/translations/pl.po +28 -0
  280. package/lang/translations/pt-br.po +28 -0
  281. package/lang/translations/pt.po +28 -0
  282. package/lang/translations/ro.po +28 -0
  283. package/lang/translations/ru.po +28 -0
  284. package/lang/translations/si.po +28 -0
  285. package/lang/translations/sk.po +28 -0
  286. package/lang/translations/sl.po +28 -0
  287. package/lang/translations/sq.po +28 -0
  288. package/lang/translations/sr-latn.po +28 -0
  289. package/lang/translations/sr.po +28 -0
  290. package/lang/translations/sv.po +28 -0
  291. package/lang/translations/th.po +28 -0
  292. package/lang/translations/ti.po +28 -0
  293. package/lang/translations/tk.po +28 -0
  294. package/lang/translations/tr.po +28 -0
  295. package/lang/translations/tt.po +28 -0
  296. package/lang/translations/ug.po +28 -0
  297. package/lang/translations/uk.po +28 -0
  298. package/lang/translations/ur.po +28 -0
  299. package/lang/translations/uz.po +28 -0
  300. package/lang/translations/vi.po +28 -0
  301. package/lang/translations/zh-cn.po +28 -0
  302. package/lang/translations/zh.po +28 -0
  303. package/package.json +10 -9
  304. package/src/augmentation.d.ts +5 -1
  305. package/src/commands/insertcolumncommand.js +4 -0
  306. package/src/commands/insertrowcommand.js +4 -0
  307. package/src/commands/inserttablelayoutcommand.d.ts +39 -0
  308. package/src/commands/inserttablelayoutcommand.js +65 -0
  309. package/src/commands/mergecellcommand.js +8 -0
  310. package/src/commands/setheadercolumncommand.js +9 -4
  311. package/src/commands/setheaderrowcommand.js +8 -3
  312. package/src/commands/splitcellcommand.js +4 -0
  313. package/src/converters/downcast.js +1 -1
  314. package/src/converters/tableproperties.js +25 -5
  315. package/src/index.d.ts +4 -0
  316. package/src/index.js +2 -0
  317. package/src/plaintableoutput.d.ts +3 -0
  318. package/src/plaintableoutput.js +12 -1
  319. package/src/tablecaption/tablecaptionediting.js +7 -0
  320. package/src/tablecaption/tablecaptionui.js +3 -2
  321. package/src/tablecaption/toggletablecaptioncommand.js +1 -1
  322. package/src/tablecellproperties/commands/tablecellpropertycommand.d.ts +11 -1
  323. package/src/tablecellproperties/commands/tablecellpropertycommand.js +40 -2
  324. package/src/tablecellproperties/tablecellpropertiesediting.js +50 -9
  325. package/src/tablecellproperties/tablecellpropertiesui.d.ts +13 -1
  326. package/src/tablecellproperties/tablecellpropertiesui.js +60 -11
  327. package/src/tablecellproperties/ui/tablecellpropertiesview.d.ts +2 -1
  328. package/src/tablecellproperties/ui/tablecellpropertiesview.js +82 -13
  329. package/src/tableclipboard.d.ts +9 -0
  330. package/src/tableclipboard.js +28 -1
  331. package/src/tablecolumnresize/constants.d.ts +4 -0
  332. package/src/tablecolumnresize/constants.js +4 -0
  333. package/src/tablecolumnresize/tablecolumnresizeediting.d.ts +8 -0
  334. package/src/tablecolumnresize/tablecolumnresizeediting.js +50 -10
  335. package/src/tableconfig.d.ts +38 -0
  336. package/src/tableediting.js +4 -0
  337. package/src/tablelayout/commands/tabletypecommand.d.ts +43 -0
  338. package/src/tablelayout/commands/tabletypecommand.js +68 -0
  339. package/src/tablelayout/tablelayoutediting.d.ts +54 -0
  340. package/src/tablelayout/tablelayoutediting.js +276 -0
  341. package/src/tablelayout/tablelayoutui.d.ts +32 -0
  342. package/src/tablelayout/tablelayoutui.js +189 -0
  343. package/src/tablelayout.d.ts +31 -0
  344. package/src/tablelayout.js +37 -0
  345. package/src/tablemouse/mouseeventsobserver.js +3 -6
  346. package/src/tableproperties/commands/tablepropertycommand.d.ts +11 -1
  347. package/src/tableproperties/commands/tablepropertycommand.js +23 -1
  348. package/src/tableproperties/tablepropertiesediting.js +49 -11
  349. package/src/tableproperties/tablepropertiesui.d.ts +21 -3
  350. package/src/tableproperties/tablepropertiesui.js +73 -26
  351. package/src/tableproperties/ui/tablepropertiesview.d.ts +4 -3
  352. package/src/tableproperties/ui/tablepropertiesview.js +70 -9
  353. package/src/tableselection.js +19 -1
  354. package/src/tableui.js +7 -9
  355. package/src/tablewalker.js +99 -4
  356. package/src/ui/colorinputview.js +34 -0
  357. package/src/ui/inserttableview.js +12 -0
  358. package/src/utils/structure.js +7 -1
  359. package/src/utils/table-properties.d.ts +3 -3
  360. package/src/utils/table-properties.js +1 -1
  361. package/src/utils/ui/table-properties.js +7 -1
  362. package/theme/formrow.css +0 -10
  363. package/theme/table.css +52 -35
  364. package/theme/tablecolumnresize.css +5 -0
  365. package/theme/tableform.css +6 -0
  366. package/theme/tablelayout.css +62 -0
  367. package/src/ui/formrowview.d.ts +0 -61
  368. package/src/ui/formrowview.js +0 -57
  369. package/theme/form.css +0 -11
  370. package/theme/icons/table-cell-properties.svg +0 -1
  371. package/theme/icons/table-column.svg +0 -1
  372. package/theme/icons/table-merge-cell.svg +0 -1
  373. package/theme/icons/table-properties.svg +0 -1
  374. package/theme/icons/table-row.svg +0 -1
@@ -30,6 +30,10 @@ import '../theme/tableediting.css';
30
30
  * The table editing feature.
31
31
  */
32
32
  export default class TableEditing extends Plugin {
33
+ /**
34
+ * Handlers for creating additional slots in the table.
35
+ */
36
+ _additionalSlots;
33
37
  /**
34
38
  * @inheritDoc
35
39
  */
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ /**
6
+ * @module table/tablelayout/commands/tabletypecommand
7
+ */
8
+ import { Command } from 'ckeditor5/src/core.js';
9
+ import type { TableType } from '../../tableconfig.js';
10
+ /**
11
+ * The set table type command.
12
+ *
13
+ * The command is registered by {@link module:table/tablelayout/tablelayoutediting~TableLayoutEditing}
14
+ * as the `'tableType'` editor command.
15
+ *
16
+ * To set the table type at the current selection, execute the command and specify the table type:
17
+ *
18
+ * ```ts
19
+ * editor.execute( 'tableType', 'layout' );
20
+ * ```
21
+ */
22
+ export default class TableTypeCommand extends Command {
23
+ /**
24
+ * The table type of selected table.
25
+ *
26
+ * @observable
27
+ * @readonly
28
+ */
29
+ value: TableType | null;
30
+ /**
31
+ * @inheritDoc
32
+ */
33
+ refresh(): void;
34
+ /**
35
+ * Executes the command.
36
+ *
37
+ * Set table type by the given table type parameter.
38
+ *
39
+ * @param tableType The type of table it should become.
40
+ * @fires execute
41
+ */
42
+ execute(tableType: TableType): void;
43
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ /**
6
+ * @module table/tablelayout/commands/tabletypecommand
7
+ */
8
+ import { Command } from 'ckeditor5/src/core.js';
9
+ import { getSelectionAffectedTable } from '../../utils/common.js';
10
+ /**
11
+ * The set table type command.
12
+ *
13
+ * The command is registered by {@link module:table/tablelayout/tablelayoutediting~TableLayoutEditing}
14
+ * as the `'tableType'` editor command.
15
+ *
16
+ * To set the table type at the current selection, execute the command and specify the table type:
17
+ *
18
+ * ```ts
19
+ * editor.execute( 'tableType', 'layout' );
20
+ * ```
21
+ */
22
+ export default class TableTypeCommand extends Command {
23
+ /**
24
+ * @inheritDoc
25
+ */
26
+ refresh() {
27
+ const model = this.editor.model;
28
+ const selection = model.document.selection;
29
+ const selectedTable = getSelectionAffectedTable(selection);
30
+ if (selectedTable) {
31
+ this.isEnabled = true;
32
+ this.value = selectedTable.getAttribute('tableType');
33
+ }
34
+ else {
35
+ this.isEnabled = false;
36
+ this.value = null;
37
+ }
38
+ }
39
+ /**
40
+ * Executes the command.
41
+ *
42
+ * Set table type by the given table type parameter.
43
+ *
44
+ * @param tableType The type of table it should become.
45
+ * @fires execute
46
+ */
47
+ execute(tableType) {
48
+ const editor = this.editor;
49
+ const model = editor.model;
50
+ const selection = model.document.selection;
51
+ const table = getSelectionAffectedTable(selection);
52
+ const currentTableType = table.getAttribute('tableType');
53
+ if (currentTableType === tableType) {
54
+ return;
55
+ }
56
+ model.change(writer => {
57
+ writer.setAttribute('tableType', tableType, table);
58
+ model.schema.removeDisallowedAttributes([table], writer);
59
+ const tableChildren = table.getChildren();
60
+ // Check if all children are allowed for the new table type.
61
+ for (const child of tableChildren) {
62
+ if (!model.schema.checkChild(table, child)) {
63
+ writer.remove(child);
64
+ }
65
+ }
66
+ });
67
+ }
68
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ /**
6
+ * @module table/tablelayout/tablelayoutediting
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core.js';
9
+ import TableColumnResize from '../tablecolumnresize.js';
10
+ import '../../theme/tablelayout.css';
11
+ /**
12
+ * The table layout editing plugin.
13
+ */
14
+ export default class TableLayoutEditing extends Plugin {
15
+ /**
16
+ * @inheritDoc
17
+ */
18
+ static get pluginName(): "TableLayoutEditing";
19
+ /**
20
+ * @inheritDoc
21
+ */
22
+ static get requires(): readonly [typeof TableColumnResize];
23
+ /**
24
+ * @inheritDoc
25
+ */
26
+ static get isOfficialPlugin(): true;
27
+ /**
28
+ * @inheritDoc
29
+ */
30
+ init(): void;
31
+ /**
32
+ * Defines the schema for the table layout feature.
33
+ */
34
+ private _defineSchema;
35
+ /**
36
+ * Defines the converters for the table layout feature.
37
+ */
38
+ private _defineConverters;
39
+ /**
40
+ * Handles the clipboard content insertion events.
41
+ *
42
+ * - If the content is from another editor, do not override the table type.
43
+ * - If the content is from another source, set the table type to 'content'.
44
+ *
45
+ * It handles the scenario when user copies `<table></table>` from Word. We do not want to
46
+ * change the table type to `layout` because it is really `content` table.
47
+ */
48
+ private _defineClipboardPasteHandlers;
49
+ /**
50
+ * Registers a post-fixer that sets the `tableType` attribute to `content` for inserted "default" tables.
51
+ * Also fixes potential issues with the table structure when the `tableType` attribute has been changed.
52
+ */
53
+ private _registerTableTypeAttributePostfixer;
54
+ }
@@ -0,0 +1,276 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ /**
6
+ * @module table/tablelayout/tablelayoutediting
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core.js';
9
+ import InsertTableLayoutCommand from './../commands/inserttablelayoutcommand.js';
10
+ import TableColumnResize from '../tablecolumnresize.js';
11
+ import TableTypeCommand from './commands/tabletypecommand.js';
12
+ import { createEmptyTableCell } from '../utils/common.js';
13
+ import '../../theme/tablelayout.css';
14
+ const TABLE_TYPES = ['content', 'layout'];
15
+ /**
16
+ * The table layout editing plugin.
17
+ */
18
+ export default class TableLayoutEditing extends Plugin {
19
+ /**
20
+ * @inheritDoc
21
+ */
22
+ static get pluginName() {
23
+ return 'TableLayoutEditing';
24
+ }
25
+ /**
26
+ * @inheritDoc
27
+ */
28
+ static get requires() {
29
+ return [TableColumnResize];
30
+ }
31
+ /**
32
+ * @inheritDoc
33
+ */
34
+ static get isOfficialPlugin() {
35
+ return true;
36
+ }
37
+ /**
38
+ * @inheritDoc
39
+ */
40
+ init() {
41
+ this._defineSchema();
42
+ this._defineConverters();
43
+ this._defineClipboardPasteHandlers();
44
+ this._registerTableTypeAttributePostfixer();
45
+ this.editor.commands.add('insertTableLayout', new InsertTableLayoutCommand(this.editor));
46
+ this.editor.commands.add('tableType', new TableTypeCommand(this.editor));
47
+ }
48
+ /**
49
+ * Defines the schema for the table layout feature.
50
+ */
51
+ _defineSchema() {
52
+ const { schema } = this.editor.model;
53
+ schema.extend('table', {
54
+ allowAttributes: 'tableType'
55
+ });
56
+ // Disallow adding `caption` to layout table.
57
+ schema.addChildCheck(layoutTableCheck, 'caption');
58
+ // Disallow adding `headingRows` attribute to layout table.
59
+ schema.addAttributeCheck(layoutTableCheck, 'headingRows');
60
+ // Disallow adding `headingColumns` attribute to layout table.
61
+ schema.addAttributeCheck(layoutTableCheck, 'headingColumns');
62
+ }
63
+ /**
64
+ * Defines the converters for the table layout feature.
65
+ */
66
+ _defineConverters() {
67
+ const { editor } = this;
68
+ const { conversion } = editor;
69
+ const preferredExternalTableType = editor.config.get('table.tableLayout.preferredExternalTableType');
70
+ conversion.for('upcast').add(upcastLayoutTable(preferredExternalTableType));
71
+ conversion.for('dataDowncast').add(dataDowncastLayoutTable());
72
+ conversion.for('editingDowncast').attributeToAttribute({
73
+ model: {
74
+ key: 'tableType',
75
+ values: ['layout', 'content']
76
+ },
77
+ view: {
78
+ layout: {
79
+ key: 'class',
80
+ value: ['layout-table']
81
+ },
82
+ content: {
83
+ key: 'class',
84
+ value: ['content-table']
85
+ }
86
+ }
87
+ });
88
+ }
89
+ /**
90
+ * Handles the clipboard content insertion events.
91
+ *
92
+ * - If the content is from another editor, do not override the table type.
93
+ * - If the content is from another source, set the table type to 'content'.
94
+ *
95
+ * It handles the scenario when user copies `<table></table>` from Word. We do not want to
96
+ * change the table type to `layout` because it is really `content` table.
97
+ */
98
+ _defineClipboardPasteHandlers() {
99
+ const { plugins } = this.editor;
100
+ if (!plugins.has('ClipboardPipeline')) {
101
+ return;
102
+ }
103
+ const clipboardPipeline = plugins.get('ClipboardPipeline');
104
+ this.listenTo(clipboardPipeline, 'contentInsertion', (evt, data) => {
105
+ // If content is pasted from the other editor, skip overriding table type.
106
+ if (data.sourceEditorId) {
107
+ return;
108
+ }
109
+ // For content from other sources, always set table type to 'content'.
110
+ this.editor.model.change(writer => {
111
+ for (const { item } of writer.createRangeIn(data.content)) {
112
+ if (item.is('element', 'table')) {
113
+ writer.setAttribute('tableType', 'content', item);
114
+ }
115
+ }
116
+ });
117
+ });
118
+ }
119
+ /**
120
+ * Registers a post-fixer that sets the `tableType` attribute to `content` for inserted "default" tables.
121
+ * Also fixes potential issues with the table structure when the `tableType` attribute has been changed.
122
+ */
123
+ _registerTableTypeAttributePostfixer() {
124
+ const editor = this.editor;
125
+ editor.model.document.registerPostFixer((writer) => {
126
+ const changes = editor.model.document.differ.getChanges();
127
+ let hasChanged = false;
128
+ for (const entry of changes) {
129
+ if (entry.type == 'insert' && entry.name != '$text') {
130
+ const element = entry.position.nodeAfter;
131
+ const range = writer.createRangeOn(element);
132
+ for (const item of range.getItems()) {
133
+ if (item.is('element', 'table') && !item.hasAttribute('tableType')) {
134
+ writer.setAttribute('tableType', 'content', item);
135
+ hasChanged = true;
136
+ }
137
+ }
138
+ }
139
+ // Remove disallowed attributes and children for layout tables
140
+ // when `tableType` attribute has been changed by `TableTypeCommand`.
141
+ if (entry.type == 'attribute' && entry.attributeKey == 'tableType') {
142
+ for (const item of entry.range.getItems()) {
143
+ if (item.is('element', 'table')) {
144
+ editor.model.schema.removeDisallowedAttributes([item], writer);
145
+ const tableChildren = item.getChildren();
146
+ // Check if all children are allowed for the new table type.
147
+ for (const child of tableChildren) {
148
+ if (!editor.model.schema.checkChild(item, child)) {
149
+ writer.remove(child);
150
+ hasChanged = true;
151
+ }
152
+ }
153
+ }
154
+ }
155
+ }
156
+ }
157
+ return hasChanged;
158
+ });
159
+ }
160
+ }
161
+ /**
162
+ * View table element to model table element conversion helper.
163
+ *
164
+ * This conversion helper overrides the default table converter to meet table layout conditions.
165
+ *
166
+ * @returns Conversion helper.
167
+ */
168
+ function upcastLayoutTable(preferredExternalTableType) {
169
+ return (dispatcher) => {
170
+ dispatcher.on('element:table', (evt, data, conversionApi) => {
171
+ const viewTable = data.viewItem;
172
+ if (!conversionApi.consumable.test(viewTable, { name: true })) {
173
+ return;
174
+ }
175
+ const resolvedTableType = resolveTableType(viewTable, preferredExternalTableType);
176
+ // When an element is a content table, then skip it.
177
+ if (resolvedTableType == 'content') {
178
+ return;
179
+ }
180
+ const table = conversionApi.writer.createElement('table', { tableType: 'layout' });
181
+ if (!conversionApi.safeInsert(table, data.modelCursor)) {
182
+ return;
183
+ }
184
+ conversionApi.consumable.consume(viewTable, { name: true });
185
+ conversionApi.consumable.consume(viewTable, { attributes: ['role'] });
186
+ conversionApi.consumable.consume(viewTable, { classes: ['layout-table'] });
187
+ // Get all rows from the table and convert them.
188
+ // While looping over the children of `<table>` we can be sure that first will be `<tbody>`
189
+ // and optionally `<thead>` and `<tfoot>`, and in these elements are the table rows found.
190
+ // We can be sure of that because of `DomParser` handle it.
191
+ for (const tableChild of viewTable.getChildren()) {
192
+ if (tableChild.is('element')) {
193
+ for (const row of tableChild.getChildren()) {
194
+ if (row.is('element', 'tr')) {
195
+ conversionApi.convertItem(row, conversionApi.writer.createPositionAt(table, 'end'));
196
+ }
197
+ }
198
+ }
199
+ }
200
+ // Convert everything else.
201
+ conversionApi.convertChildren(viewTable, conversionApi.writer.createPositionAt(table, 'end'));
202
+ // Create one row and one table cell for empty table.
203
+ if (table.isEmpty) {
204
+ const row = conversionApi.writer.createElement('tableRow');
205
+ conversionApi.writer.insert(row, conversionApi.writer.createPositionAt(table, 'end'));
206
+ createEmptyTableCell(conversionApi.writer, conversionApi.writer.createPositionAt(row, 'end'));
207
+ }
208
+ conversionApi.updateConversionResult(table, data);
209
+ }, { priority: 'high' });
210
+ // Sets only the table type attribute.
211
+ dispatcher.on('element:table', (evt, data, conversionApi) => {
212
+ const { viewItem, modelRange } = data;
213
+ if (modelRange) {
214
+ conversionApi.writer.setAttribute('tableType', resolveTableType(viewItem, preferredExternalTableType), modelRange);
215
+ conversionApi.consumable.consume(viewItem, { classes: ['layout-table'] });
216
+ conversionApi.consumable.consume(viewItem, { classes: ['content-table'] });
217
+ }
218
+ }, { priority: 'low' });
219
+ };
220
+ }
221
+ /**
222
+ * Model table container element to view table element conversion helper.
223
+ *
224
+ * @returns Conversion helper.
225
+ */
226
+ function dataDowncastLayoutTable() {
227
+ return (dispatcher) => {
228
+ return dispatcher.on('attribute:tableType:table', (evt, data, conversionApi) => {
229
+ const { item, attributeNewValue } = data;
230
+ const { mapper, writer } = conversionApi;
231
+ if (!conversionApi.consumable.test(item, evt.name)) {
232
+ return;
233
+ }
234
+ const table = mapper.toViewElement(item);
235
+ writer.addClass(`${attributeNewValue}-table`, table);
236
+ if (attributeNewValue == 'layout') {
237
+ writer.setAttribute('role', 'presentation', table);
238
+ }
239
+ conversionApi.consumable.consume(item, evt.name);
240
+ });
241
+ };
242
+ }
243
+ /**
244
+ * Resolves the table type based on the view table element and the preferred external table type.
245
+ */
246
+ function resolveTableType(viewTable, preferredExternalTableType) {
247
+ if (viewTable.hasClass('content-table')) {
248
+ return 'content';
249
+ }
250
+ if (viewTable.hasClass('layout-table')) {
251
+ return 'layout';
252
+ }
253
+ if (preferredExternalTableType && TABLE_TYPES.includes(preferredExternalTableType)) {
254
+ return preferredExternalTableType;
255
+ }
256
+ const parent = viewTable.parent;
257
+ /**
258
+ * Checks if the table is a content table if any of the following conditions are met:
259
+ * - the `<table>` is wrapped with `<figure>`,
260
+ * - the `<table>` has a `<caption>` element.
261
+ */
262
+ if (parent.is('element', 'figure') ||
263
+ Array.from(viewTable.getChildren()).some(child => child.is('element', 'caption'))) {
264
+ return 'content';
265
+ }
266
+ return 'layout';
267
+ }
268
+ /**
269
+ * Checks if the element is a layout table.
270
+ * It is used to disallow attributes or children that is managed by `Schema`.
271
+ */
272
+ function layoutTableCheck(context) {
273
+ if (context.endsWith('table') && context.last.getAttribute('tableType') == 'layout') {
274
+ return false;
275
+ }
276
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ /**
6
+ * @module table/tablelayout/tablelayoutui
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core.js';
9
+ /**
10
+ * The table layout UI plugin. It introduces:
11
+ *
12
+ * * The `'insertTableLayout'` dropdown,
13
+ * * The `'menuBar:insertTableLayout'` menu bar menu.
14
+ */
15
+ export default class TableLayoutUI extends Plugin {
16
+ /**
17
+ * @inheritDoc
18
+ */
19
+ static get pluginName(): "TableLayoutUI";
20
+ /**
21
+ * @inheritDoc
22
+ */
23
+ static get isOfficialPlugin(): true;
24
+ /**
25
+ * @inheritDoc
26
+ */
27
+ init(): void;
28
+ /**
29
+ * @inheritDoc
30
+ */
31
+ afterInit(): void;
32
+ }
@@ -0,0 +1,189 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
4
+ */
5
+ /**
6
+ * @module table/tablelayout/tablelayoutui
7
+ */
8
+ import { Plugin } from 'ckeditor5/src/core.js';
9
+ import { IconTableLayout, IconTableProperties } from 'ckeditor5/src/icons.js';
10
+ import { createDropdown, addListToDropdown, MenuBarMenuView, SplitButtonView, DropdownButtonView, ViewModel } from 'ckeditor5/src/ui.js';
11
+ import { Collection } from 'ckeditor5/src/utils.js';
12
+ import InsertTableView from '../ui/inserttableview.js';
13
+ /**
14
+ * The table layout UI plugin. It introduces:
15
+ *
16
+ * * The `'insertTableLayout'` dropdown,
17
+ * * The `'menuBar:insertTableLayout'` menu bar menu.
18
+ */
19
+ export default class TableLayoutUI extends Plugin {
20
+ /**
21
+ * @inheritDoc
22
+ */
23
+ static get pluginName() {
24
+ return 'TableLayoutUI';
25
+ }
26
+ /**
27
+ * @inheritDoc
28
+ */
29
+ static get isOfficialPlugin() {
30
+ return true;
31
+ }
32
+ /**
33
+ * @inheritDoc
34
+ */
35
+ init() {
36
+ const editor = this.editor;
37
+ const t = this.editor.t;
38
+ editor.ui.componentFactory.add('insertTableLayout', locale => {
39
+ const command = editor.commands.get('insertTableLayout');
40
+ const dropdownView = createDropdown(locale);
41
+ dropdownView.bind('isEnabled').to(command);
42
+ // Decorate dropdown's button.
43
+ dropdownView.buttonView.set({
44
+ icon: IconTableLayout,
45
+ label: t('Insert table layout'),
46
+ tooltip: true
47
+ });
48
+ let insertTableLayoutView;
49
+ dropdownView.on('change:isOpen', () => {
50
+ if (insertTableLayoutView) {
51
+ return;
52
+ }
53
+ // Prepare custom view for dropdown's panel.
54
+ insertTableLayoutView = new InsertTableView(locale);
55
+ dropdownView.panelView.children.add(insertTableLayoutView);
56
+ insertTableLayoutView.delegate('execute').to(dropdownView);
57
+ dropdownView.on('execute', () => {
58
+ editor.execute('insertTableLayout', {
59
+ rows: insertTableLayoutView.rows,
60
+ columns: insertTableLayoutView.columns
61
+ });
62
+ editor.editing.view.focus();
63
+ });
64
+ });
65
+ return dropdownView;
66
+ });
67
+ editor.ui.componentFactory.add('menuBar:insertTableLayout', locale => {
68
+ const command = editor.commands.get('insertTableLayout');
69
+ const menuView = new MenuBarMenuView(locale);
70
+ const insertTableLayoutView = new InsertTableView(locale);
71
+ insertTableLayoutView.delegate('execute').to(menuView);
72
+ menuView.on('change:isOpen', (event, name, isOpen) => {
73
+ if (!isOpen) {
74
+ insertTableLayoutView.reset();
75
+ }
76
+ });
77
+ insertTableLayoutView.on('execute', () => {
78
+ editor.execute('insertTableLayout', {
79
+ rows: insertTableLayoutView.rows,
80
+ columns: insertTableLayoutView.columns
81
+ });
82
+ editor.editing.view.focus();
83
+ });
84
+ menuView.buttonView.set({
85
+ label: t('Table layout'),
86
+ icon: IconTableLayout
87
+ });
88
+ menuView.panelView.children.add(insertTableLayoutView);
89
+ menuView.bind('isEnabled').to(command);
90
+ return menuView;
91
+ });
92
+ // Create table type dropdown button.
93
+ editor.ui.componentFactory.add('tableType', () => {
94
+ const editor = this.editor;
95
+ const t = editor.t;
96
+ const button = new DropdownButtonView(editor.locale);
97
+ button.set({
98
+ label: t('Table type'),
99
+ icon: IconTableProperties,
100
+ tooltip: true
101
+ });
102
+ return createTableTypeDropdown(editor, button);
103
+ });
104
+ }
105
+ /**
106
+ * @inheritDoc
107
+ */
108
+ afterInit() {
109
+ const editor = this.editor;
110
+ if (!editor.plugins.has('TablePropertiesUI')) {
111
+ return;
112
+ }
113
+ const tablePropertiesUI = editor.plugins.get('TablePropertiesUI');
114
+ // Override the default table properties button to include the table type dropdown.
115
+ // It needs to be done in `afterInit()` to make sure that `tableProperties` button is
116
+ // registered after the initialization of the `TablePropertiesUI`. Otherwise, the
117
+ // button will be overridden by the default one if the `TablePropertiesUI` is
118
+ // initialized after the `TableLayoutUI`.
119
+ editor.ui.componentFactory.add('tableProperties', locale => {
120
+ const baseButton = tablePropertiesUI._createTablePropertiesButton();
121
+ const splitButtonView = new SplitButtonView(locale, baseButton);
122
+ return createTableTypeDropdown(editor, splitButtonView);
123
+ });
124
+ }
125
+ }
126
+ /**
127
+ * Creates a dropdown for the table type selection.
128
+ *
129
+ * @param editor The editor instance.
130
+ * @param dropdownButton The button view that will be used as the dropdown trigger.
131
+ * @returns A dropdown view containing table type options.
132
+ */
133
+ function createTableTypeDropdown(editor, dropdownButton) {
134
+ const t = editor.t;
135
+ const locale = editor.locale;
136
+ const tableTypeCommand = editor.commands.get('tableType');
137
+ // Wrap the original button in a SplitButtonView.
138
+ const dropdownView = createDropdown(locale, dropdownButton);
139
+ const itemsDefinitions = createTableLayoutTypeDropdownItems(editor);
140
+ // Add table types to the dropdown.
141
+ addListToDropdown(dropdownView, itemsDefinitions, {
142
+ ariaLabel: t('Table type options'),
143
+ role: 'menu'
144
+ });
145
+ dropdownButton.tooltip = t('Choose table type');
146
+ dropdownView.on('execute', evt => {
147
+ const tableType = evt.source.tableType;
148
+ if (tableType) {
149
+ tableTypeCommand.execute(tableType);
150
+ }
151
+ });
152
+ return dropdownView;
153
+ }
154
+ /**
155
+ * Creates dropdown items for table type selection.
156
+ *
157
+ * @param editor The editor instance.
158
+ * @returns A collection of dropdown items for the table type dropdown.
159
+ */
160
+ function createTableLayoutTypeDropdownItems(editor) {
161
+ const t = editor.t;
162
+ const tableTypeCommand = editor.commands.get('tableType');
163
+ const itemDefinitions = new Collection();
164
+ itemDefinitions.add(createTableTypeDropdownItem(tableTypeCommand, 'layout', t('Layout table')));
165
+ itemDefinitions.add(createTableTypeDropdownItem(tableTypeCommand, 'content', t('Content table')));
166
+ return itemDefinitions;
167
+ }
168
+ /**
169
+ * Creates a dropdown item for a specific table type.
170
+ *
171
+ * @param tableTypeCommand The table type command.
172
+ * @param type The table type value ('layout' or 'content').
173
+ * @param label The localized label for the dropdown item.
174
+ * @returns The dropdown item definition.
175
+ */
176
+ function createTableTypeDropdownItem(tableTypeCommand, type, label) {
177
+ const model = new ViewModel({
178
+ label,
179
+ role: 'menuitemradio',
180
+ withText: true,
181
+ tableType: type
182
+ });
183
+ model.bind('isEnabled').to(tableTypeCommand, 'isEnabled');
184
+ model.bind('isOn').to(tableTypeCommand, 'value', value => value === type);
185
+ return {
186
+ type: 'button',
187
+ model
188
+ };
189
+ }