@ckeditor/ckeditor5-list 35.3.2 → 36.0.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 (55) hide show
  1. package/LICENSE.md +1 -1
  2. package/build/list.js +2 -2
  3. package/package.json +43 -39
  4. package/src/documentlist/converters.js +303 -419
  5. package/src/documentlist/documentlistcommand.js +136 -207
  6. package/src/documentlist/documentlistediting.js +538 -697
  7. package/src/documentlist/documentlistindentcommand.js +115 -168
  8. package/src/documentlist/documentlistmergecommand.js +161 -222
  9. package/src/documentlist/documentlistsplitcommand.js +59 -103
  10. package/src/documentlist/documentlistutils.js +41 -0
  11. package/src/documentlist/utils/listwalker.js +138 -236
  12. package/src/documentlist/utils/model.js +322 -421
  13. package/src/documentlist/utils/postfixers.js +98 -118
  14. package/src/documentlist/utils/view.js +74 -105
  15. package/src/documentlist.js +13 -19
  16. package/src/documentlistproperties/converters.js +33 -47
  17. package/src/documentlistproperties/documentlistpropertiesediting.js +266 -354
  18. package/src/documentlistproperties/documentlistpropertiesutils.js +44 -0
  19. package/src/documentlistproperties/documentlistreversedcommand.js +40 -61
  20. package/src/documentlistproperties/documentliststartcommand.js +42 -61
  21. package/src/documentlistproperties/documentliststylecommand.js +97 -147
  22. package/src/documentlistproperties/utils/style.js +27 -47
  23. package/src/documentlistproperties.js +13 -19
  24. package/src/index.js +4 -3
  25. package/src/list/converters.js +772 -929
  26. package/src/list/indentcommand.js +105 -140
  27. package/src/list/listcommand.js +262 -315
  28. package/src/list/listediting.js +142 -200
  29. package/src/list/listui.js +16 -25
  30. package/src/list/listutils.js +46 -0
  31. package/src/list/utils.js +295 -378
  32. package/src/list.js +13 -44
  33. package/src/listcommands.js +5 -0
  34. package/src/listconfig.js +5 -0
  35. package/src/listproperties/listpropertiesediting.js +656 -801
  36. package/src/listproperties/listpropertiesui.js +244 -296
  37. package/src/listproperties/listreversedcommand.js +37 -49
  38. package/src/listproperties/liststartcommand.js +37 -49
  39. package/src/listproperties/liststylecommand.js +82 -115
  40. package/src/listproperties/ui/collapsibleview.js +75 -138
  41. package/src/listproperties/ui/listpropertiesview.js +289 -414
  42. package/src/listproperties.js +13 -118
  43. package/src/liststyle.js +18 -24
  44. package/src/todolist/checktodolistcommand.js +60 -102
  45. package/src/todolist/todolistconverters.js +189 -271
  46. package/src/todolist/todolistediting.js +141 -206
  47. package/src/todolist/todolistui.js +14 -21
  48. package/src/todolist.js +13 -19
  49. package/theme/collapsible.css +1 -1
  50. package/theme/documentlist.css +1 -1
  51. package/theme/list.css +40 -0
  52. package/theme/listproperties.css +1 -1
  53. package/theme/liststyles.css +1 -37
  54. package/theme/todolist.css +1 -1
  55. package/build/list.js.map +0 -1
@@ -1,219 +1,161 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module list/list/listediting
8
7
  */
9
-
10
8
  import ListCommand from './listcommand';
11
9
  import IndentCommand from './indentcommand';
12
-
10
+ import ListUtils from './listutils';
13
11
  import { Plugin } from 'ckeditor5/src/core';
14
12
  import { Enter } from 'ckeditor5/src/enter';
15
13
  import { Delete } from 'ckeditor5/src/typing';
16
-
17
- import {
18
- cleanList,
19
- cleanListItem,
20
- modelViewInsertion,
21
- modelViewChangeType,
22
- modelViewMergeAfterChangeType,
23
- modelViewMergeAfter,
24
- modelViewRemove,
25
- modelViewSplitOnInsert,
26
- modelViewChangeIndent,
27
- modelChangePostFixer,
28
- modelIndentPasteFixer,
29
- viewModelConverter,
30
- modelToViewPosition,
31
- viewToModelPosition
32
- } from './converters';
33
-
14
+ import { cleanList, cleanListItem, modelViewInsertion, modelViewChangeType, modelViewMergeAfterChangeType, modelViewMergeAfter, modelViewRemove, modelViewSplitOnInsert, modelViewChangeIndent, modelChangePostFixer, modelIndentPasteFixer, viewModelConverter, modelToViewPosition, viewToModelPosition } from './converters';
15
+ import '../../theme/list.css';
34
16
  /**
35
17
  * The engine of the list feature. It handles creating, editing and removing lists and list items.
36
18
  *
37
19
  * It registers the `'numberedList'`, `'bulletedList'`, `'indentList'` and `'outdentList'` commands.
38
- *
39
- * @extends module:core/plugin~Plugin
40
20
  */
41
21
  export default class ListEditing extends Plugin {
42
- /**
43
- * @inheritDoc
44
- */
45
- static get pluginName() {
46
- return 'ListEditing';
47
- }
48
-
49
- /**
50
- * @inheritDoc
51
- */
52
- static get requires() {
53
- return [ Enter, Delete ];
54
- }
55
-
56
- /**
57
- * @inheritDoc
58
- */
59
- init() {
60
- const editor = this.editor;
61
-
62
- // Schema.
63
- // Note: in case `$block` will ever be allowed in `listItem`, keep in mind that this feature
64
- // uses `Selection#getSelectedBlocks()` without any additional processing to obtain all selected list items.
65
- // If there are blocks allowed inside list item, algorithms using `getSelectedBlocks()` will have to be modified.
66
- editor.model.schema.register( 'listItem', {
67
- inheritAllFrom: '$block',
68
- allowAttributes: [ 'listType', 'listIndent' ]
69
- } );
70
-
71
- // Converters.
72
- const data = editor.data;
73
- const editing = editor.editing;
74
-
75
- editor.model.document.registerPostFixer( writer => modelChangePostFixer( editor.model, writer ) );
76
-
77
- editing.mapper.registerViewToModelLength( 'li', getViewListItemLength );
78
- data.mapper.registerViewToModelLength( 'li', getViewListItemLength );
79
-
80
- editing.mapper.on( 'modelToViewPosition', modelToViewPosition( editing.view ) );
81
- editing.mapper.on( 'viewToModelPosition', viewToModelPosition( editor.model ) );
82
- data.mapper.on( 'modelToViewPosition', modelToViewPosition( editing.view ) );
83
-
84
- editor.conversion.for( 'editingDowncast' )
85
- .add( dispatcher => {
86
- dispatcher.on( 'insert', modelViewSplitOnInsert, { priority: 'high' } );
87
- dispatcher.on( 'insert:listItem', modelViewInsertion( editor.model ) );
88
- dispatcher.on( 'attribute:listType:listItem', modelViewChangeType, { priority: 'high' } );
89
- dispatcher.on( 'attribute:listType:listItem', modelViewMergeAfterChangeType, { priority: 'low' } );
90
- dispatcher.on( 'attribute:listIndent:listItem', modelViewChangeIndent( editor.model ) );
91
- dispatcher.on( 'remove:listItem', modelViewRemove( editor.model ) );
92
- dispatcher.on( 'remove', modelViewMergeAfter, { priority: 'low' } );
93
- } );
94
-
95
- editor.conversion.for( 'dataDowncast' )
96
- .add( dispatcher => {
97
- dispatcher.on( 'insert', modelViewSplitOnInsert, { priority: 'high' } );
98
- dispatcher.on( 'insert:listItem', modelViewInsertion( editor.model ) );
99
- } );
100
-
101
- editor.conversion.for( 'upcast' )
102
- .add( dispatcher => {
103
- dispatcher.on( 'element:ul', cleanList, { priority: 'high' } );
104
- dispatcher.on( 'element:ol', cleanList, { priority: 'high' } );
105
- dispatcher.on( 'element:li', cleanListItem, { priority: 'high' } );
106
- dispatcher.on( 'element:li', viewModelConverter );
107
- } );
108
-
109
- // Fix indentation of pasted items.
110
- editor.model.on( 'insertContent', modelIndentPasteFixer, { priority: 'high' } );
111
-
112
- // Register commands for numbered and bulleted list.
113
- editor.commands.add( 'numberedList', new ListCommand( editor, 'numbered' ) );
114
- editor.commands.add( 'bulletedList', new ListCommand( editor, 'bulleted' ) );
115
-
116
- // Register commands for indenting.
117
- editor.commands.add( 'indentList', new IndentCommand( editor, 'forward' ) );
118
- editor.commands.add( 'outdentList', new IndentCommand( editor, 'backward' ) );
119
-
120
- const viewDocument = editing.view.document;
121
-
122
- // Overwrite default Enter key behavior.
123
- // If Enter key is pressed with selection collapsed in empty list item, outdent it instead of breaking it.
124
- this.listenTo( viewDocument, 'enter', ( evt, data ) => {
125
- const doc = this.editor.model.document;
126
- const positionParent = doc.selection.getLastPosition().parent;
127
-
128
- if ( doc.selection.isCollapsed && positionParent.name == 'listItem' && positionParent.isEmpty ) {
129
- this.editor.execute( 'outdentList' );
130
-
131
- data.preventDefault();
132
- evt.stop();
133
- }
134
- }, { context: 'li' } );
135
-
136
- // Overwrite default Backspace key behavior.
137
- // If Backspace key is pressed with selection collapsed on first position in first list item, outdent it. #83
138
- this.listenTo( viewDocument, 'delete', ( evt, data ) => {
139
- // Check conditions from those that require less computations like those immediately available.
140
- if ( data.direction !== 'backward' ) {
141
- return;
142
- }
143
-
144
- const selection = this.editor.model.document.selection;
145
-
146
- if ( !selection.isCollapsed ) {
147
- return;
148
- }
149
-
150
- const firstPosition = selection.getFirstPosition();
151
-
152
- if ( !firstPosition.isAtStart ) {
153
- return;
154
- }
155
-
156
- const positionParent = firstPosition.parent;
157
-
158
- if ( positionParent.name !== 'listItem' ) {
159
- return;
160
- }
161
-
162
- const previousIsAListItem = positionParent.previousSibling && positionParent.previousSibling.name === 'listItem';
163
-
164
- if ( previousIsAListItem ) {
165
- return;
166
- }
167
-
168
- this.editor.execute( 'outdentList' );
169
-
170
- data.preventDefault();
171
- evt.stop();
172
- }, { context: 'li' } );
173
-
174
- this.listenTo( editor.editing.view.document, 'tab', ( evt, data ) => {
175
- const commandName = data.shiftKey ? 'outdentList' : 'indentList';
176
- const command = this.editor.commands.get( commandName );
177
-
178
- if ( command.isEnabled ) {
179
- editor.execute( commandName );
180
-
181
- data.stopPropagation();
182
- data.preventDefault();
183
- evt.stop();
184
- }
185
- }, { context: 'li' } );
186
- }
187
-
188
- /**
189
- * @inheritDoc
190
- */
191
- afterInit() {
192
- const commands = this.editor.commands;
193
-
194
- const indent = commands.get( 'indent' );
195
- const outdent = commands.get( 'outdent' );
196
-
197
- if ( indent ) {
198
- indent.registerChildCommand( commands.get( 'indentList' ) );
199
- }
200
-
201
- if ( outdent ) {
202
- outdent.registerChildCommand( commands.get( 'outdentList' ) );
203
- }
204
- }
22
+ /**
23
+ * @inheritDoc
24
+ */
25
+ static get pluginName() {
26
+ return 'ListEditing';
27
+ }
28
+ /**
29
+ * @inheritDoc
30
+ */
31
+ static get requires() {
32
+ return [Enter, Delete, ListUtils];
33
+ }
34
+ /**
35
+ * @inheritDoc
36
+ */
37
+ init() {
38
+ const editor = this.editor;
39
+ // Schema.
40
+ // Note: in case `$block` will ever be allowed in `listItem`, keep in mind that this feature
41
+ // uses `Selection#getSelectedBlocks()` without any additional processing to obtain all selected list items.
42
+ // If there are blocks allowed inside list item, algorithms using `getSelectedBlocks()` will have to be modified.
43
+ editor.model.schema.register('listItem', {
44
+ inheritAllFrom: '$block',
45
+ allowAttributes: ['listType', 'listIndent']
46
+ });
47
+ // Converters.
48
+ const data = editor.data;
49
+ const editing = editor.editing;
50
+ editor.model.document.registerPostFixer(writer => modelChangePostFixer(editor.model, writer));
51
+ editing.mapper.registerViewToModelLength('li', getViewListItemLength);
52
+ data.mapper.registerViewToModelLength('li', getViewListItemLength);
53
+ editing.mapper.on('modelToViewPosition', modelToViewPosition(editing.view));
54
+ editing.mapper.on('viewToModelPosition', viewToModelPosition(editor.model));
55
+ data.mapper.on('modelToViewPosition', modelToViewPosition(editing.view));
56
+ editor.conversion.for('editingDowncast')
57
+ .add(dispatcher => {
58
+ dispatcher.on('insert', modelViewSplitOnInsert, { priority: 'high' });
59
+ dispatcher.on('insert:listItem', modelViewInsertion(editor.model));
60
+ dispatcher.on('attribute:listType:listItem', modelViewChangeType, { priority: 'high' });
61
+ dispatcher.on('attribute:listType:listItem', modelViewMergeAfterChangeType, { priority: 'low' });
62
+ dispatcher.on('attribute:listIndent:listItem', modelViewChangeIndent(editor.model));
63
+ dispatcher.on('remove:listItem', modelViewRemove(editor.model));
64
+ dispatcher.on('remove', modelViewMergeAfter, { priority: 'low' });
65
+ });
66
+ editor.conversion.for('dataDowncast')
67
+ .add(dispatcher => {
68
+ dispatcher.on('insert', modelViewSplitOnInsert, { priority: 'high' });
69
+ dispatcher.on('insert:listItem', modelViewInsertion(editor.model));
70
+ });
71
+ editor.conversion.for('upcast')
72
+ .add(dispatcher => {
73
+ dispatcher.on('element:ul', cleanList, { priority: 'high' });
74
+ dispatcher.on('element:ol', cleanList, { priority: 'high' });
75
+ dispatcher.on('element:li', cleanListItem, { priority: 'high' });
76
+ dispatcher.on('element:li', viewModelConverter);
77
+ });
78
+ // Fix indentation of pasted items.
79
+ editor.model.on('insertContent', modelIndentPasteFixer, { priority: 'high' });
80
+ // Register commands for numbered and bulleted list.
81
+ editor.commands.add('numberedList', new ListCommand(editor, 'numbered'));
82
+ editor.commands.add('bulletedList', new ListCommand(editor, 'bulleted'));
83
+ // Register commands for indenting.
84
+ editor.commands.add('indentList', new IndentCommand(editor, 'forward'));
85
+ editor.commands.add('outdentList', new IndentCommand(editor, 'backward'));
86
+ const viewDocument = editing.view.document;
87
+ // Overwrite default Enter key behavior.
88
+ // If Enter key is pressed with selection collapsed in empty list item, outdent it instead of breaking it.
89
+ this.listenTo(viewDocument, 'enter', (evt, data) => {
90
+ const doc = this.editor.model.document;
91
+ const positionParent = doc.selection.getLastPosition().parent;
92
+ if (doc.selection.isCollapsed && positionParent.name == 'listItem' && positionParent.isEmpty) {
93
+ this.editor.execute('outdentList');
94
+ data.preventDefault();
95
+ evt.stop();
96
+ }
97
+ }, { context: 'li' });
98
+ // Overwrite default Backspace key behavior.
99
+ // If Backspace key is pressed with selection collapsed on first position in first list item, outdent it. #83
100
+ this.listenTo(viewDocument, 'delete', (evt, data) => {
101
+ // Check conditions from those that require less computations like those immediately available.
102
+ if (data.direction !== 'backward') {
103
+ return;
104
+ }
105
+ const selection = this.editor.model.document.selection;
106
+ if (!selection.isCollapsed) {
107
+ return;
108
+ }
109
+ const firstPosition = selection.getFirstPosition();
110
+ if (!firstPosition.isAtStart) {
111
+ return;
112
+ }
113
+ const positionParent = firstPosition.parent;
114
+ if (positionParent.name !== 'listItem') {
115
+ return;
116
+ }
117
+ const previousIsAListItem = positionParent.previousSibling && positionParent.previousSibling.name === 'listItem';
118
+ if (previousIsAListItem) {
119
+ return;
120
+ }
121
+ this.editor.execute('outdentList');
122
+ data.preventDefault();
123
+ evt.stop();
124
+ }, { context: 'li' });
125
+ this.listenTo(editor.editing.view.document, 'tab', (evt, data) => {
126
+ const commandName = data.shiftKey ? 'outdentList' : 'indentList';
127
+ const command = this.editor.commands.get(commandName);
128
+ if (command.isEnabled) {
129
+ editor.execute(commandName);
130
+ data.stopPropagation();
131
+ data.preventDefault();
132
+ evt.stop();
133
+ }
134
+ }, { context: 'li' });
135
+ }
136
+ /**
137
+ * @inheritDoc
138
+ */
139
+ afterInit() {
140
+ const commands = this.editor.commands;
141
+ const indent = commands.get('indent');
142
+ const outdent = commands.get('outdent');
143
+ if (indent) {
144
+ indent.registerChildCommand(commands.get('indentList'));
145
+ }
146
+ if (outdent) {
147
+ outdent.registerChildCommand(commands.get('outdentList'));
148
+ }
149
+ }
205
150
  }
206
-
207
- function getViewListItemLength( element ) {
208
- let length = 1;
209
-
210
- for ( const child of element.getChildren() ) {
211
- if ( child.name == 'ul' || child.name == 'ol' ) {
212
- for ( const item of child.getChildren() ) {
213
- length += getViewListItemLength( item );
214
- }
215
- }
216
- }
217
-
218
- return length;
151
+ function getViewListItemLength(element) {
152
+ let length = 1;
153
+ for (const child of element.getChildren()) {
154
+ if (child.name == 'ul' || child.name == 'ol') {
155
+ for (const item of child.getChildren()) {
156
+ length += getViewListItemLength(item);
157
+ }
158
+ }
159
+ }
160
+ return length;
219
161
  }
@@ -1,41 +1,32 @@
1
1
  /**
2
- * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
-
6
5
  /**
7
6
  * @module list/list/listui
8
7
  */
9
-
10
8
  import { createUIComponent } from './utils';
11
-
12
9
  import numberedListIcon from '../../theme/icons/numberedlist.svg';
13
10
  import bulletedListIcon from '../../theme/icons/bulletedlist.svg';
14
-
15
11
  import { Plugin } from 'ckeditor5/src/core';
16
-
17
12
  /**
18
13
  * The list UI feature. It introduces the `'numberedList'` and `'bulletedList'` buttons that
19
14
  * allow to convert paragraphs to and from list items and indent or outdent them.
20
- *
21
- * @extends module:core/plugin~Plugin
22
15
  */
23
16
  export default class ListUI extends Plugin {
24
- /**
25
- * @inheritDoc
26
- */
27
- static get pluginName() {
28
- return 'ListUI';
29
- }
30
-
31
- /**
32
- * @inheritDoc
33
- */
34
- init() {
35
- const t = this.editor.t;
36
-
37
- // Create two buttons and link them with numberedList and bulletedList commands.
38
- createUIComponent( this.editor, 'numberedList', t( 'Numbered List' ), numberedListIcon );
39
- createUIComponent( this.editor, 'bulletedList', t( 'Bulleted List' ), bulletedListIcon );
40
- }
17
+ /**
18
+ * @inheritDoc
19
+ */
20
+ static get pluginName() {
21
+ return 'ListUI';
22
+ }
23
+ /**
24
+ * @inheritDoc
25
+ */
26
+ init() {
27
+ const t = this.editor.t;
28
+ // Create two buttons and link them with numberedList and bulletedList commands.
29
+ createUIComponent(this.editor, 'numberedList', t('Numbered List'), numberedListIcon);
30
+ createUIComponent(this.editor, 'bulletedList', t('Bulleted List'), bulletedListIcon);
31
+ }
41
32
  }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
+ */
5
+ import { Plugin } from 'ckeditor5/src/core';
6
+ import { getListTypeFromListStyleType, getSelectedListItems, getSiblingNodes } from './utils';
7
+ /**
8
+ * A set of helpers related to document lists.
9
+ */
10
+ export default class ListUtils extends Plugin {
11
+ /**
12
+ * @inheritDoc
13
+ */
14
+ static get pluginName() {
15
+ return 'ListUtils';
16
+ }
17
+ /**
18
+ * Checks whether the given list-style-type is supported by numbered or bulleted list.
19
+ */
20
+ getListTypeFromListStyleType(listStyleType) {
21
+ return getListTypeFromListStyleType(listStyleType);
22
+ }
23
+ /**
24
+ * Returns an array with all `listItem` elements in the model selection.
25
+ *
26
+ * It returns all the items even if only a part of the list is selected, including items that belong to nested lists.
27
+ * If no list is selected, it returns an empty array.
28
+ * The order of the elements is not specified.
29
+ */
30
+ getSelectedListItems(model) {
31
+ return getSelectedListItems(model);
32
+ }
33
+ /**
34
+ * Returns an array with all `listItem` elements that represent the same list.
35
+ *
36
+ * It means that values of `listIndent`, `listType`, `listStyle`, `listReversed` and `listStart` for all items are equal.
37
+ *
38
+ * Additionally, if the `position` is inside a list item, that list item will be returned as well.
39
+ *
40
+ * @param position Starting position.
41
+ * @param direction Walking direction.
42
+ */
43
+ getSiblingNodes(position, direction) {
44
+ return getSiblingNodes(position, direction);
45
+ }
46
+ }