@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,470 +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/todolist/todolistediting
7
- */
8
- import { Matcher } from 'ckeditor5/src/engine.js';
9
- import { getCode, parseKeystroke, getLocalizedArrowKeyCodeDirection } from 'ckeditor5/src/utils.js';
10
- import { Plugin } from 'ckeditor5/src/core.js';
11
- import { getAllListItemBlocks, isFirstBlockOfListItem, isListItemBlock } from '../list/utils/model.js';
12
- import { ListEditing } from '../list/listediting.js';
13
- import { ListCommand } from '../list/listcommand.js';
14
- import { CheckTodoListCommand } from './checktodolistcommand.js';
15
- import { TodoCheckboxChangeObserver } from './todocheckboxchangeobserver.js';
16
- const ITEM_TOGGLE_KEYSTROKE = /* #__PURE__ */ parseKeystroke('Ctrl+Enter');
17
- /**
18
- * The engine of the to-do list feature. It handles creating, editing and removing to-do lists and their items.
19
- *
20
- * It registers the entire functionality of the {@link module:list/list/listediting~ListEditing list editing plugin}
21
- * and extends it with the commands:
22
- *
23
- * - `'todoList'`,
24
- * - `'checkTodoList'`,
25
- */
26
- export class TodoListEditing extends Plugin {
27
- /**
28
- * @inheritDoc
29
- */
30
- static get pluginName() {
31
- return 'TodoListEditing';
32
- }
33
- /**
34
- * @inheritDoc
35
- */
36
- static get isOfficialPlugin() {
37
- return true;
38
- }
39
- /**
40
- * @inheritDoc
41
- */
42
- static get requires() {
43
- return [ListEditing];
44
- }
45
- /**
46
- * @inheritDoc
47
- */
48
- init() {
49
- const editor = this.editor;
50
- const model = editor.model;
51
- const editing = editor.editing;
52
- const listEditing = editor.plugins.get(ListEditing);
53
- const multiBlock = editor.config.get('list.multiBlock');
54
- const elementName = multiBlock ? 'paragraph' : 'listItem';
55
- editor.commands.add('todoList', new ListCommand(editor, 'todo'));
56
- editor.commands.add('checkTodoList', new CheckTodoListCommand(editor));
57
- editing.view.addObserver(TodoCheckboxChangeObserver);
58
- model.schema.extend('$listItem', { allowAttributes: 'todoListChecked' });
59
- model.schema.addAttributeCheck(context => {
60
- const item = context.last;
61
- // Don't allow `todoListChecked` attribute on elements which are not todo list items.
62
- if (!item.getAttribute('listItemId') || item.getAttribute('listType') != 'todo') {
63
- return false;
64
- }
65
- }, 'todoListChecked');
66
- editor.conversion.for('upcast').add(dispatcher => {
67
- // Upcast of to-do list item is based on a checkbox at the beginning of a <li> to keep compatibility with markdown input.
68
- dispatcher.on('element:input', todoItemInputConverter());
69
- // Priority is set to low to allow generic list item converter to run first.
70
- dispatcher.on('element:li', todoListItemUpcastConverter(), {
71
- priority: 'low'
72
- });
73
- // Consume other elements that are normally generated in data downcast, so they won't get captured by GHS.
74
- dispatcher.on('element:label', elementUpcastConsumingConverter({ name: 'label', classes: 'todo-list__label' }));
75
- dispatcher.on('element:label', elementUpcastConsumingConverter({ name: 'label', classes: ['todo-list__label', 'todo-list__label_without-description'] }));
76
- dispatcher.on('element:span', elementUpcastConsumingConverter({ name: 'span', classes: 'todo-list__label__description' }));
77
- dispatcher.on('element:ul', attributeUpcastConsumingConverter({ name: 'ul', classes: 'todo-list' }));
78
- });
79
- editor.conversion.for('downcast').elementToElement({
80
- model: elementName,
81
- view: (element, { writer }) => {
82
- if (isDescriptionBlock(element, listEditing.getListAttributeNames())) {
83
- return writer.createContainerElement('span', { class: 'todo-list__label__description' });
84
- }
85
- },
86
- converterPriority: 'highest'
87
- });
88
- listEditing.registerDowncastStrategy({
89
- scope: 'list',
90
- attributeName: 'listType',
91
- setAttributeOnDowncast(writer, value, element) {
92
- if (value == 'todo') {
93
- writer.addClass('todo-list', element);
94
- }
95
- else {
96
- writer.removeClass('todo-list', element);
97
- }
98
- }
99
- });
100
- listEditing.registerDowncastStrategy({
101
- scope: 'itemMarker',
102
- attributeName: 'todoListChecked',
103
- createElement(writer, modelElement, { dataPipeline }) {
104
- if (modelElement.getAttribute('listType') != 'todo') {
105
- return null;
106
- }
107
- const viewElement = writer.createUIElement('input', {
108
- type: 'checkbox',
109
- ...(modelElement.getAttribute('todoListChecked') ?
110
- { checked: 'checked' } :
111
- null),
112
- ...(dataPipeline ?
113
- { disabled: 'disabled' } :
114
- { tabindex: '-1' })
115
- });
116
- if (dataPipeline) {
117
- return viewElement;
118
- }
119
- const wrapper = writer.createContainerElement('span', { contenteditable: 'false' }, viewElement);
120
- wrapper.getFillerOffset = () => null;
121
- return wrapper;
122
- },
123
- canWrapElement(modelElement) {
124
- return isDescriptionBlock(modelElement, listEditing.getListAttributeNames());
125
- },
126
- createWrapperElement(writer, modelElement, { dataPipeline }) {
127
- const classes = ['todo-list__label'];
128
- if (!isDescriptionBlock(modelElement, listEditing.getListAttributeNames())) {
129
- classes.push('todo-list__label_without-description');
130
- }
131
- return writer.createAttributeElement(dataPipeline ? 'label' : 'span', {
132
- class: classes.join(' ')
133
- });
134
- }
135
- });
136
- // Verifies if a to-do list block requires reconversion of a first item downcasted as an item description.
137
- listEditing.on('checkElement', (evt, { modelElement, viewElement }) => {
138
- const isFirstTodoModelParagraphBlock = isDescriptionBlock(modelElement, listEditing.getListAttributeNames());
139
- const hasViewClass = viewElement.hasClass('todo-list__label__description');
140
- if (hasViewClass != isFirstTodoModelParagraphBlock) {
141
- evt.return = true;
142
- evt.stop();
143
- }
144
- });
145
- // Verifies if a to-do list block requires reconversion of a checkbox element
146
- // (for example there is a new paragraph inserted as a first block of a list item).
147
- listEditing.on('checkElement', (evt, { modelElement, viewElement }) => {
148
- const isFirstTodoModelItemBlock = modelElement.getAttribute('listType') == 'todo' && isFirstBlockOfListItem(modelElement);
149
- let hasViewItemMarker = false;
150
- const viewWalker = editor.editing.view.createPositionBefore(viewElement).getWalker({ direction: 'backward' });
151
- for (const { item } of viewWalker) {
152
- if (item.is('element') && editor.editing.mapper.toModelElement(item)) {
153
- break;
154
- }
155
- if (item.is('element', 'input') && item.getAttribute('type') == 'checkbox') {
156
- hasViewItemMarker = true;
157
- }
158
- }
159
- if (hasViewItemMarker != isFirstTodoModelItemBlock) {
160
- evt.return = true;
161
- evt.stop();
162
- }
163
- });
164
- // Make sure that all blocks of the same list item have the same todoListChecked attribute.
165
- listEditing.on('postFixer', (evt, { listNodes, writer }) => {
166
- for (const { node, previousNodeInList } of listNodes) {
167
- // This is a first item of a nested list.
168
- if (!previousNodeInList) {
169
- continue;
170
- }
171
- if (previousNodeInList.getAttribute('listItemId') != node.getAttribute('listItemId')) {
172
- continue;
173
- }
174
- const previousHasAttribute = previousNodeInList.hasAttribute('todoListChecked');
175
- const nodeHasAttribute = node.hasAttribute('todoListChecked');
176
- if (nodeHasAttribute && !previousHasAttribute) {
177
- writer.removeAttribute('todoListChecked', node);
178
- evt.return = true;
179
- }
180
- else if (!nodeHasAttribute && previousHasAttribute) {
181
- writer.setAttribute('todoListChecked', true, node);
182
- evt.return = true;
183
- }
184
- }
185
- });
186
- // Make sure that todoListChecked attribute is only present for to-do list items.
187
- model.document.registerPostFixer(writer => {
188
- const changes = model.document.differ.getChanges();
189
- let wasFixed = false;
190
- for (const change of changes) {
191
- if (change.type == 'attribute' && change.attributeKey == 'listType') {
192
- const element = change.range.start.nodeAfter;
193
- if (change.attributeOldValue == 'todo' && element.hasAttribute('todoListChecked')) {
194
- writer.removeAttribute('todoListChecked', element);
195
- wasFixed = true;
196
- }
197
- }
198
- else if (change.type == 'insert' && change.name != '$text') {
199
- for (const { item } of writer.createRangeOn(change.position.nodeAfter)) {
200
- if (item.is('element') && item.getAttribute('listType') != 'todo' && item.hasAttribute('todoListChecked')) {
201
- writer.removeAttribute('todoListChecked', item);
202
- wasFixed = true;
203
- }
204
- }
205
- }
206
- }
207
- return wasFixed;
208
- });
209
- // Toggle check state of selected to-do list items on keystroke.
210
- this.listenTo(editing.view.document, 'keydown', (evt, data) => {
211
- if (getCode(data) === ITEM_TOGGLE_KEYSTROKE) {
212
- editor.execute('checkTodoList');
213
- evt.stop();
214
- }
215
- }, { priority: 'high' });
216
- // Toggle check state of a to-do list item clicked on the checkbox.
217
- this.listenTo(editing.view.document, 'todoCheckboxChange', (evt, data) => {
218
- const viewTarget = data.target;
219
- if (!viewTarget || !viewTarget.is('element', 'input')) {
220
- return;
221
- }
222
- const viewPositionAfter = editing.view.createPositionAfter(viewTarget);
223
- const modelPositionAfter = editing.mapper.toModelPosition(viewPositionAfter);
224
- const modelElement = modelPositionAfter.parent;
225
- if (modelElement && isListItemBlock(modelElement) && modelElement.getAttribute('listType') == 'todo') {
226
- this._handleCheckmarkChange(modelElement);
227
- }
228
- });
229
- // Jump at the start/end of the next node on right arrow key press, when selection is before the checkbox.
230
- //
231
- // <blockquote><p>Foo{}</p></blockquote>
232
- // <ul><li><checkbox/>Bar</li></ul>
233
- //
234
- // press: `->`
235
- //
236
- // <blockquote><p>Foo</p></blockquote>
237
- // <ul><li><checkbox/>{}Bar</li></ul>
238
- //
239
- this.listenTo(editing.view.document, 'arrowKey', jumpOverCheckmarkOnSideArrowKeyPress(model, editor.locale), { context: '$text' });
240
- // Map view positions inside the checkbox and wrappers to the position in the first block of the list item.
241
- this.listenTo(editing.mapper, 'viewToModelPosition', (evt, data) => {
242
- const viewParent = data.viewPosition.parent;
243
- const isStartOfListItem = viewParent.is('attributeElement', 'li') && data.viewPosition.offset == 0;
244
- const isStartOfListLabel = isLabelElement(viewParent) && data.viewPosition.offset <= 1;
245
- const isInInputWrapper = viewParent.is('element', 'span') &&
246
- viewParent.getAttribute('contenteditable') == 'false' &&
247
- isLabelElement(viewParent.parent);
248
- if (!isStartOfListItem && !isStartOfListLabel && !isInInputWrapper) {
249
- return;
250
- }
251
- const nodeAfter = data.modelPosition.nodeAfter;
252
- if (nodeAfter && nodeAfter.getAttribute('listType') == 'todo') {
253
- data.modelPosition = model.createPositionAt(nodeAfter, 0);
254
- }
255
- }, { priority: 'low' });
256
- this._initAriaAnnouncements();
257
- }
258
- /**
259
- * Handles the checkbox element change, moves the selection to the corresponding model item to make it possible
260
- * to toggle the `todoListChecked` attribute using the command, and restores the selection position.
261
- *
262
- * Some say it's a hack :) Moving the selection only for executing the command on a certain node and restoring it after,
263
- * is not a clear solution. We need to design an API for using commands beyond the selection range.
264
- * See https://github.com/ckeditor/ckeditor5/issues/1954.
265
- */
266
- _handleCheckmarkChange(listItem) {
267
- const editor = this.editor;
268
- const model = editor.model;
269
- const previousSelectionRanges = Array.from(model.document.selection.getRanges());
270
- model.change(writer => {
271
- writer.setSelection(listItem, 'end');
272
- editor.execute('checkTodoList');
273
- writer.setSelection(previousSelectionRanges);
274
- });
275
- }
276
- /**
277
- * Observe when user enters or leaves todo list and set proper aria value in global live announcer.
278
- * This allows screen readers to indicate when the user has entered and left the specified todo list.
279
- *
280
- * @internal
281
- */
282
- _initAriaAnnouncements() {
283
- const { model, ui, t } = this.editor;
284
- let lastFocusedCodeBlock = null;
285
- if (!ui) {
286
- return;
287
- }
288
- model.document.selection.on('change:range', () => {
289
- const focusParent = model.document.selection.focus.parent;
290
- const lastElementIsTodoList = isTodoListItemElement(lastFocusedCodeBlock);
291
- const currentElementIsTodoList = isTodoListItemElement(focusParent);
292
- if (lastElementIsTodoList && !currentElementIsTodoList) {
293
- ui.ariaLiveAnnouncer.announce(t('Leaving a to-do list'));
294
- }
295
- else if (!lastElementIsTodoList && currentElementIsTodoList) {
296
- ui.ariaLiveAnnouncer.announce(t('Entering a to-do list'));
297
- }
298
- lastFocusedCodeBlock = focusParent;
299
- });
300
- }
301
- }
302
- /**
303
- * Returns an upcast converter for to-do list items.
304
- */
305
- function todoListItemUpcastConverter() {
306
- return (evt, data, conversionApi) => {
307
- const { writer, schema } = conversionApi;
308
- if (!data.modelRange) {
309
- return;
310
- }
311
- // Group to-do list items by their listItemId attribute to ensure that all items of the same list item have the same checked state.
312
- const groupedItems = Array
313
- .from(data.modelRange.getItems({ shallow: true }))
314
- .filter((item) => item.getAttribute('listType') === 'todo' && schema.checkAttribute(item, 'listItemId'))
315
- .reduce((acc, item) => {
316
- const listItemId = item.getAttribute('listItemId');
317
- if (!acc.has(listItemId)) {
318
- acc.set(listItemId, getAllListItemBlocks(item));
319
- }
320
- return acc;
321
- }, new Map());
322
- // During the upcast, we need to ensure that all items of the same list have the same checked state. From time to time
323
- // the checked state of the items can be different when the user pastes content from the clipboard with <input type="checkbox">
324
- // that has checked state set to true. In such cases, we need to ensure that all items of the same list have the same checked state.
325
- // See more: https://github.com/ckeditor/ckeditor5/issues/15602
326
- for (const [, items] of groupedItems.entries()) {
327
- if (items.some(item => item.getAttribute('todoListChecked'))) {
328
- for (const item of items) {
329
- writer.setAttribute('todoListChecked', true, item);
330
- }
331
- }
332
- }
333
- };
334
- }
335
- /**
336
- * Returns an upcast converter that detects a to-do list checkbox and marks the list item as a to-do list.
337
- */
338
- function todoItemInputConverter() {
339
- return (evt, data, conversionApi) => {
340
- const modelCursor = data.modelCursor;
341
- const modelItem = modelCursor.parent;
342
- const viewItem = data.viewItem;
343
- if (!conversionApi.consumable.test(viewItem, { name: true })) {
344
- return;
345
- }
346
- if (viewItem.getAttribute('type') != 'checkbox' || !modelCursor.isAtStart || !modelItem.hasAttribute('listType')) {
347
- return;
348
- }
349
- conversionApi.consumable.consume(viewItem, { name: true });
350
- const writer = conversionApi.writer;
351
- writer.setAttribute('listType', 'todo', modelItem);
352
- if (data.viewItem.hasAttribute('checked')) {
353
- writer.setAttribute('todoListChecked', true, modelItem);
354
- }
355
- data.modelRange = writer.createRange(modelCursor);
356
- };
357
- }
358
- /**
359
- * Returns an upcast converter that consumes element matching the given matcher pattern.
360
- */
361
- function elementUpcastConsumingConverter(matcherPattern) {
362
- const matcher = new Matcher(matcherPattern);
363
- return (evt, data, conversionApi) => {
364
- const matcherResult = matcher.match(data.viewItem);
365
- if (!matcherResult) {
366
- return;
367
- }
368
- if (!conversionApi.consumable.consume(data.viewItem, matcherResult.match)) {
369
- return;
370
- }
371
- Object.assign(data, conversionApi.convertChildren(data.viewItem, data.modelCursor));
372
- };
373
- }
374
- /**
375
- * Returns an upcast converter that consumes attributes matching the given matcher pattern.
376
- */
377
- function attributeUpcastConsumingConverter(matcherPattern) {
378
- const matcher = new Matcher(matcherPattern);
379
- return (evt, data, conversionApi) => {
380
- const matcherResult = matcher.match(data.viewItem);
381
- if (!matcherResult) {
382
- return;
383
- }
384
- const match = matcherResult.match;
385
- match.name = false;
386
- conversionApi.consumable.consume(data.viewItem, match);
387
- };
388
- }
389
- /**
390
- * Returns true if the given list item block should be converted as a description block of a to-do list item.
391
- */
392
- function isDescriptionBlock(modelElement, listAttributeNames) {
393
- return (modelElement.is('element', 'paragraph') || modelElement.is('element', 'listItem')) &&
394
- modelElement.getAttribute('listType') == 'todo' &&
395
- isFirstBlockOfListItem(modelElement) &&
396
- hasOnlyListAttributes(modelElement, listAttributeNames);
397
- }
398
- /**
399
- * Returns true if only attributes from the given list are present on the model element.
400
- */
401
- function hasOnlyListAttributes(modelElement, attributeNames) {
402
- for (const attributeKey of modelElement.getAttributeKeys()) {
403
- // Ignore selection attributes stored on block elements.
404
- if (attributeKey.startsWith('selection:')) {
405
- continue;
406
- }
407
- if (!attributeNames.includes(attributeKey)) {
408
- return false;
409
- }
410
- }
411
- return true;
412
- }
413
- /**
414
- * Jump at the start and end of a to-do list item.
415
- */
416
- function jumpOverCheckmarkOnSideArrowKeyPress(model, locale) {
417
- return (eventInfo, domEventData) => {
418
- const direction = getLocalizedArrowKeyCodeDirection(domEventData.keyCode, locale.contentLanguageDirection);
419
- const schema = model.schema;
420
- const selection = model.document.selection;
421
- if (!selection.isCollapsed) {
422
- return;
423
- }
424
- const position = selection.getFirstPosition();
425
- const parent = position.parent;
426
- // Right arrow before a to-do list item.
427
- if (direction == 'right' && position.isAtEnd) {
428
- const newRange = schema.getNearestSelectionRange(model.createPositionAfter(parent), 'forward');
429
- if (!newRange) {
430
- return;
431
- }
432
- const newRangeParent = newRange.start.parent;
433
- if (newRangeParent && isListItemBlock(newRangeParent) && newRangeParent.getAttribute('listType') == 'todo') {
434
- model.change(writer => writer.setSelection(newRange));
435
- domEventData.preventDefault();
436
- domEventData.stopPropagation();
437
- eventInfo.stop();
438
- }
439
- }
440
- // Left arrow at the beginning of a to-do list item.
441
- else if (direction == 'left' && position.isAtStart && isListItemBlock(parent) && parent.getAttribute('listType') == 'todo') {
442
- const newRange = schema.getNearestSelectionRange(model.createPositionBefore(parent), 'backward');
443
- if (!newRange) {
444
- return;
445
- }
446
- model.change(writer => writer.setSelection(newRange));
447
- domEventData.preventDefault();
448
- domEventData.stopPropagation();
449
- eventInfo.stop();
450
- }
451
- };
452
- }
453
- /**
454
- * Returns true if the given element is a label element of a to-do list item.
455
- */
456
- function isLabelElement(viewElement) {
457
- return !!viewElement && viewElement.is('attributeElement') && viewElement.hasClass('todo-list__label');
458
- }
459
- /**
460
- * Returns true if the given element is a list item model element of a to-do list.
461
- */
462
- function isTodoListItemElement(element) {
463
- if (!element) {
464
- return false;
465
- }
466
- if (!element.is('element', 'paragraph') && !element.is('element', 'listItem')) {
467
- return false;
468
- }
469
- return element.getAttribute('listType') == 'todo';
470
- }
@@ -1,35 +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/todolist/todolistui
7
- */
8
- import { createUIComponents } from '../list/utils.js';
9
- import { Plugin } from 'ckeditor5/src/core.js';
10
- import { IconTodoList } from 'ckeditor5/src/icons.js';
11
- /**
12
- * The to-do list UI feature. It introduces the `'todoList'` button that
13
- * allows to convert elements to and from to-do list items and to indent or outdent them.
14
- */
15
- export class TodoListUI extends Plugin {
16
- /**
17
- * @inheritDoc
18
- */
19
- static get pluginName() {
20
- return 'TodoListUI';
21
- }
22
- /**
23
- * @inheritDoc
24
- */
25
- static get isOfficialPlugin() {
26
- return true;
27
- }
28
- /**
29
- * @inheritDoc
30
- */
31
- init() {
32
- const t = this.editor.t;
33
- createUIComponents(this.editor, 'todoList', t('To-do List'), IconTodoList);
34
- }
35
- }
package/src/todolist.js DELETED
@@ -1,37 +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/todolist
7
- */
8
- import { TodoListEditing } from './todolist/todolistediting.js';
9
- import { TodoListUI } from './todolist/todolistui.js';
10
- import { Plugin } from 'ckeditor5/src/core.js';
11
- import '../theme/todolist.css';
12
- /**
13
- * The to-do list feature.
14
- *
15
- * This is a "glue" plugin that loads the {@link module:list/todolist/todolistediting~TodoListEditing to-do list
16
- * editing feature} and the {@link module:list/todolist/todolistui~TodoListUI to-do list UI feature}.
17
- */
18
- export class TodoList extends Plugin {
19
- /**
20
- * @inheritDoc
21
- */
22
- static get requires() {
23
- return [TodoListEditing, TodoListUI];
24
- }
25
- /**
26
- * @inheritDoc
27
- */
28
- static get pluginName() {
29
- return 'TodoList';
30
- }
31
- /**
32
- * @inheritDoc
33
- */
34
- static get isOfficialPlugin() {
35
- return true;
36
- }
37
- }
@@ -1,8 +0,0 @@
1
- /*
2
- * 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
- .ck-editor__editable .ck-list-bogus-paragraph {
7
- display: block;
8
- }
package/theme/list.css DELETED
@@ -1,40 +0,0 @@
1
- /*
2
- * 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
- .ck-content ol {
7
- list-style-type: decimal;
8
-
9
- & ol {
10
- list-style-type: lower-latin;
11
-
12
- & ol {
13
- list-style-type: lower-roman;
14
-
15
- & ol {
16
- list-style-type: upper-latin;
17
-
18
- & ol {
19
- list-style-type: upper-roman;
20
- }
21
- }
22
- }
23
- }
24
- }
25
-
26
- .ck-content ul {
27
- list-style-type: disc;
28
-
29
- & ul {
30
- list-style-type: circle;
31
-
32
- & ul {
33
- list-style-type: square;
34
-
35
- & ul {
36
- list-style-type: square;
37
- }
38
- }
39
- }
40
- }
@@ -1,66 +0,0 @@
1
- /*
2
- * 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
- :root {
7
- --ck-content-list-marker-color: var(--ck-content-font-color);
8
- --ck-content-list-marker-font-family: var(--ck-content-font-family);
9
- --ck-content-list-marker-font-size: var(--ck-content-font-size);
10
- }
11
-
12
- .ck-content li {
13
- /* Opinionated list content styling: prevents content shift
14
- * when a list becomes multi-block (Enter + Backspace scenario).
15
- * See: https://github.com/ckeditor/ckeditor5/pull/18801
16
- */
17
- & > p:first-of-type {
18
- margin-top: 0;
19
- }
20
-
21
- /* Prevents margins from appearing when a bogus paragraph
22
- * receives line height or text alignment.
23
- * Ensures a consistent experience with the first paragraph.
24
- * See: https://github.com/ckeditor/ckeditor5/pull/18801
25
- */
26
- & > p:only-of-type {
27
- margin-top: 0;
28
- margin-bottom: 0;
29
- }
30
-
31
- &.ck-list-marker-bold::marker {
32
- font-weight: bold;
33
- }
34
-
35
- &.ck-list-marker-italic::marker {
36
- font-style: italic;
37
- }
38
-
39
- &.ck-list-marker-color::marker {
40
- color: var(--ck-content-list-marker-color);
41
- }
42
-
43
- &.ck-list-marker-font-family::marker {
44
- font-family: var(--ck-content-list-marker-font-family);
45
- }
46
-
47
- &.ck-list-marker-font-size::marker {
48
- font-size: var(--ck-content-list-marker-font-size);
49
- }
50
-
51
- &.ck-list-marker-font-size-tiny::marker {
52
- font-size: var(--ck-content-font-size-tiny);
53
- }
54
-
55
- &.ck-list-marker-font-size-small::marker {
56
- font-size: var(--ck-content-font-size-small);
57
- }
58
-
59
- &.ck-list-marker-font-size-big::marker {
60
- font-size: var(--ck-content-font-size-big);
61
- }
62
-
63
- &.ck-list-marker-font-size-huge::marker {
64
- font-size: var(--ck-content-font-size-huge);
65
- }
66
- }
@@ -1,10 +0,0 @@
1
- /*
2
- * 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
- /*
7
- * Note: This file should contain the wireframe styles only. But since there are no such styles,
8
- * it acts as a message to the builder telling that it should look for the corresponding styles
9
- * **in the theme** when compiling the editor.
10
- */
@@ -1,8 +0,0 @@
1
- /*
2
- * 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
- .ck.ck-list-styles-list {
7
- display: grid;
8
- }