@ckeditor/ckeditor5-list 47.6.1 → 48.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/LICENSE.md +1 -1
  2. package/ckeditor5-metadata.json +21 -18
  3. package/dist/index-content.css +135 -111
  4. package/dist/index-editor.css +152 -73
  5. package/dist/index.css +204 -238
  6. package/dist/index.css.map +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/{src → dist}/legacylist/legacyconverters.d.ts +2 -2
  9. package/{src → dist}/legacylist/legacyindentcommand.d.ts +1 -1
  10. package/{src → dist}/legacylist/legacylistcommand.d.ts +1 -1
  11. package/{src → dist}/legacylist/legacylistediting.d.ts +3 -3
  12. package/{src → dist}/legacylist/legacylistutils.d.ts +2 -2
  13. package/{src → dist}/legacylist/legacyutils.d.ts +1 -1
  14. package/{src → dist}/legacylist.d.ts +1 -1
  15. package/{src → dist}/legacylistproperties/legacylistpropertiesediting.d.ts +1 -1
  16. package/{src → dist}/legacylistproperties/legacylistreversedcommand.d.ts +1 -1
  17. package/{src → dist}/legacylistproperties/legacyliststartcommand.d.ts +1 -1
  18. package/{src → dist}/legacylistproperties/legacyliststylecommand.d.ts +1 -1
  19. package/{src → dist}/legacylistproperties.d.ts +1 -1
  20. package/{src → dist}/legacytodolist/legacychecktodolistcommand.d.ts +2 -2
  21. package/{src → dist}/legacytodolist/legacytodolistconverters.d.ts +2 -2
  22. package/{src → dist}/legacytodolist/legacytodolistediting.d.ts +1 -1
  23. package/{src → dist}/legacytodolist.d.ts +1 -1
  24. package/{src → dist}/list/adjacentlistssupport.d.ts +1 -1
  25. package/{src → dist}/list/converters.d.ts +2 -2
  26. package/{src → dist}/list/listcommand.d.ts +2 -2
  27. package/{src → dist}/list/listediting.d.ts +5 -5
  28. package/{src → dist}/list/listindentcommand.d.ts +2 -2
  29. package/{src → dist}/list/listmergecommand.d.ts +2 -2
  30. package/{src → dist}/list/listsplitcommand.d.ts +2 -2
  31. package/{src → dist}/list/listui.d.ts +1 -1
  32. package/{src → dist}/list/listutils.d.ts +3 -3
  33. package/{src → dist}/list/utils/listwalker.d.ts +2 -2
  34. package/{src → dist}/list/utils/model.d.ts +2 -2
  35. package/{src → dist}/list/utils/postfixers.d.ts +1 -1
  36. package/{src → dist}/list/utils/view.d.ts +1 -1
  37. package/{src → dist}/list/utils.d.ts +1 -1
  38. package/{src → dist}/list.d.ts +1 -1
  39. package/{src → dist}/listconfig.d.ts +1 -1
  40. package/{src → dist}/listformatting/listitemboldintegration.d.ts +1 -1
  41. package/{src → dist}/listformatting/listitemfontcolorintegration.d.ts +1 -1
  42. package/{src → dist}/listformatting/listitemfontfamilyintegration.d.ts +1 -1
  43. package/{src → dist}/listformatting/listitemfontsizeintegration.d.ts +1 -1
  44. package/{src → dist}/listformatting/listitemitalicintegration.d.ts +1 -1
  45. package/{src → dist}/listformatting.d.ts +1 -1
  46. package/{src → dist}/listproperties/converters.d.ts +2 -2
  47. package/{src → dist}/listproperties/listpropertiesediting.d.ts +2 -2
  48. package/{src → dist}/listproperties/listpropertiesui.d.ts +1 -1
  49. package/{src → dist}/listproperties/listpropertiesutils.d.ts +1 -1
  50. package/{src → dist}/listproperties/listreversedcommand.d.ts +1 -1
  51. package/{src → dist}/listproperties/liststartcommand.d.ts +1 -1
  52. package/{src → dist}/listproperties/liststylecommand.d.ts +1 -1
  53. package/{src → dist}/listproperties/ui/listpropertiesview.d.ts +2 -2
  54. package/{src → dist}/listproperties.d.ts +1 -1
  55. package/{src → dist}/todolist/checktodolistcommand.d.ts +1 -1
  56. package/{src → dist}/todolist/todocheckboxchangeobserver.d.ts +1 -1
  57. package/{src → dist}/todolist/todolistediting.d.ts +1 -1
  58. package/{src → dist}/todolist/todolistui.d.ts +1 -1
  59. package/{src → dist}/todolist.d.ts +1 -1
  60. package/package.json +28 -52
  61. package/build/list.js +0 -5
  62. package/build/translations/af.js +0 -1
  63. package/build/translations/ar.js +0 -1
  64. package/build/translations/ast.js +0 -1
  65. package/build/translations/az.js +0 -1
  66. package/build/translations/be.js +0 -1
  67. package/build/translations/bg.js +0 -1
  68. package/build/translations/bn.js +0 -1
  69. package/build/translations/bs.js +0 -1
  70. package/build/translations/ca.js +0 -1
  71. package/build/translations/cs.js +0 -1
  72. package/build/translations/da.js +0 -1
  73. package/build/translations/de-ch.js +0 -1
  74. package/build/translations/de.js +0 -1
  75. package/build/translations/el.js +0 -1
  76. package/build/translations/en-au.js +0 -1
  77. package/build/translations/en-gb.js +0 -1
  78. package/build/translations/eo.js +0 -1
  79. package/build/translations/es-co.js +0 -1
  80. package/build/translations/es.js +0 -1
  81. package/build/translations/et.js +0 -1
  82. package/build/translations/eu.js +0 -1
  83. package/build/translations/fa.js +0 -1
  84. package/build/translations/fi.js +0 -1
  85. package/build/translations/fr.js +0 -1
  86. package/build/translations/gl.js +0 -1
  87. package/build/translations/gu.js +0 -1
  88. package/build/translations/he.js +0 -1
  89. package/build/translations/hi.js +0 -1
  90. package/build/translations/hr.js +0 -1
  91. package/build/translations/hu.js +0 -1
  92. package/build/translations/hy.js +0 -1
  93. package/build/translations/id.js +0 -1
  94. package/build/translations/it.js +0 -1
  95. package/build/translations/ja.js +0 -1
  96. package/build/translations/jv.js +0 -1
  97. package/build/translations/kk.js +0 -1
  98. package/build/translations/km.js +0 -1
  99. package/build/translations/kn.js +0 -1
  100. package/build/translations/ko.js +0 -1
  101. package/build/translations/ku.js +0 -1
  102. package/build/translations/lt.js +0 -1
  103. package/build/translations/lv.js +0 -1
  104. package/build/translations/ms.js +0 -1
  105. package/build/translations/nb.js +0 -1
  106. package/build/translations/ne.js +0 -1
  107. package/build/translations/nl.js +0 -1
  108. package/build/translations/no.js +0 -1
  109. package/build/translations/oc.js +0 -1
  110. package/build/translations/pl.js +0 -1
  111. package/build/translations/pt-br.js +0 -1
  112. package/build/translations/pt.js +0 -1
  113. package/build/translations/ro.js +0 -1
  114. package/build/translations/ru.js +0 -1
  115. package/build/translations/si.js +0 -1
  116. package/build/translations/sk.js +0 -1
  117. package/build/translations/sl.js +0 -1
  118. package/build/translations/sq.js +0 -1
  119. package/build/translations/sr-latn.js +0 -1
  120. package/build/translations/sr.js +0 -1
  121. package/build/translations/sv.js +0 -1
  122. package/build/translations/th.js +0 -1
  123. package/build/translations/ti.js +0 -1
  124. package/build/translations/tk.js +0 -1
  125. package/build/translations/tr.js +0 -1
  126. package/build/translations/tt.js +0 -1
  127. package/build/translations/ug.js +0 -1
  128. package/build/translations/uk.js +0 -1
  129. package/build/translations/ur.js +0 -1
  130. package/build/translations/uz.js +0 -1
  131. package/build/translations/vi.js +0 -1
  132. package/build/translations/zh-cn.js +0 -1
  133. package/build/translations/zh.js +0 -1
  134. package/lang/contexts.json +0 -37
  135. package/lang/translations/af.po +0 -152
  136. package/lang/translations/ar.po +0 -152
  137. package/lang/translations/ast.po +0 -152
  138. package/lang/translations/az.po +0 -152
  139. package/lang/translations/be.po +0 -152
  140. package/lang/translations/bg.po +0 -152
  141. package/lang/translations/bn.po +0 -152
  142. package/lang/translations/bs.po +0 -152
  143. package/lang/translations/ca.po +0 -152
  144. package/lang/translations/cs.po +0 -152
  145. package/lang/translations/da.po +0 -152
  146. package/lang/translations/de-ch.po +0 -152
  147. package/lang/translations/de.po +0 -152
  148. package/lang/translations/el.po +0 -152
  149. package/lang/translations/en-au.po +0 -152
  150. package/lang/translations/en-gb.po +0 -152
  151. package/lang/translations/en.po +0 -152
  152. package/lang/translations/eo.po +0 -152
  153. package/lang/translations/es-co.po +0 -152
  154. package/lang/translations/es.po +0 -152
  155. package/lang/translations/et.po +0 -152
  156. package/lang/translations/eu.po +0 -152
  157. package/lang/translations/fa.po +0 -152
  158. package/lang/translations/fi.po +0 -152
  159. package/lang/translations/fr.po +0 -152
  160. package/lang/translations/gl.po +0 -152
  161. package/lang/translations/gu.po +0 -152
  162. package/lang/translations/he.po +0 -152
  163. package/lang/translations/hi.po +0 -152
  164. package/lang/translations/hr.po +0 -152
  165. package/lang/translations/hu.po +0 -152
  166. package/lang/translations/hy.po +0 -152
  167. package/lang/translations/id.po +0 -152
  168. package/lang/translations/it.po +0 -152
  169. package/lang/translations/ja.po +0 -152
  170. package/lang/translations/jv.po +0 -152
  171. package/lang/translations/kk.po +0 -152
  172. package/lang/translations/km.po +0 -152
  173. package/lang/translations/kn.po +0 -152
  174. package/lang/translations/ko.po +0 -152
  175. package/lang/translations/ku.po +0 -152
  176. package/lang/translations/lt.po +0 -152
  177. package/lang/translations/lv.po +0 -152
  178. package/lang/translations/ms.po +0 -152
  179. package/lang/translations/nb.po +0 -152
  180. package/lang/translations/ne.po +0 -152
  181. package/lang/translations/nl.po +0 -152
  182. package/lang/translations/no.po +0 -152
  183. package/lang/translations/oc.po +0 -152
  184. package/lang/translations/pl.po +0 -152
  185. package/lang/translations/pt-br.po +0 -152
  186. package/lang/translations/pt.po +0 -152
  187. package/lang/translations/ro.po +0 -152
  188. package/lang/translations/ru.po +0 -152
  189. package/lang/translations/si.po +0 -152
  190. package/lang/translations/sk.po +0 -152
  191. package/lang/translations/sl.po +0 -152
  192. package/lang/translations/sq.po +0 -152
  193. package/lang/translations/sr-latn.po +0 -152
  194. package/lang/translations/sr.po +0 -152
  195. package/lang/translations/sv.po +0 -152
  196. package/lang/translations/th.po +0 -152
  197. package/lang/translations/ti.po +0 -152
  198. package/lang/translations/tk.po +0 -152
  199. package/lang/translations/tr.po +0 -152
  200. package/lang/translations/tt.po +0 -152
  201. package/lang/translations/ug.po +0 -152
  202. package/lang/translations/uk.po +0 -152
  203. package/lang/translations/ur.po +0 -152
  204. package/lang/translations/uz.po +0 -152
  205. package/lang/translations/vi.po +0 -152
  206. package/lang/translations/zh-cn.po +0 -152
  207. package/lang/translations/zh.po +0 -152
  208. package/src/augmentation.js +0 -5
  209. package/src/index.js +0 -67
  210. package/src/legacyerrors.js +0 -28
  211. package/src/legacylist/legacyconverters.js +0 -921
  212. package/src/legacylist/legacyindentcommand.js +0 -111
  213. package/src/legacylist/legacylistcommand.js +0 -278
  214. package/src/legacylist/legacylistediting.js +0 -167
  215. package/src/legacylist/legacylistutils.js +0 -52
  216. package/src/legacylist/legacyutils.js +0 -357
  217. package/src/legacylist.js +0 -36
  218. package/src/legacylistproperties/legacylistpropertiesediting.js +0 -703
  219. package/src/legacylistproperties/legacylistreversedcommand.js +0 -52
  220. package/src/legacylistproperties/legacyliststartcommand.js +0 -52
  221. package/src/legacylistproperties/legacyliststylecommand.js +0 -105
  222. package/src/legacylistproperties.js +0 -37
  223. package/src/legacytodolist/legacychecktodolistcommand.js +0 -82
  224. package/src/legacytodolist/legacytodolistconverters.js +0 -268
  225. package/src/legacytodolist/legacytodolistediting.js +0 -199
  226. package/src/legacytodolist.js +0 -37
  227. package/src/list/adjacentlistssupport.js +0 -87
  228. package/src/list/converters.js +0 -533
  229. package/src/list/listcommand.js +0 -176
  230. package/src/list/listediting.js +0 -696
  231. package/src/list/listindentcommand.js +0 -136
  232. package/src/list/listmergecommand.js +0 -182
  233. package/src/list/listsplitcommand.js +0 -74
  234. package/src/list/listui.js +0 -42
  235. package/src/list/listutils.js +0 -68
  236. package/src/list/utils/listwalker.js +0 -236
  237. package/src/list/utils/model.js +0 -487
  238. package/src/list/utils/postfixers.js +0 -131
  239. package/src/list/utils/view.js +0 -117
  240. package/src/list/utils.js +0 -51
  241. package/src/list.js +0 -36
  242. package/src/listconfig.js +0 -5
  243. package/src/listformatting/listitemboldintegration.js +0 -88
  244. package/src/listformatting/listitemfontcolorintegration.js +0 -92
  245. package/src/listformatting/listitemfontfamilyintegration.js +0 -93
  246. package/src/listformatting/listitemfontsizeintegration.js +0 -124
  247. package/src/listformatting/listitemitalicintegration.js +0 -88
  248. package/src/listformatting.js +0 -248
  249. package/src/listproperties/converters.js +0 -43
  250. package/src/listproperties/listpropertiesediting.js +0 -291
  251. package/src/listproperties/listpropertiesui.js +0 -385
  252. package/src/listproperties/listpropertiesutils.js +0 -50
  253. package/src/listproperties/listreversedcommand.js +0 -55
  254. package/src/listproperties/liststartcommand.js +0 -61
  255. package/src/listproperties/liststylecommand.js +0 -121
  256. package/src/listproperties/ui/listpropertiesview.js +0 -318
  257. package/src/listproperties/utils/config.js +0 -84
  258. package/src/listproperties/utils/style.js +0 -85
  259. package/src/listproperties.js +0 -37
  260. package/src/todolist/checktodolistcommand.js +0 -82
  261. package/src/todolist/todocheckboxchangeobserver.js +0 -36
  262. package/src/todolist/todolistediting.js +0 -470
  263. package/src/todolist/todolistui.js +0 -35
  264. package/src/todolist.js +0 -37
  265. package/theme/documentlist.css +0 -8
  266. package/theme/list.css +0 -40
  267. package/theme/listformatting.css +0 -66
  268. package/theme/listproperties.css +0 -10
  269. package/theme/liststyles.css +0 -8
  270. package/theme/todolist.css +0 -140
  271. /package/{src → dist}/augmentation.d.ts +0 -0
  272. /package/{src → dist}/index.d.ts +0 -0
  273. /package/{src → dist}/legacyerrors.d.ts +0 -0
  274. /package/{src → dist}/listproperties/utils/config.d.ts +0 -0
  275. /package/{src → dist}/listproperties/utils/style.d.ts +0 -0
@@ -1,88 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, 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 list/listformatting/listitemitalicintegration
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { env } from 'ckeditor5/src/utils.js';
10
- import { ListEditing } from '../list/listediting.js';
11
- /**
12
- * The list item italic integration plugin.
13
- */
14
- export class ListItemItalicIntegration extends Plugin {
15
- /**
16
- * @inheritDoc
17
- */
18
- static get pluginName() {
19
- return 'ListItemItalicIntegration';
20
- }
21
- /**
22
- * @inheritDoc
23
- */
24
- static get isOfficialPlugin() {
25
- return true;
26
- }
27
- /**
28
- * @inheritDoc
29
- */
30
- static get requires() {
31
- return [ListEditing];
32
- }
33
- /**
34
- * @inheritDoc
35
- */
36
- init() {
37
- const editor = this.editor;
38
- const ListFormatting = editor.plugins.get('ListFormatting');
39
- const listEditing = editor.plugins.get(ListEditing);
40
- if (!editor.plugins.has('ItalicEditing') || !this.editor.config.get('list.enableListItemMarkerFormatting')) {
41
- return;
42
- }
43
- ListFormatting.registerFormatAttribute('italic', 'listItemItalic');
44
- // Register the downcast strategy in init() so that the attribute name is registered before the list editing
45
- // registers its converters.
46
- // This ensures that the attribute is recognized by downcast strategies and bogus paragraphs are handled correctly.
47
- listEditing.registerDowncastStrategy({
48
- scope: 'item',
49
- attributeName: 'listItemItalic',
50
- setAttributeOnDowncast(writer, value, viewElement, options) {
51
- if (value) {
52
- writer.addClass('ck-list-marker-italic', viewElement);
53
- // See: https://github.com/ckeditor/ckeditor5/issues/18790.
54
- if (env.isSafari && !(options && options.dataPipeline)) {
55
- writer.setStyle('--ck-content-list-marker-dummy-italic', '0', viewElement);
56
- }
57
- }
58
- }
59
- });
60
- }
61
- /**
62
- * @inheritDoc
63
- */
64
- afterInit() {
65
- const editor = this.editor;
66
- const model = editor.model;
67
- if (!editor.plugins.has('ItalicEditing') || !this.editor.config.get('list.enableListItemMarkerFormatting')) {
68
- return;
69
- }
70
- model.schema.extend('$listItem', { allowAttributes: 'listItemItalic' });
71
- model.schema.setAttributeProperties('listItemItalic', {
72
- isFormatting: true
73
- });
74
- model.schema.addAttributeCheck(context => {
75
- const item = context.last;
76
- if (!item.getAttribute('listItemId')) {
77
- return false;
78
- }
79
- }, 'listItemItalic');
80
- editor.conversion.for('upcast').attributeToAttribute({
81
- model: 'listItemItalic',
82
- view: {
83
- name: 'li',
84
- classes: 'ck-list-marker-italic'
85
- }
86
- });
87
- }
88
- }
@@ -1,248 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, 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 list/listformatting
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { ListItemBoldIntegration } from './listformatting/listitemboldintegration.js';
10
- import { ListItemItalicIntegration } from './listformatting/listitemitalicintegration.js';
11
- import { ListItemFontSizeIntegration } from './listformatting/listitemfontsizeintegration.js';
12
- import { ListItemFontColorIntegration } from './listformatting/listitemfontcolorintegration.js';
13
- import { ListItemFontFamilyIntegration } from './listformatting/listitemfontfamilyintegration.js';
14
- import { isListItemBlock, getAllListItemBlocks, isFirstBlockOfListItem } from './list/utils/model.js';
15
- import '../theme/listformatting.css';
16
- /**
17
- * The list formatting plugin.
18
- *
19
- * It enables integration with formatting plugins to style the list marker.
20
- * The list marker is styled based on the consistent formatting applied to the content of the list item.
21
- *
22
- * The list of supported formatting plugins includes:
23
- * * Font color.
24
- * * Font size.
25
- * * Font family.
26
- * * Bold.
27
- * * Italic.
28
- */
29
- export class ListFormatting extends Plugin {
30
- /**
31
- * The list of loaded formatting.
32
- */
33
- _loadedFormatting = {};
34
- /**
35
- * @inheritDoc
36
- */
37
- static get pluginName() {
38
- return 'ListFormatting';
39
- }
40
- /**
41
- * @inheritDoc
42
- */
43
- static get isOfficialPlugin() {
44
- return true;
45
- }
46
- /**
47
- * @inheritDoc
48
- */
49
- static get requires() {
50
- return [
51
- ListItemBoldIntegration,
52
- ListItemItalicIntegration,
53
- ListItemFontSizeIntegration,
54
- ListItemFontColorIntegration,
55
- ListItemFontFamilyIntegration
56
- ];
57
- }
58
- /**
59
- * @inheritDoc
60
- */
61
- constructor(editor) {
62
- super(editor);
63
- editor.config.define('list.enableListItemMarkerFormatting', true);
64
- }
65
- /**
66
- * @inheritDoc
67
- */
68
- afterInit() {
69
- if (!this.editor.config.get('list.enableListItemMarkerFormatting')) {
70
- return;
71
- }
72
- this._registerPostfixerForListItemFormatting();
73
- }
74
- /**
75
- * Registers a postfixer that ensures that the list item formatting attribute is consistent with the formatting
76
- * applied to the content of the list item.
77
- */
78
- _registerPostfixerForListItemFormatting() {
79
- const model = this.editor.model;
80
- model.document.registerPostFixer(writer => {
81
- const changes = model.document.differ.getChanges();
82
- const modifiedListItems = new Set();
83
- let returnValue = false;
84
- for (const entry of changes) {
85
- if (entry.type === 'attribute') {
86
- if (entry.attributeKey == 'listItemId' ||
87
- entry.attributeKey == 'listType' ||
88
- this._isInlineOrSelectionFormatting(entry.attributeKey) ||
89
- Object.values(this._loadedFormatting).includes(entry.attributeKey)) {
90
- if (isListItemBlock(entry.range.start.nodeAfter)) {
91
- modifiedListItems.add(entry.range.start.nodeAfter);
92
- }
93
- else if (isListItemBlock(entry.range.start.parent)) {
94
- modifiedListItems.add(entry.range.start.parent);
95
- }
96
- }
97
- }
98
- else {
99
- if (isListItemBlock(entry.position.nodeAfter)) {
100
- modifiedListItems.add(entry.position.nodeAfter);
101
- }
102
- if (isListItemBlock(entry.position.nodeBefore)) {
103
- modifiedListItems.add(entry.position.nodeBefore);
104
- }
105
- if (isListItemBlock(entry.position.parent)) {
106
- modifiedListItems.add(entry.position.parent);
107
- }
108
- if (entry.type == 'insert' && entry.name != '$text') {
109
- const range = writer.createRangeIn(entry.position.nodeAfter);
110
- for (const item of range.getItems()) {
111
- if (isListItemBlock(item)) {
112
- modifiedListItems.add(item);
113
- }
114
- }
115
- }
116
- }
117
- }
118
- for (const listItem of modifiedListItems) {
119
- const formats = getListItemConsistentFormat(model, listItem, Object.keys(this._loadedFormatting));
120
- for (const [formatAttributeName, formatValue] of Object.entries(formats)) {
121
- const listItemFormatAttributeName = this._loadedFormatting[formatAttributeName];
122
- if (formatValue && setFormattingToListItem(writer, listItem, listItemFormatAttributeName, formatValue)) {
123
- returnValue = true;
124
- }
125
- else if (!formatValue && removeFormattingFromListItem(writer, listItem, listItemFormatAttributeName)) {
126
- returnValue = true;
127
- }
128
- }
129
- }
130
- return returnValue;
131
- });
132
- }
133
- /**
134
- * Registers an integration between a default attribute (e.g., `fontFamily`) and a new attribute
135
- * intended specifically for list item elements (e.g., `listItemFontFamily`).
136
- *
137
- * These attributes are later used by the postfixer logic to determine whether to add the new attribute
138
- * to the list item element, based on whether there is a consistent default formatting attribute
139
- * applied within its content.
140
- */
141
- registerFormatAttribute(formatAttribute, listItemFormatAttribute) {
142
- this._loadedFormatting[formatAttribute] = listItemFormatAttribute;
143
- }
144
- /**
145
- * Returns true if the given model attribute name is a supported inline formatting attribute.
146
- */
147
- _isInlineOrSelectionFormatting(attributeKey) {
148
- return attributeKey.replace(/^selection:/, '') in this._loadedFormatting;
149
- }
150
- }
151
- /**
152
- * Returns the consistent format of the list item element.
153
- * If the list item contains multiple blocks, it checks only the first block.
154
- */
155
- function getListItemConsistentFormat(model, listItem, attributeKeys) {
156
- if (isFirstBlockOfListItem(listItem)) {
157
- return getSingleListItemConsistentFormat(model, listItem, attributeKeys);
158
- }
159
- // Always the first block of the list item should be checked for consistent formatting.
160
- const listItemBlocks = getAllListItemBlocks(listItem);
161
- return getSingleListItemConsistentFormat(model, listItemBlocks[0], attributeKeys);
162
- }
163
- /**
164
- * Returns the consistent format of a single list item element.
165
- */
166
- function getSingleListItemConsistentFormat(model, listItem, attributeKeys) {
167
- // Only bulleted and numbered lists can have formatting (to-do lists are not supported).
168
- // Do not check internals of limit elements (for example, do not check table cells).
169
- if (!isNumberedOrBulletedList(listItem) || model.schema.isLimit(listItem)) {
170
- return Object.fromEntries(attributeKeys.map(attributeKey => [attributeKey]));
171
- }
172
- if (listItem.isEmpty) {
173
- return Object.fromEntries(attributeKeys.map(attributeKey => ([attributeKey, listItem.getAttribute(`selection:${attributeKey}`)])));
174
- }
175
- const attributesToCheck = new Set(attributeKeys);
176
- const valuesMap = {};
177
- const range = model.createRangeIn(listItem);
178
- const walker = range.getWalker({ ignoreElementEnd: true });
179
- for (const { item } of walker) {
180
- for (const attributeKey of attributesToCheck) {
181
- if (model.schema.checkAttribute(item, attributeKey)) {
182
- const formatAttribute = item.getAttribute(attributeKey);
183
- if (formatAttribute === undefined) {
184
- attributesToCheck.delete(attributeKey);
185
- valuesMap[attributeKey] = undefined;
186
- }
187
- else if (valuesMap[attributeKey] === undefined) {
188
- // First item inside a list item block.
189
- valuesMap[attributeKey] = formatAttribute;
190
- }
191
- else if (valuesMap[attributeKey] !== formatAttribute) {
192
- // Following items in the same block of a list item.
193
- attributesToCheck.delete(attributeKey);
194
- valuesMap[attributeKey] = undefined;
195
- }
196
- }
197
- else if (!(attributeKey in valuesMap)) {
198
- // Store it so a format would be removed when all items in the given list item does not allow that formatting.
199
- valuesMap[attributeKey] = undefined;
200
- }
201
- }
202
- // End early if all attributes have been checked and are inconsistent.
203
- if (!attributesToCheck.size) {
204
- break;
205
- }
206
- // Jump over inline limit elements as we expect only outside them to be the same formatting.
207
- if (model.schema.isLimit(item)) {
208
- walker.jumpTo(model.createPositionAfter(item));
209
- }
210
- }
211
- return valuesMap;
212
- }
213
- /**
214
- * Adds the specified formatting attribute to the list item element.
215
- */
216
- function setFormattingToListItem(writer, listItem, attributeKey, attributeValue) {
217
- // Multi-block items should have consistent formatting.
218
- const listItemBlocks = getAllListItemBlocks(listItem);
219
- let wasChanged = false;
220
- for (const listItem of listItemBlocks) {
221
- if (!listItem.hasAttribute(attributeKey) || listItem.getAttribute(attributeKey) !== attributeValue) {
222
- writer.setAttribute(attributeKey, attributeValue, listItem);
223
- wasChanged = true;
224
- }
225
- }
226
- return wasChanged;
227
- }
228
- /**
229
- * Removes the specified formatting attribute from the list item element.
230
- */
231
- function removeFormattingFromListItem(writer, listItem, attributeKey) {
232
- // Multi-block items should have consistent formatting.
233
- const listItemBlocks = getAllListItemBlocks(listItem);
234
- let wasChanged = false;
235
- for (const listItem of listItemBlocks) {
236
- if (listItem.hasAttribute(attributeKey)) {
237
- writer.removeAttribute(attributeKey, listItem);
238
- wasChanged = true;
239
- }
240
- }
241
- return wasChanged;
242
- }
243
- /**
244
- * Checks if the given list type is a numbered or bulleted list.
245
- */
246
- function isNumberedOrBulletedList(listItem) {
247
- return ['numbered', 'bulleted', 'customNumbered', 'customBulleted'].includes(listItem.getAttribute('listType'));
248
- }
@@ -1,43 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, 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
- * Returns a converter that consumes the `style`, `reversed`, and `start` attributes.
7
- * In `style`, it searches for the `list-style-type` definition.
8
- * If not found, the `"default"` value will be used.
9
- *
10
- * @internal
11
- * @param strategy
12
- */
13
- export function listPropertiesUpcastConverter(strategy) {
14
- return (evt, data, conversionApi) => {
15
- const { writer, schema, consumable } = conversionApi;
16
- // If there is no view consumable to consume, set the default attribute value to be able to reconvert nested lists on parent change.
17
- // So abort converting if attribute was directly consumed.
18
- if (consumable.test(data.viewItem, strategy.viewConsumables) === false) {
19
- return;
20
- }
21
- if (!data.modelRange) {
22
- Object.assign(data, conversionApi.convertChildren(data.viewItem, data.modelCursor));
23
- }
24
- let applied = false;
25
- for (const item of data.modelRange.getItems({ shallow: true })) {
26
- if (!schema.checkAttribute(item, strategy.attributeName)) {
27
- continue;
28
- }
29
- if (!strategy.appliesToListItem(item)) {
30
- continue;
31
- }
32
- // Set list attributes only on same level items, those nested deeper are already handled by the recursive conversion.
33
- if (item.hasAttribute(strategy.attributeName)) {
34
- continue;
35
- }
36
- writer.setAttribute(strategy.attributeName, strategy.getAttributeOnUpcast(data.viewItem), item);
37
- applied = true;
38
- }
39
- if (applied) {
40
- consumable.consume(data.viewItem, strategy.viewConsumables);
41
- }
42
- };
43
- }
@@ -1,291 +0,0 @@
1
- /**
2
- * @license Copyright (c) 2003-2026, 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 list/listproperties/listpropertiesediting
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { ListEditing } from '../list/listediting.js';
10
- import { ListStartCommand } from './liststartcommand.js';
11
- import { ListStyleCommand } from './liststylecommand.js';
12
- import { ListReversedCommand } from './listreversedcommand.js';
13
- import { listPropertiesUpcastConverter } from './converters.js';
14
- import { getAllSupportedStyleTypes, getListTypeFromListStyleType, getListStyleTypeFromTypeAttribute, getTypeAttributeFromListStyleType, normalizeListStyle } from './utils/style.js';
15
- import { ListPropertiesUtils } from './listpropertiesutils.js';
16
- import { isNumberedListType } from '../list/utils/model.js';
17
- import { getNormalizedConfig } from './utils/config.js';
18
- const DEFAULT_LIST_TYPE = 'default';
19
- /**
20
- * The document list properties engine feature.
21
- *
22
- * It registers the `'listStyle'`, `'listReversed'` and `'listStart'` commands if they are enabled in the configuration.
23
- * Read more in {@link module:list/listconfig~ListPropertiesConfig}.
24
- */
25
- export class ListPropertiesEditing extends Plugin {
26
- /**
27
- * @inheritDoc
28
- */
29
- static get requires() {
30
- return [ListEditing, ListPropertiesUtils];
31
- }
32
- /**
33
- * @inheritDoc
34
- */
35
- static get pluginName() {
36
- return 'ListPropertiesEditing';
37
- }
38
- /**
39
- * @inheritDoc
40
- * @internal
41
- */
42
- static get licenseFeatureCode() {
43
- return 'LP';
44
- }
45
- /**
46
- * @inheritDoc
47
- */
48
- static get isOfficialPlugin() {
49
- return true;
50
- }
51
- /**
52
- * @inheritDoc
53
- */
54
- static get isPremiumPlugin() {
55
- return true;
56
- }
57
- /**
58
- * @inheritDoc
59
- */
60
- constructor(editor) {
61
- super(editor);
62
- editor.config.define('list.properties', {
63
- styles: true,
64
- startIndex: false,
65
- reversed: false
66
- });
67
- }
68
- /**
69
- * @inheritDoc
70
- */
71
- init() {
72
- const editor = this.editor;
73
- const model = editor.model;
74
- const listEditing = editor.plugins.get(ListEditing);
75
- const enabledProperties = editor.config.get('list.properties');
76
- const strategies = createAttributeStrategies(enabledProperties);
77
- for (const strategy of strategies) {
78
- strategy.addCommand(editor);
79
- model.schema.extend('$listItem', { allowAttributes: strategy.attributeName });
80
- // Register downcast strategy.
81
- listEditing.registerDowncastStrategy({
82
- scope: 'list',
83
- attributeName: strategy.attributeName,
84
- setAttributeOnDowncast(writer, attributeValue, viewElement) {
85
- strategy.setAttributeOnDowncast(writer, attributeValue, viewElement);
86
- }
87
- });
88
- }
89
- // Set up conversion.
90
- editor.conversion.for('upcast').add(dispatcher => {
91
- for (const strategy of strategies) {
92
- dispatcher.on('element:ol', listPropertiesUpcastConverter(strategy));
93
- dispatcher.on('element:ul', listPropertiesUpcastConverter(strategy));
94
- }
95
- });
96
- // Verify if the list view element (ul or ol) requires refreshing.
97
- listEditing.on('checkAttributes:list', (evt, { viewElement, modelAttributes, modelReferenceElement }) => {
98
- for (const strategy of strategies) {
99
- if (!strategy.appliesToListItem(modelReferenceElement)) {
100
- continue;
101
- }
102
- if (strategy.getAttributeOnUpcast(viewElement) != modelAttributes[strategy.attributeName]) {
103
- evt.return = true;
104
- evt.stop();
105
- }
106
- }
107
- });
108
- // Reset list properties after indenting list items.
109
- this.listenTo(editor.commands.get('indentList'), 'afterExecute', (evt, changedBlocks) => {
110
- model.change(writer => {
111
- for (const node of changedBlocks) {
112
- for (const strategy of strategies) {
113
- if (strategy.appliesToListItem(node)) {
114
- // Just reset the attribute.
115
- // If there is a previous indented list that this node should be merged into,
116
- // the postfixer will unify all the attributes of both sub-lists.
117
- writer.setAttribute(strategy.attributeName, strategy.defaultValue, node);
118
- }
119
- }
120
- }
121
- });
122
- });
123
- // Add or remove list properties attributes depending on the list type.
124
- listEditing.on('postFixer', (evt, { listNodes, writer }) => {
125
- for (const { node } of listNodes) {
126
- for (const strategy of strategies) {
127
- // Check if attribute is valid.
128
- if (strategy.hasValidAttribute(node)) {
129
- continue;
130
- }
131
- // Add missing default property attributes...
132
- if (strategy.appliesToListItem(node)) {
133
- writer.setAttribute(strategy.attributeName, strategy.defaultValue, node);
134
- }
135
- // ...or remove invalid property attributes.
136
- else {
137
- writer.removeAttribute(strategy.attributeName, node);
138
- }
139
- evt.return = true;
140
- }
141
- }
142
- });
143
- // Make sure that all items in a single list (items at the same level & listType) have the same properties.
144
- listEditing.on('postFixer', (evt, { listNodes, writer }) => {
145
- for (const { node, previousNodeInList } of listNodes) {
146
- // This is a first item of a nested list.
147
- if (!previousNodeInList) {
148
- continue;
149
- }
150
- // This is a first block of a list of a different type.
151
- if (previousNodeInList.getAttribute('listType') != node.getAttribute('listType')) {
152
- continue;
153
- }
154
- // Copy properties from the previous one.
155
- for (const strategy of strategies) {
156
- const { attributeName } = strategy;
157
- if (!strategy.appliesToListItem(node)) {
158
- continue;
159
- }
160
- const value = previousNodeInList.getAttribute(attributeName);
161
- if (node.getAttribute(attributeName) != value) {
162
- writer.setAttribute(attributeName, value, node);
163
- evt.return = true;
164
- }
165
- }
166
- }
167
- });
168
- }
169
- }
170
- /**
171
- * Creates an array of strategies for dealing with enabled listItem attributes.
172
- */
173
- function createAttributeStrategies(enabledProperties) {
174
- const strategies = [];
175
- const normalizedConfig = getNormalizedConfig(enabledProperties);
176
- if (enabledProperties.styles) {
177
- const useAttribute = normalizedConfig.styles.useAttribute;
178
- strategies.push({
179
- attributeName: 'listStyle',
180
- defaultValue: DEFAULT_LIST_TYPE,
181
- viewConsumables: { styles: 'list-style-type' },
182
- addCommand(editor) {
183
- let supportedTypes = getAllSupportedStyleTypes();
184
- if (useAttribute) {
185
- supportedTypes = supportedTypes.filter(styleType => !!getTypeAttributeFromListStyleType(styleType));
186
- }
187
- editor.commands.add('listStyle', new ListStyleCommand(editor, DEFAULT_LIST_TYPE, supportedTypes));
188
- },
189
- appliesToListItem(item) {
190
- return item.getAttribute('listType') == 'numbered' || item.getAttribute('listType') == 'bulleted';
191
- },
192
- hasValidAttribute(item) {
193
- if (!this.appliesToListItem(item)) {
194
- return !item.hasAttribute('listStyle');
195
- }
196
- if (!item.hasAttribute('listStyle')) {
197
- return false;
198
- }
199
- const value = item.getAttribute('listStyle');
200
- if (value == DEFAULT_LIST_TYPE) {
201
- return true;
202
- }
203
- return getListTypeFromListStyleType(value) == item.getAttribute('listType');
204
- },
205
- setAttributeOnDowncast(writer, listStyle, element) {
206
- if (listStyle && listStyle !== DEFAULT_LIST_TYPE) {
207
- if (useAttribute) {
208
- const value = getTypeAttributeFromListStyleType(listStyle);
209
- if (value) {
210
- writer.setAttribute('type', value, element);
211
- return;
212
- }
213
- }
214
- else {
215
- writer.setStyle('list-style-type', listStyle, element);
216
- return;
217
- }
218
- }
219
- writer.removeStyle('list-style-type', element);
220
- writer.removeAttribute('type', element);
221
- },
222
- getAttributeOnUpcast(listParent) {
223
- const style = listParent.getStyle('list-style-type');
224
- if (style) {
225
- return normalizeListStyle(style);
226
- }
227
- const attribute = listParent.getAttribute('type');
228
- if (attribute) {
229
- return getListStyleTypeFromTypeAttribute(attribute);
230
- }
231
- return DEFAULT_LIST_TYPE;
232
- }
233
- });
234
- }
235
- if (enabledProperties.reversed) {
236
- strategies.push({
237
- attributeName: 'listReversed',
238
- defaultValue: false,
239
- viewConsumables: { attributes: 'reversed' },
240
- addCommand(editor) {
241
- editor.commands.add('listReversed', new ListReversedCommand(editor));
242
- },
243
- appliesToListItem(item) {
244
- return item.getAttribute('listType') == 'numbered';
245
- },
246
- hasValidAttribute(item) {
247
- return this.appliesToListItem(item) == item.hasAttribute('listReversed');
248
- },
249
- setAttributeOnDowncast(writer, listReversed, element) {
250
- if (listReversed) {
251
- writer.setAttribute('reversed', 'reversed', element);
252
- }
253
- else {
254
- writer.removeAttribute('reversed', element);
255
- }
256
- },
257
- getAttributeOnUpcast(listParent) {
258
- return listParent.hasAttribute('reversed');
259
- }
260
- });
261
- }
262
- if (enabledProperties.startIndex) {
263
- strategies.push({
264
- attributeName: 'listStart',
265
- defaultValue: 1,
266
- viewConsumables: { attributes: 'start' },
267
- addCommand(editor) {
268
- editor.commands.add('listStart', new ListStartCommand(editor));
269
- },
270
- appliesToListItem(item) {
271
- return isNumberedListType(item.getAttribute('listType'));
272
- },
273
- hasValidAttribute(item) {
274
- return this.appliesToListItem(item) == item.hasAttribute('listStart');
275
- },
276
- setAttributeOnDowncast(writer, listStart, element) {
277
- if (listStart == 0 || listStart > 1) {
278
- writer.setAttribute('start', listStart, element);
279
- }
280
- else {
281
- writer.removeAttribute('start', element);
282
- }
283
- },
284
- getAttributeOnUpcast(listParent) {
285
- const startAttributeValue = listParent.getAttribute('start');
286
- return startAttributeValue >= 0 ? startAttributeValue : 1;
287
- }
288
- });
289
- }
290
- return strategies;
291
- }