@ckeditor/ckeditor5-list 35.4.0 → 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 (54) 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 -698
  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 +31 -45
  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 -126
  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 +265 -356
  18. package/src/documentlistproperties/documentlistpropertiesutils.js +32 -57
  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 +1 -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 +141 -200
  29. package/src/list/listui.js +16 -25
  30. package/src/list/listutils.js +37 -59
  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 -803
  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 -415
  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
@@ -1,235 +1,174 @@
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/documentlist/documentlistmergecommand
8
7
  */
9
-
10
8
  import { Command } from 'ckeditor5/src/core';
11
- import {
12
- getNestedListBlocks,
13
- indentBlocks,
14
- sortBlocks,
15
- isFirstBlockOfListItem,
16
- mergeListItemBefore,
17
- isSingleListItem,
18
- getSelectedBlockObject,
19
- isListItemBlock
20
- } from './utils/model';
9
+ import { getNestedListBlocks, indentBlocks, sortBlocks, isFirstBlockOfListItem, mergeListItemBefore, isSingleListItem, getSelectedBlockObject, isListItemBlock } from './utils/model';
21
10
  import ListWalker from './utils/listwalker';
22
-
23
11
  /**
24
12
  * The document list merge command. It is used by the {@link module:list/documentlist~DocumentList list feature}.
25
- *
26
- * @extends module:core/command~Command
27
13
  */
28
14
  export default class DocumentListMergeCommand extends Command {
29
- /**
30
- * Creates an instance of the command.
31
- *
32
- * @param {module:core/editor/editor~Editor} editor The editor instance.
33
- * @param {'backward'|'forward'} direction Whether list item should be merged before or after the selected block.
34
- */
35
- constructor( editor, direction ) {
36
- super( editor );
37
-
38
- /**
39
- * Whether list item should be merged before or after the selected block.
40
- *
41
- * @readonly
42
- * @private
43
- * @member {'backward'|'forward'}
44
- */
45
- this._direction = direction;
46
- }
47
-
48
- /**
49
- * @inheritDoc
50
- */
51
- refresh() {
52
- this.isEnabled = this._checkEnabled();
53
- }
54
-
55
- /**
56
- * Merges list blocks together (depending on the {@link #constructor}'s `direction` parameter).
57
- *
58
- * @fires execute
59
- * @fires afterExecute
60
- * @param {Object} [options] Command options.
61
- * @param {String|Boolean} [options.shouldMergeOnBlocksContentLevel=false] When set `true`, merging will be performed together
62
- * with {@link module:engine/model/model~Model#deleteContent} to get rid of the inline content in the selection or take advantage
63
- * of the heuristics in `deleteContent()` that helps convert lists into paragraphs in certain cases.
64
- */
65
- execute( { shouldMergeOnBlocksContentLevel = false } = {} ) {
66
- const model = this.editor.model;
67
- const selection = model.document.selection;
68
- const changedBlocks = [];
69
-
70
- model.change( writer => {
71
- const { firstElement, lastElement } = this._getMergeSubjectElements( selection, shouldMergeOnBlocksContentLevel );
72
-
73
- const firstIndent = firstElement.getAttribute( 'listIndent' ) || 0;
74
- const lastIndent = lastElement.getAttribute( 'listIndent' );
75
- const lastElementId = lastElement.getAttribute( 'listItemId' );
76
-
77
- if ( firstIndent != lastIndent ) {
78
- const nestedLastElementBlocks = getNestedListBlocks( lastElement );
79
-
80
- changedBlocks.push( ...indentBlocks( [ lastElement, ...nestedLastElementBlocks ], writer, {
81
- indentBy: firstIndent - lastIndent,
82
-
83
- // If outdenting, the entire sub-tree that follows must be included.
84
- expand: firstIndent < lastIndent
85
- } ) );
86
- }
87
-
88
- if ( shouldMergeOnBlocksContentLevel ) {
89
- let sel = selection;
90
-
91
- if ( selection.isCollapsed ) {
92
- sel = writer.createSelection( writer.createRange(
93
- writer.createPositionAt( firstElement, 'end' ),
94
- writer.createPositionAt( lastElement, 0 )
95
- ) );
96
- }
97
-
98
- // Delete selected content. Replace entire content only for non-collapsed selection.
99
- model.deleteContent( sel, { doNotResetEntireContent: selection.isCollapsed } );
100
-
101
- // Get the last "touched" element after deleteContent call (can't use the lastElement because
102
- // it could get merged into the firstElement while deleting content).
103
- const lastElementAfterDelete = sel.getLastPosition().parent;
104
-
105
- // Check if the element after it was in the same list item and adjust it if needed.
106
- const nextSibling = lastElementAfterDelete.nextSibling;
107
-
108
- changedBlocks.push( lastElementAfterDelete );
109
-
110
- if ( nextSibling && nextSibling !== lastElement && nextSibling.getAttribute( 'listItemId' ) == lastElementId ) {
111
- changedBlocks.push( ...mergeListItemBefore( nextSibling, lastElementAfterDelete, writer ) );
112
- }
113
- } else {
114
- changedBlocks.push( ...mergeListItemBefore( lastElement, firstElement, writer ) );
115
- }
116
-
117
- this._fireAfterExecute( changedBlocks );
118
- } );
119
- }
120
-
121
- /**
122
- * Fires the `afterExecute` event.
123
- *
124
- * @private
125
- * @param {Array.<module:engine/model/element~Element>} changedBlocks The changed list elements.
126
- */
127
- _fireAfterExecute( changedBlocks ) {
128
- /**
129
- * Event fired by the {@link #execute} method.
130
- *
131
- * It allows to execute an action after executing the {@link ~DocumentListMergeCommand#execute} method,
132
- * for example adjusting attributes of changed list items.
133
- *
134
- * @protected
135
- * @event afterExecute
136
- */
137
- this.fire( 'afterExecute', sortBlocks( new Set( changedBlocks ) ) );
138
- }
139
-
140
- /**
141
- * Checks whether the command can be enabled in the current context.
142
- *
143
- * @private
144
- * @returns {Boolean} Whether the command should be enabled.
145
- */
146
- _checkEnabled() {
147
- const model = this.editor.model;
148
- const selection = model.document.selection;
149
- const selectedBlockObject = getSelectedBlockObject( model );
150
-
151
- if ( selection.isCollapsed || selectedBlockObject ) {
152
- const positionParent = selectedBlockObject || selection.getFirstPosition().parent;
153
-
154
- if ( !isListItemBlock( positionParent ) ) {
155
- return false;
156
- }
157
-
158
- const siblingNode = this._direction == 'backward' ?
159
- positionParent.previousSibling :
160
- positionParent.nextSibling;
161
-
162
- if ( !siblingNode ) {
163
- return false;
164
- }
165
-
166
- if ( isSingleListItem( [ positionParent, siblingNode ] ) ) {
167
- return false;
168
- }
169
- } else {
170
- const lastPosition = selection.getLastPosition();
171
- const firstPosition = selection.getFirstPosition();
172
-
173
- // If deleting within a single block of a list item, there's no need to merge anything.
174
- // The default delete should be executed instead.
175
- if ( lastPosition.parent === firstPosition.parent ) {
176
- return false;
177
- }
178
-
179
- if ( !isListItemBlock( lastPosition.parent ) ) {
180
- return false;
181
- }
182
- }
183
-
184
- return true;
185
- }
186
-
187
- /**
188
- * Returns the boundary elements the merge should be executed for. These are not necessarily selection's first
189
- * and last position parents but sometimes sibling or even further blocks depending on the context.
190
- *
191
- * @param {module:engine/model/selection~Selection} selection The selection the merge is executed for.
192
- * @param {Boolean} shouldMergeOnBlocksContentLevel When `true`, merge is performed together with
193
- * {@link module:engine/model/model~Model#deleteContent} to remove the inline content within the selection.
194
- * @returns {Object} elements
195
- * @returns {module:engine/model/element~Element} elements.firstElement
196
- * @returns {module:engine/model/element~Element} elements.lastElement
197
- */
198
- _getMergeSubjectElements( selection, shouldMergeOnBlocksContentLevel ) {
199
- const model = this.editor.model;
200
- const selectedBlockObject = getSelectedBlockObject( model );
201
- let firstElement, lastElement;
202
-
203
- if ( selection.isCollapsed || selectedBlockObject ) {
204
- const positionParent = selectedBlockObject || selection.getFirstPosition().parent;
205
- const isFirstBlock = isFirstBlockOfListItem( positionParent );
206
-
207
- if ( this._direction == 'backward' ) {
208
- lastElement = positionParent;
209
-
210
- if ( isFirstBlock && !shouldMergeOnBlocksContentLevel ) {
211
- // For the "c" as an anchorElement:
212
- // * a
213
- // * b
214
- // * [c] <-- this block should be merged with "a"
215
- // It should find "a" element to merge with:
216
- // * a
217
- // * b
218
- // c
219
- firstElement = ListWalker.first( positionParent, { sameIndent: true, lowerIndent: true } );
220
- } else {
221
- firstElement = positionParent.previousSibling;
222
- }
223
- } else {
224
- // In case of the forward merge there is no case as above, just merge with next sibling.
225
- firstElement = positionParent;
226
- lastElement = positionParent.nextSibling;
227
- }
228
- } else {
229
- firstElement = selection.getFirstPosition().parent;
230
- lastElement = selection.getLastPosition().parent;
231
- }
232
-
233
- return { firstElement, lastElement };
234
- }
15
+ /**
16
+ * Creates an instance of the command.
17
+ *
18
+ * @param editor The editor instance.
19
+ * @param direction Whether list item should be merged before or after the selected block.
20
+ */
21
+ constructor(editor, direction) {
22
+ super(editor);
23
+ this._direction = direction;
24
+ }
25
+ /**
26
+ * @inheritDoc
27
+ */
28
+ refresh() {
29
+ this.isEnabled = this._checkEnabled();
30
+ }
31
+ /**
32
+ * Merges list blocks together (depending on the {@link #constructor}'s `direction` parameter).
33
+ *
34
+ * @fires execute
35
+ * @fires afterExecute
36
+ * @param options Command options.
37
+ * @param options.shouldMergeOnBlocksContentLevel When set `true`, merging will be performed together
38
+ * with {@link module:engine/model/model~Model#deleteContent} to get rid of the inline content in the selection or take advantage
39
+ * of the heuristics in `deleteContent()` that helps convert lists into paragraphs in certain cases.
40
+ */
41
+ execute({ shouldMergeOnBlocksContentLevel = false } = {}) {
42
+ const model = this.editor.model;
43
+ const selection = model.document.selection;
44
+ const changedBlocks = [];
45
+ model.change(writer => {
46
+ const { firstElement, lastElement } = this._getMergeSubjectElements(selection, shouldMergeOnBlocksContentLevel);
47
+ const firstIndent = firstElement.getAttribute('listIndent') || 0;
48
+ const lastIndent = lastElement.getAttribute('listIndent');
49
+ const lastElementId = lastElement.getAttribute('listItemId');
50
+ if (firstIndent != lastIndent) {
51
+ const nestedLastElementBlocks = getNestedListBlocks(lastElement);
52
+ changedBlocks.push(...indentBlocks([lastElement, ...nestedLastElementBlocks], writer, {
53
+ indentBy: firstIndent - lastIndent,
54
+ // If outdenting, the entire sub-tree that follows must be included.
55
+ expand: firstIndent < lastIndent
56
+ }));
57
+ }
58
+ if (shouldMergeOnBlocksContentLevel) {
59
+ let sel = selection;
60
+ if (selection.isCollapsed) {
61
+ sel = writer.createSelection(writer.createRange(writer.createPositionAt(firstElement, 'end'), writer.createPositionAt(lastElement, 0)));
62
+ }
63
+ // Delete selected content. Replace entire content only for non-collapsed selection.
64
+ model.deleteContent(sel, { doNotResetEntireContent: selection.isCollapsed });
65
+ // Get the last "touched" element after deleteContent call (can't use the lastElement because
66
+ // it could get merged into the firstElement while deleting content).
67
+ const lastElementAfterDelete = sel.getLastPosition().parent;
68
+ // Check if the element after it was in the same list item and adjust it if needed.
69
+ const nextSibling = lastElementAfterDelete.nextSibling;
70
+ changedBlocks.push(lastElementAfterDelete);
71
+ if (nextSibling && nextSibling !== lastElement && nextSibling.getAttribute('listItemId') == lastElementId) {
72
+ changedBlocks.push(...mergeListItemBefore(nextSibling, lastElementAfterDelete, writer));
73
+ }
74
+ }
75
+ else {
76
+ changedBlocks.push(...mergeListItemBefore(lastElement, firstElement, writer));
77
+ }
78
+ this._fireAfterExecute(changedBlocks);
79
+ });
80
+ }
81
+ /**
82
+ * Fires the `afterExecute` event.
83
+ *
84
+ * @param changedBlocks The changed list elements.
85
+ */
86
+ _fireAfterExecute(changedBlocks) {
87
+ this.fire('afterExecute', sortBlocks(new Set(changedBlocks)));
88
+ }
89
+ /**
90
+ * Checks whether the command can be enabled in the current context.
91
+ *
92
+ * @returns Whether the command should be enabled.
93
+ */
94
+ _checkEnabled() {
95
+ const model = this.editor.model;
96
+ const selection = model.document.selection;
97
+ const selectedBlockObject = getSelectedBlockObject(model);
98
+ if (selection.isCollapsed || selectedBlockObject) {
99
+ const positionParent = selectedBlockObject || selection.getFirstPosition().parent;
100
+ if (!isListItemBlock(positionParent)) {
101
+ return false;
102
+ }
103
+ const siblingNode = this._direction == 'backward' ?
104
+ positionParent.previousSibling :
105
+ positionParent.nextSibling;
106
+ if (!siblingNode) {
107
+ return false;
108
+ }
109
+ if (isSingleListItem([positionParent, siblingNode])) {
110
+ return false;
111
+ }
112
+ }
113
+ else {
114
+ const lastPosition = selection.getLastPosition();
115
+ const firstPosition = selection.getFirstPosition();
116
+ // If deleting within a single block of a list item, there's no need to merge anything.
117
+ // The default delete should be executed instead.
118
+ if (lastPosition.parent === firstPosition.parent) {
119
+ return false;
120
+ }
121
+ if (!isListItemBlock(lastPosition.parent)) {
122
+ return false;
123
+ }
124
+ }
125
+ return true;
126
+ }
127
+ /**
128
+ * Returns the boundary elements the merge should be executed for. These are not necessarily selection's first
129
+ * and last position parents but sometimes sibling or even further blocks depending on the context.
130
+ *
131
+ * @param selection The selection the merge is executed for.
132
+ * @param shouldMergeOnBlocksContentLevel When `true`, merge is performed together with
133
+ * {@link module:engine/model/model~Model#deleteContent} to remove the inline content within the selection.
134
+ */
135
+ _getMergeSubjectElements(selection, shouldMergeOnBlocksContentLevel) {
136
+ const model = this.editor.model;
137
+ const selectedBlockObject = getSelectedBlockObject(model);
138
+ let firstElement, lastElement;
139
+ if (selection.isCollapsed || selectedBlockObject) {
140
+ const positionParent = selectedBlockObject || selection.getFirstPosition().parent;
141
+ const isFirstBlock = isFirstBlockOfListItem(positionParent);
142
+ if (this._direction == 'backward') {
143
+ lastElement = positionParent;
144
+ if (isFirstBlock && !shouldMergeOnBlocksContentLevel) {
145
+ // For the "c" as an anchorElement:
146
+ // * a
147
+ // * b
148
+ // * [c] <-- this block should be merged with "a"
149
+ // It should find "a" element to merge with:
150
+ // * a
151
+ // * b
152
+ // c
153
+ firstElement = ListWalker.first(positionParent, { sameIndent: true, lowerIndent: true });
154
+ }
155
+ else {
156
+ firstElement = positionParent.previousSibling;
157
+ }
158
+ }
159
+ else {
160
+ // In case of the forward merge there is no case as above, just merge with next sibling.
161
+ firstElement = positionParent;
162
+ lastElement = positionParent.nextSibling;
163
+ }
164
+ }
165
+ else {
166
+ firstElement = selection.getFirstPosition().parent;
167
+ lastElement = selection.getLastPosition().parent;
168
+ }
169
+ return {
170
+ firstElement: firstElement,
171
+ lastElement: lastElement
172
+ };
173
+ }
235
174
  }
@@ -1,114 +1,70 @@
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
- /**
7
- * @module list/documentlist/documentlistsplitcommand
8
- */
9
-
10
5
  import { Command } from 'ckeditor5/src/core';
11
- import {
12
- isFirstBlockOfListItem,
13
- isListItemBlock,
14
- sortBlocks,
15
- splitListItemBefore
16
- } from './utils/model';
17
-
6
+ import { isFirstBlockOfListItem, isListItemBlock, sortBlocks, splitListItemBefore } from './utils/model';
18
7
  /**
19
8
  * The document list split command that splits the list item at the selection.
20
9
  *
21
10
  * It is used by the {@link module:list/documentlist~DocumentList document list feature}.
22
- *
23
- * @extends module:core/command~Command
24
11
  */
25
12
  export default class DocumentListSplitCommand extends Command {
26
- /**
27
- * Creates an instance of the command.
28
- *
29
- * @param {module:core/editor/editor~Editor} editor The editor instance.
30
- * @param {'before'|'after'} direction Whether list item should be split before or after the selected block.
31
- */
32
- constructor( editor, direction ) {
33
- super( editor );
34
-
35
- /**
36
- * Whether list item should be split before or after the selected block.
37
- *
38
- * @readonly
39
- * @private
40
- * @member {'before'|'after'}
41
- */
42
- this._direction = direction;
43
- }
44
-
45
- /**
46
- * @inheritDoc
47
- */
48
- refresh() {
49
- this.isEnabled = this._checkEnabled();
50
- }
51
-
52
- /**
53
- * Splits the list item at the selection.
54
- *
55
- * @fires execute
56
- * @fires afterExecute
57
- */
58
- execute() {
59
- const editor = this.editor;
60
-
61
- editor.model.change( writer => {
62
- const changedBlocks = splitListItemBefore( this._getStartBlock(), writer );
63
-
64
- this._fireAfterExecute( changedBlocks );
65
- } );
66
- }
67
-
68
- /**
69
- * Fires the `afterExecute` event.
70
- *
71
- * @private
72
- * @param {Array.<module:engine/model/element~Element>} changedBlocks The changed list elements.
73
- */
74
- _fireAfterExecute( changedBlocks ) {
75
- /**
76
- * Event fired by the {@link #execute} method.
77
- *
78
- * It allows to execute an action after executing the {@link ~DocumentListSplitCommand#execute} method,
79
- * for example adjusting attributes of changed list items.
80
- *
81
- * @protected
82
- * @event afterExecute
83
- */
84
- this.fire( 'afterExecute', sortBlocks( new Set( changedBlocks ) ) );
85
- }
86
-
87
- /**
88
- * Checks whether the command can be enabled in the current context.
89
- *
90
- * @private
91
- * @returns {Boolean} Whether the command should be enabled.
92
- */
93
- _checkEnabled() {
94
- const selection = this.editor.model.document.selection;
95
- const block = this._getStartBlock();
96
-
97
- return selection.isCollapsed &&
98
- isListItemBlock( block ) &&
99
- !isFirstBlockOfListItem( block );
100
- }
101
-
102
- /**
103
- * Returns the model element that is the main focus of the command (according to the current selection and command direction).
104
- *
105
- * @private
106
- * @returns {module:engine/model/element~Element}
107
- */
108
- _getStartBlock() {
109
- const doc = this.editor.model.document;
110
- const positionParent = doc.selection.getFirstPosition().parent;
111
-
112
- return this._direction == 'before' ? positionParent : positionParent.nextSibling;
113
- }
13
+ /**
14
+ * Creates an instance of the command.
15
+ *
16
+ * @param editor The editor instance.
17
+ * @param direction Whether list item should be split before or after the selected block.
18
+ */
19
+ constructor(editor, direction) {
20
+ super(editor);
21
+ this._direction = direction;
22
+ }
23
+ /**
24
+ * @inheritDoc
25
+ */
26
+ refresh() {
27
+ this.isEnabled = this._checkEnabled();
28
+ }
29
+ /**
30
+ * Splits the list item at the selection.
31
+ *
32
+ * @fires execute
33
+ * @fires afterExecute
34
+ */
35
+ execute() {
36
+ const editor = this.editor;
37
+ editor.model.change(writer => {
38
+ const changedBlocks = splitListItemBefore(this._getStartBlock(), writer);
39
+ this._fireAfterExecute(changedBlocks);
40
+ });
41
+ }
42
+ /**
43
+ * Fires the `afterExecute` event.
44
+ *
45
+ * @param changedBlocks The changed list elements.
46
+ */
47
+ _fireAfterExecute(changedBlocks) {
48
+ this.fire('afterExecute', sortBlocks(new Set(changedBlocks)));
49
+ }
50
+ /**
51
+ * Checks whether the command can be enabled in the current context.
52
+ *
53
+ * @returns Whether the command should be enabled.
54
+ */
55
+ _checkEnabled() {
56
+ const selection = this.editor.model.document.selection;
57
+ const block = this._getStartBlock();
58
+ return selection.isCollapsed &&
59
+ isListItemBlock(block) &&
60
+ !isFirstBlockOfListItem(block);
61
+ }
62
+ /**
63
+ * Returns the model element that is the main focus of the command (according to the current selection and command direction).
64
+ */
65
+ _getStartBlock() {
66
+ const doc = this.editor.model.document;
67
+ const positionParent = doc.selection.getFirstPosition().parent;
68
+ return (this._direction == 'before' ? positionParent : positionParent.nextSibling);
69
+ }
114
70
  }