@ckeditor/ckeditor5-list 47.6.1-alpha.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,703 +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/legacylistproperties/legacylistpropertiesediting
7
- */
8
- import { Plugin } from 'ckeditor5/src/core.js';
9
- import { LegacyListEditing } from '../legacylist/legacylistediting.js';
10
- import { LegacyListStyleCommand } from './legacyliststylecommand.js';
11
- import { LegacyListReversedCommand } from './legacylistreversedcommand.js';
12
- import { LegacyListStartCommand } from './legacyliststartcommand.js';
13
- import { getSiblingListItem, getSiblingNodes } from '../legacylist/legacyutils.js';
14
- import { normalizeListStyle } from '../listproperties/utils/style.js';
15
- const DEFAULT_LIST_TYPE = 'default';
16
- /**
17
- * The engine of the list properties feature.
18
- *
19
- * It sets the value for the `listItem` attribute of the {@link module:list/legacylist~LegacyList `<listItem>`} element that
20
- * allows modifying the list style type.
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 LegacyListPropertiesEditing extends Plugin {
26
- /**
27
- * @inheritDoc
28
- */
29
- static get requires() {
30
- return [LegacyListEditing];
31
- }
32
- /**
33
- * @inheritDoc
34
- */
35
- static get pluginName() {
36
- return 'LegacyListPropertiesEditing';
37
- }
38
- /**
39
- * @inheritDoc
40
- */
41
- static get isOfficialPlugin() {
42
- return true;
43
- }
44
- /**
45
- * @inheritDoc
46
- */
47
- constructor(editor) {
48
- super(editor);
49
- editor.config.define('list', {
50
- properties: {
51
- styles: true,
52
- startIndex: false,
53
- reversed: false
54
- }
55
- });
56
- }
57
- /**
58
- * @inheritDoc
59
- */
60
- init() {
61
- const editor = this.editor;
62
- const model = editor.model;
63
- const enabledProperties = editor.config.get('list.properties');
64
- const strategies = createAttributeStrategies(enabledProperties);
65
- // Extend schema.
66
- model.schema.extend('listItem', {
67
- allowAttributes: strategies.map(s => s.attributeName)
68
- });
69
- for (const strategy of strategies) {
70
- strategy.addCommand(editor);
71
- }
72
- // Fix list attributes when modifying their nesting levels (the `listIndent` attribute).
73
- this.listenTo(editor.commands.get('indentList'), '_executeCleanup', fixListAfterIndentListCommand(editor, strategies));
74
- this.listenTo(editor.commands.get('outdentList'), '_executeCleanup', fixListAfterOutdentListCommand(editor, strategies));
75
- this.listenTo(editor.commands.get('bulletedList'), '_executeCleanup', restoreDefaultListStyle(editor));
76
- this.listenTo(editor.commands.get('numberedList'), '_executeCleanup', restoreDefaultListStyle(editor));
77
- // Register a post-fixer that ensures that the attributes is specified in each `listItem` element.
78
- model.document.registerPostFixer(fixListAttributesOnListItemElements(editor, strategies));
79
- // Set up conversion.
80
- editor.conversion.for('upcast').add(upcastListItemAttributes(strategies));
81
- editor.conversion.for('downcast').add(downcastListItemAttributes(strategies));
82
- // Handle merging two separated lists into the single one.
83
- this._mergeListAttributesWhileMergingLists(strategies);
84
- }
85
- /**
86
- * @inheritDoc
87
- */
88
- afterInit() {
89
- const editor = this.editor;
90
- // Enable post-fixer that removes the attributes from to-do list items only if the "TodoList" plugin is on.
91
- // We need to registry the hook here since the `TodoList` plugin can be added after the `ListPropertiesEditing`.
92
- if (editor.commands.get('todoList')) {
93
- editor.model.document.registerPostFixer(removeListItemAttributesFromTodoList(editor));
94
- }
95
- }
96
- /**
97
- * Starts listening to {@link module:engine/model/model~Model#deleteContent} and checks whether two lists will be merged into a single
98
- * one after deleting the content.
99
- *
100
- * The purpose of this action is to adjust the `listStyle`, `listReversed` and `listStart` values
101
- * for the list that was merged.
102
- *
103
- * Consider the following model's content:
104
- *
105
- * ```xml
106
- * <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
107
- * <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 2</listItem>
108
- * <paragraph>[A paragraph.]</paragraph>
109
- * <listItem listIndent="0" listType="bulleted" listStyle="circle">UL List item 1</listItem>
110
- * <listItem listIndent="0" listType="bulleted" listStyle="circle">UL List item 2</listItem>
111
- * ```
112
- *
113
- * After removing the paragraph element, the second list will be merged into the first one.
114
- * We want to inherit the `listStyle` attribute for the second list from the first one.
115
- *
116
- * ```xml
117
- * <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
118
- * <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 2</listItem>
119
- * <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
120
- * <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 2</listItem>
121
- * ```
122
- *
123
- * See https://github.com/ckeditor/ckeditor5/issues/7879.
124
- *
125
- * @param attributeStrategies Strategies for the enabled attributes.
126
- */
127
- _mergeListAttributesWhileMergingLists(attributeStrategies) {
128
- const editor = this.editor;
129
- const model = editor.model;
130
- // First the outer-most`listItem` in the first list reference.
131
- // If found, the lists should be merged and this `listItem` provides the attributes
132
- // and it is also a starting point when searching for items in the second list.
133
- let firstMostOuterItem;
134
- // Check whether the removed content is between two lists.
135
- this.listenTo(model, 'deleteContent', (evt, [selection]) => {
136
- const firstPosition = selection.getFirstPosition();
137
- const lastPosition = selection.getLastPosition();
138
- // Typing or removing content in a single item. Aborting.
139
- if (firstPosition.parent === lastPosition.parent) {
140
- return;
141
- }
142
- // An element before the content that will be removed is not a list.
143
- if (!firstPosition.parent.is('element', 'listItem')) {
144
- return;
145
- }
146
- const nextSibling = lastPosition.parent.nextSibling;
147
- // An element after the content that will be removed is not a list.
148
- if (!nextSibling || !nextSibling.is('element', 'listItem')) {
149
- return;
150
- }
151
- // Find the outermost list item based on the `listIndent` attribute. We can't assume that `listIndent=0`
152
- // because the selection can be hooked in nested lists.
153
- //
154
- // <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
155
- // <listItem listIndent="1" listType="bulleted" listStyle="square">UL List [item 1.1</listItem>
156
- // <listItem listIndent="0" listType="bulleted" listStyle="circle">[]UL List item 1.</listItem>
157
- // <listItem listIndent="1" listType="bulleted" listStyle="circle">UL List ]item 1.1</listItem>
158
- //
159
- // After deleting the content, we would like to inherit the "square" attribute for the last element:
160
- //
161
- // <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
162
- // <listItem listIndent="1" listType="bulleted" listStyle="square">UL List []item 1.1</listItem>
163
- const mostOuterItemList = getSiblingListItem(firstPosition.parent, {
164
- sameIndent: true,
165
- listIndent: nextSibling.getAttribute('listIndent')
166
- });
167
- // The outermost list item may not exist while removing elements between lists with different value
168
- // of the `listIndent` attribute. In such a case we don't want to update anything. See: #8073.
169
- if (!mostOuterItemList) {
170
- return;
171
- }
172
- if (mostOuterItemList.getAttribute('listType') === nextSibling.getAttribute('listType')) {
173
- firstMostOuterItem = mostOuterItemList;
174
- }
175
- }, { priority: 'high' });
176
- // If so, update the `listStyle` attribute for the second list.
177
- this.listenTo(model, 'deleteContent', () => {
178
- if (!firstMostOuterItem) {
179
- return;
180
- }
181
- model.change(writer => {
182
- // Find the first most-outer item list in the merged list.
183
- // A case when the first list item in the second list was merged into the last item in the first list.
184
- //
185
- // <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 1</listItem>
186
- // <listItem listIndent="0" listType="bulleted" listStyle="square">UL List item 2</listItem>
187
- // <listItem listIndent="0" listType="bulleted" listStyle="circle">[]UL List item 1</listItem>
188
- // <listItem listIndent="0" listType="bulleted" listStyle="circle">UL List item 2</listItem>
189
- const secondListMostOuterItem = getSiblingListItem(firstMostOuterItem.nextSibling, {
190
- sameIndent: true,
191
- listIndent: firstMostOuterItem.getAttribute('listIndent'),
192
- direction: 'forward'
193
- });
194
- // If the selection ends in a non-list element, there are no <listItem>s that would require adjustments.
195
- // See: #8642.
196
- if (!secondListMostOuterItem) {
197
- firstMostOuterItem = null;
198
- return;
199
- }
200
- const items = [
201
- secondListMostOuterItem,
202
- ...getSiblingNodes(writer.createPositionAt(secondListMostOuterItem, 0), 'forward')
203
- ];
204
- for (const listItem of items) {
205
- for (const strategy of attributeStrategies) {
206
- if (strategy.appliesToListItem(listItem)) {
207
- const attributeName = strategy.attributeName;
208
- const value = firstMostOuterItem.getAttribute(attributeName);
209
- writer.setAttribute(attributeName, value, listItem);
210
- }
211
- }
212
- }
213
- });
214
- firstMostOuterItem = null;
215
- }, { priority: 'low' });
216
- }
217
- }
218
- /**
219
- * Creates an array of strategies for dealing with enabled listItem attributes.
220
- */
221
- function createAttributeStrategies(enabledProperties) {
222
- const strategies = [];
223
- if (enabledProperties.styles) {
224
- strategies.push({
225
- attributeName: 'listStyle',
226
- defaultValue: DEFAULT_LIST_TYPE,
227
- addCommand(editor) {
228
- editor.commands.add('listStyle', new LegacyListStyleCommand(editor, DEFAULT_LIST_TYPE));
229
- },
230
- appliesToListItem() {
231
- return true;
232
- },
233
- setAttributeOnDowncast(writer, listStyle, element) {
234
- if (listStyle && listStyle !== DEFAULT_LIST_TYPE) {
235
- writer.setStyle('list-style-type', listStyle, element);
236
- }
237
- else {
238
- writer.removeStyle('list-style-type', element);
239
- }
240
- },
241
- getAttributeOnUpcast(listParent) {
242
- return normalizeListStyle(listParent.getStyle('list-style-type')) || DEFAULT_LIST_TYPE;
243
- }
244
- });
245
- }
246
- if (enabledProperties.reversed) {
247
- strategies.push({
248
- attributeName: 'listReversed',
249
- defaultValue: false,
250
- addCommand(editor) {
251
- editor.commands.add('listReversed', new LegacyListReversedCommand(editor));
252
- },
253
- appliesToListItem(item) {
254
- return item.getAttribute('listType') == 'numbered';
255
- },
256
- setAttributeOnDowncast(writer, listReversed, element) {
257
- if (listReversed) {
258
- writer.setAttribute('reversed', 'reversed', element);
259
- }
260
- else {
261
- writer.removeAttribute('reversed', element);
262
- }
263
- },
264
- getAttributeOnUpcast(listParent) {
265
- return listParent.hasAttribute('reversed');
266
- }
267
- });
268
- }
269
- if (enabledProperties.startIndex) {
270
- strategies.push({
271
- attributeName: 'listStart',
272
- defaultValue: 1,
273
- addCommand(editor) {
274
- editor.commands.add('listStart', new LegacyListStartCommand(editor));
275
- },
276
- appliesToListItem(item) {
277
- return item.getAttribute('listType') == 'numbered';
278
- },
279
- setAttributeOnDowncast(writer, listStart, element) {
280
- if (listStart == 0 || listStart > 1) {
281
- writer.setAttribute('start', listStart, element);
282
- }
283
- else {
284
- writer.removeAttribute('start', element);
285
- }
286
- },
287
- getAttributeOnUpcast(listParent) {
288
- const startAttributeValue = listParent.getAttribute('start');
289
- return startAttributeValue >= 0 ? startAttributeValue : 1;
290
- }
291
- });
292
- }
293
- return strategies;
294
- }
295
- /**
296
- * Returns a converter consumes the `style`, `reversed` and `start` attribute.
297
- * In `style` it searches for the `list-style-type` definition.
298
- * If not found, the `"default"` value will be used.
299
- */
300
- function upcastListItemAttributes(attributeStrategies) {
301
- return (dispatcher) => {
302
- dispatcher.on('element:li', (evt, data, conversionApi) => {
303
- // https://github.com/ckeditor/ckeditor5/issues/13858
304
- if (!data.modelRange) {
305
- return;
306
- }
307
- const listParent = data.viewItem.parent;
308
- const listItem = data.modelRange.start.nodeAfter || data.modelRange.end.nodeBefore;
309
- for (const strategy of attributeStrategies) {
310
- if (strategy.appliesToListItem(listItem)) {
311
- const listStyle = strategy.getAttributeOnUpcast(listParent);
312
- conversionApi.writer.setAttribute(strategy.attributeName, listStyle, listItem);
313
- }
314
- }
315
- }, { priority: 'low' });
316
- };
317
- }
318
- /**
319
- * Returns a converter that adds `reversed`, `start` attributes and adds `list-style-type` definition as a value for the `style` attribute.
320
- * The `"default"` values are removed and not present in the view/data.
321
- */
322
- function downcastListItemAttributes(attributeStrategies) {
323
- return (dispatcher) => {
324
- for (const strategy of attributeStrategies) {
325
- dispatcher.on(`attribute:${strategy.attributeName}:listItem`, (evt, data, conversionApi) => {
326
- const viewWriter = conversionApi.writer;
327
- const currentElement = data.item;
328
- const previousElement = getSiblingListItem(currentElement.previousSibling, {
329
- sameIndent: true,
330
- listIndent: currentElement.getAttribute('listIndent'),
331
- direction: 'backward'
332
- });
333
- const viewItem = conversionApi.mapper.toViewElement(currentElement);
334
- // A case when elements represent different lists. We need to separate their container.
335
- if (!areRepresentingSameList(currentElement, previousElement)) {
336
- viewWriter.breakContainer(viewWriter.createPositionBefore(viewItem));
337
- }
338
- strategy.setAttributeOnDowncast(viewWriter, data.attributeNewValue, viewItem.parent);
339
- }, { priority: 'low' });
340
- }
341
- };
342
- /**
343
- * Checks whether specified list items belong to the same list.
344
- */
345
- function areRepresentingSameList(listItem1, listItem2) {
346
- return listItem2 &&
347
- listItem1.getAttribute('listType') === listItem2.getAttribute('listType') &&
348
- listItem1.getAttribute('listIndent') === listItem2.getAttribute('listIndent') &&
349
- listItem1.getAttribute('listStyle') === listItem2.getAttribute('listStyle') &&
350
- listItem1.getAttribute('listReversed') === listItem2.getAttribute('listReversed') &&
351
- listItem1.getAttribute('listStart') === listItem2.getAttribute('listStart');
352
- }
353
- }
354
- /**
355
- * When indenting list, nested list should clear its value for the attributes or inherit from nested lists.
356
- *
357
- * ■ List item 1.
358
- * ■ List item 2.[]
359
- * ■ List item 3.
360
- * editor.execute( 'indentList' );
361
- *
362
- * ■ List item 1.
363
- * ○ List item 2.[]
364
- * ■ List item 3.
365
- */
366
- function fixListAfterIndentListCommand(editor, attributeStrategies) {
367
- return (evt, changedItems) => {
368
- const root = changedItems[0];
369
- const rootIndent = root.getAttribute('listIndent');
370
- const itemsToUpdate = changedItems.filter(item => item.getAttribute('listIndent') === rootIndent);
371
- // A case where a few list items are indented must be checked separately
372
- // since `getSiblingListItem()` returns the first changed element.
373
- // ■ List item 1.
374
- // ○ [List item 2.
375
- // ○ List item 3.]
376
- // ■ List item 4.
377
- //
378
- // List items: `2` and `3` should be adjusted.
379
- let previousSibling = null;
380
- if (root.previousSibling.getAttribute('listIndent') + 1 !== rootIndent) {
381
- previousSibling = getSiblingListItem(root.previousSibling, {
382
- sameIndent: true, direction: 'backward', listIndent: rootIndent
383
- });
384
- }
385
- editor.model.change(writer => {
386
- for (const item of itemsToUpdate) {
387
- for (const strategy of attributeStrategies) {
388
- if (strategy.appliesToListItem(item)) {
389
- const valueToSet = previousSibling == null ?
390
- strategy.defaultValue :
391
- previousSibling.getAttribute(strategy.attributeName);
392
- writer.setAttribute(strategy.attributeName, valueToSet, item);
393
- }
394
- }
395
- }
396
- });
397
- };
398
- }
399
- /**
400
- * When outdenting a list, a nested list should copy attribute values
401
- * from the previous sibling list item including the same value for the `listIndent` value.
402
- *
403
- * ■ List item 1.
404
- * ○ List item 2.[]
405
- * ■ List item 3.
406
- *
407
- * editor.execute( 'outdentList' );
408
- *
409
- * ■ List item 1.
410
- * ■ List item 2.[]
411
- * ■ List item 3.
412
- */
413
- function fixListAfterOutdentListCommand(editor, attributeStrategies) {
414
- return (evt, changedItems) => {
415
- changedItems = changedItems.reverse().filter(item => item.is('element', 'listItem'));
416
- if (!changedItems.length) {
417
- return;
418
- }
419
- const indent = changedItems[0].getAttribute('listIndent');
420
- const listType = changedItems[0].getAttribute('listType');
421
- let listItem = changedItems[0].previousSibling;
422
- // ■ List item 1.
423
- // ○ List item 2.
424
- // ○ List item 3.[]
425
- // ■ List item 4.
426
- //
427
- // After outdenting a list, `List item 3` should inherit the `listStyle` attribute from `List item 1`.
428
- //
429
- // ■ List item 1.
430
- // ○ List item 2.
431
- // ■ List item 3.[]
432
- // ■ List item 4.
433
- if (listItem.is('element', 'listItem')) {
434
- while (listItem.getAttribute('listIndent') !== indent) {
435
- listItem = listItem.previousSibling;
436
- }
437
- }
438
- else {
439
- listItem = null;
440
- }
441
- // Outdenting such a list should restore values based on `List item 4`.
442
- // ■ List item 1.[]
443
- // ○ List item 2.
444
- // ○ List item 3.
445
- // ■ List item 4.
446
- if (!listItem) {
447
- listItem = changedItems[changedItems.length - 1].nextSibling;
448
- }
449
- // And such a list should not modify anything.
450
- // However, `listItem` can indicate a node below the list. Be sure that we have the `listItem` element.
451
- // ■ List item 1.[]
452
- // ○ List item 2.
453
- // ○ List item 3.
454
- // <paragraph>The later if check.</paragraph>
455
- if (!listItem || !listItem.is('element', 'listItem')) {
456
- return;
457
- }
458
- // Do not modify the list if found `listItem` represents other type of list than outdented list items.
459
- if (listItem.getAttribute('listType') !== listType) {
460
- return;
461
- }
462
- editor.model.change(writer => {
463
- const itemsToUpdate = changedItems.filter(item => item.getAttribute('listIndent') === indent);
464
- for (const item of itemsToUpdate) {
465
- for (const strategy of attributeStrategies) {
466
- if (strategy.appliesToListItem(item)) {
467
- const attributeName = strategy.attributeName;
468
- const valueToSet = listItem.getAttribute(attributeName);
469
- writer.setAttribute(attributeName, valueToSet, item);
470
- }
471
- }
472
- }
473
- });
474
- };
475
- }
476
- /**
477
- * Each `listItem` element must have specified the `listStyle`, `listReversed` and `listStart` attributes
478
- * if they are enabled and supported by its `listType`.
479
- * This post-fixer checks whether inserted elements `listItem` elements should inherit the attribute values from
480
- * their sibling nodes or should use the default values.
481
- *
482
- * Paragraph[]
483
- * ■ List item 1. // [listStyle="square", listType="bulleted"]
484
- * ■ List item 2. // ...
485
- * ■ List item 3. // ...
486
- *
487
- * editor.execute( 'bulletedList' )
488
- *
489
- * ■ Paragraph[] // [listStyle="square", listType="bulleted"]
490
- * ■ List item 1. // [listStyle="square", listType="bulleted"]
491
- * ■ List item 2.
492
- * ■ List item 3.
493
- *
494
- * It also covers a such change:
495
- *
496
- * [Paragraph 1
497
- * Paragraph 2]
498
- * ■ List item 1. // [listStyle="square", listType="bulleted"]
499
- * ■ List item 2. // ...
500
- * ■ List item 3. // ...
501
- *
502
- * editor.execute( 'numberedList' )
503
- *
504
- * 1. [Paragraph 1 // [listStyle="default", listType="numbered"]
505
- * 2. Paragraph 2] // [listStyle="default", listType="numbered"]
506
- * ■ List item 1. // [listStyle="square", listType="bulleted"]
507
- * ■ List item 2. // ...
508
- * ■ List item 3. // ...
509
- */
510
- function fixListAttributesOnListItemElements(editor, attributeStrategies) {
511
- return (writer) => {
512
- let wasFixed = false;
513
- const insertedListItems = getChangedListItems(editor.model.document.differ.getChanges())
514
- .filter(item => {
515
- // Don't touch todo lists. They are handled in another post-fixer.
516
- return item.getAttribute('listType') !== 'todo';
517
- });
518
- if (!insertedListItems.length) {
519
- return wasFixed;
520
- }
521
- // Check whether the last inserted element is next to the `listItem` element.
522
- //
523
- // ■ Paragraph[] // <-- The inserted item.
524
- // ■ List item 1.
525
- let existingListItem = insertedListItems[insertedListItems.length - 1].nextSibling;
526
- // If it doesn't, maybe the `listItem` was inserted at the end of the list.
527
- //
528
- // ■ List item 1.
529
- // ■ Paragraph[] // <-- The inserted item.
530
- if (!existingListItem || !existingListItem.is('element', 'listItem')) {
531
- existingListItem = insertedListItems[0].previousSibling;
532
- if (existingListItem) {
533
- const indent = insertedListItems[0].getAttribute('listIndent');
534
- // But we need to find a `listItem` with the `listIndent=0` attribute.
535
- // If doesn't, maybe the `listItem` was inserted at the end of the list.
536
- //
537
- // ■ List item 1.
538
- // ○ List item 2.
539
- // ■ Paragraph[] // <-- The inserted item.
540
- while (existingListItem.is('element', 'listItem') && existingListItem.getAttribute('listIndent') !== indent) {
541
- existingListItem = existingListItem.previousSibling;
542
- // If the item does not exist, most probably there is no other content in the editor. See: #8072.
543
- if (!existingListItem) {
544
- break;
545
- }
546
- }
547
- }
548
- }
549
- for (const strategy of attributeStrategies) {
550
- const attributeName = strategy.attributeName;
551
- for (const item of insertedListItems) {
552
- if (!strategy.appliesToListItem(item)) {
553
- writer.removeAttribute(attributeName, item);
554
- continue;
555
- }
556
- if (!item.hasAttribute(attributeName)) {
557
- if (shouldInheritListType(existingListItem, item, strategy)) {
558
- writer.setAttribute(attributeName, existingListItem.getAttribute(attributeName), item);
559
- }
560
- else {
561
- writer.setAttribute(attributeName, strategy.defaultValue, item);
562
- }
563
- wasFixed = true;
564
- }
565
- else {
566
- // Adjust the `listStyle`, `listReversed` and `listStart`
567
- // attributes for inserted (pasted) items. See #8160.
568
- //
569
- // ■ List item 1. // [listStyle="square", listType="bulleted"]
570
- // ○ List item 1.1. // [listStyle="circle", listType="bulleted"]
571
- // ○ [] (selection is here)
572
- //
573
- // Then, pasting a list with different attributes (listStyle, listType):
574
- //
575
- // 1. First. // [listStyle="decimal", listType="numbered"]
576
- // 2. Second // [listStyle="decimal", listType="numbered"]
577
- //
578
- // The `listType` attribute will be corrected by the `ListEditing` converters.
579
- // We need to adjust the `listStyle` attribute. Expected structure:
580
- //
581
- // ■ List item 1. // [listStyle="square", listType="bulleted"]
582
- // ○ List item 1.1. // [listStyle="circle", listType="bulleted"]
583
- // ○ First. // [listStyle="circle", listType="bulleted"]
584
- // ○ Second // [listStyle="circle", listType="bulleted"]
585
- const previousSibling = item.previousSibling;
586
- if (shouldInheritListTypeFromPreviousItem(previousSibling, item, strategy.attributeName)) {
587
- writer.setAttribute(attributeName, previousSibling.getAttribute(attributeName), item);
588
- wasFixed = true;
589
- }
590
- }
591
- }
592
- }
593
- return wasFixed;
594
- };
595
- }
596
- /**
597
- * Checks whether the `listStyle`, `listReversed` and `listStart` attributes
598
- * should be copied from the `baseItem` element.
599
- *
600
- * The attribute should be copied if the inserted element does not have defined it and
601
- * the value for the element is other than default in the base element.
602
- */
603
- function shouldInheritListType(baseItem, itemToChange, attributeStrategy) {
604
- if (!baseItem) {
605
- return false;
606
- }
607
- const baseListAttribute = baseItem.getAttribute(attributeStrategy.attributeName);
608
- if (!baseListAttribute) {
609
- return false;
610
- }
611
- if (baseListAttribute == attributeStrategy.defaultValue) {
612
- return false;
613
- }
614
- if (baseItem.getAttribute('listType') !== itemToChange.getAttribute('listType')) {
615
- return false;
616
- }
617
- return true;
618
- }
619
- /**
620
- * Checks whether the `listStyle`, `listReversed` and `listStart` attributes
621
- * should be copied from previous list item.
622
- *
623
- * The attribute should be copied if there's a mismatch of styles of the pasted list into a nested list.
624
- * Top-level lists are not normalized as we allow side-by-side list of different types.
625
- */
626
- function shouldInheritListTypeFromPreviousItem(previousItem, itemToChange, attributeName) {
627
- if (!previousItem || !previousItem.is('element', 'listItem')) {
628
- return false;
629
- }
630
- if (itemToChange.getAttribute('listType') !== previousItem.getAttribute('listType')) {
631
- return false;
632
- }
633
- const previousItemIndent = previousItem.getAttribute('listIndent');
634
- if (previousItemIndent < 1 || previousItemIndent !== itemToChange.getAttribute('listIndent')) {
635
- return false;
636
- }
637
- const previousItemListAttribute = previousItem.getAttribute(attributeName);
638
- if (!previousItemListAttribute || previousItemListAttribute === itemToChange.getAttribute(attributeName)) {
639
- return false;
640
- }
641
- return true;
642
- }
643
- /**
644
- * Removes the `listStyle`, `listReversed` and `listStart` attributes from "todo" list items.
645
- */
646
- function removeListItemAttributesFromTodoList(editor) {
647
- return (writer) => {
648
- const todoListItems = getChangedListItems(editor.model.document.differ.getChanges())
649
- .filter(item => {
650
- // Handle the todo lists only. The rest is handled in another post-fixer.
651
- return item.getAttribute('listType') === 'todo' && (item.hasAttribute('listStyle') ||
652
- item.hasAttribute('listReversed') ||
653
- item.hasAttribute('listStart'));
654
- });
655
- if (!todoListItems.length) {
656
- return false;
657
- }
658
- for (const item of todoListItems) {
659
- writer.removeAttribute('listStyle', item);
660
- writer.removeAttribute('listReversed', item);
661
- writer.removeAttribute('listStart', item);
662
- }
663
- return true;
664
- };
665
- }
666
- /**
667
- * Restores the `listStyle` attribute after changing the list type.
668
- */
669
- function restoreDefaultListStyle(editor) {
670
- return (evt, changedItems) => {
671
- changedItems = changedItems.filter(item => item.is('element', 'listItem'));
672
- editor.model.change(writer => {
673
- for (const item of changedItems) {
674
- // Remove the attribute. Post-fixer will restore the proper value.
675
- writer.removeAttribute('listStyle', item);
676
- }
677
- });
678
- };
679
- }
680
- /**
681
- * Returns the `listItem` that was inserted or changed.
682
- *
683
- * @param changes The changes list returned by the differ.
684
- */
685
- function getChangedListItems(changes) {
686
- const items = [];
687
- for (const change of changes) {
688
- const item = getItemFromChange(change);
689
- if (item && item.is('element', 'listItem')) {
690
- items.push(item);
691
- }
692
- }
693
- return items;
694
- }
695
- function getItemFromChange(change) {
696
- if (change.type === 'attribute') {
697
- return change.range.start.nodeAfter;
698
- }
699
- if (change.type === 'insert') {
700
- return change.position.nodeAfter;
701
- }
702
- return null;
703
- }