@ckeditor/ckeditor5-list 40.1.0 → 41.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.
- package/CHANGELOG.md +50 -50
- package/LICENSE.md +1 -1
- package/build/list.js +2 -2
- package/build/translations/ug.js +1 -1
- package/ckeditor5-metadata.json +34 -34
- package/lang/translations/ar.po +1 -1
- package/lang/translations/ast.po +1 -1
- package/lang/translations/az.po +1 -1
- package/lang/translations/bg.po +1 -1
- package/lang/translations/bn.po +1 -1
- package/lang/translations/ca.po +1 -1
- package/lang/translations/cs.po +1 -1
- package/lang/translations/da.po +1 -1
- package/lang/translations/de-ch.po +1 -1
- package/lang/translations/de.po +1 -1
- package/lang/translations/el.po +1 -1
- package/lang/translations/en-au.po +1 -1
- package/lang/translations/en-gb.po +1 -1
- package/lang/translations/en.po +1 -1
- package/lang/translations/eo.po +1 -1
- package/lang/translations/es.po +1 -1
- package/lang/translations/et.po +1 -1
- package/lang/translations/eu.po +1 -1
- package/lang/translations/fa.po +1 -1
- package/lang/translations/fi.po +1 -1
- package/lang/translations/fr.po +1 -1
- package/lang/translations/gl.po +1 -1
- package/lang/translations/he.po +1 -1
- package/lang/translations/hi.po +1 -1
- package/lang/translations/hr.po +1 -1
- package/lang/translations/hu.po +1 -1
- package/lang/translations/id.po +1 -1
- package/lang/translations/it.po +1 -1
- package/lang/translations/ja.po +1 -1
- package/lang/translations/jv.po +1 -1
- package/lang/translations/km.po +1 -1
- package/lang/translations/kn.po +1 -1
- package/lang/translations/ko.po +1 -1
- package/lang/translations/ku.po +1 -1
- package/lang/translations/lt.po +1 -1
- package/lang/translations/lv.po +1 -1
- package/lang/translations/ms.po +1 -1
- package/lang/translations/nb.po +1 -1
- package/lang/translations/ne.po +1 -1
- package/lang/translations/nl.po +1 -1
- package/lang/translations/no.po +1 -1
- package/lang/translations/pl.po +1 -1
- package/lang/translations/pt-br.po +1 -1
- package/lang/translations/pt.po +1 -1
- package/lang/translations/ro.po +1 -1
- package/lang/translations/ru.po +1 -1
- package/lang/translations/si.po +1 -1
- package/lang/translations/sk.po +1 -1
- package/lang/translations/sq.po +1 -1
- package/lang/translations/sr-latn.po +1 -1
- package/lang/translations/sr.po +1 -1
- package/lang/translations/sv.po +1 -1
- package/lang/translations/th.po +1 -1
- package/lang/translations/tk.po +1 -1
- package/lang/translations/tr.po +1 -1
- package/lang/translations/tt.po +1 -1
- package/lang/translations/ug.po +11 -11
- package/lang/translations/uk.po +1 -1
- package/lang/translations/ur.po +1 -1
- package/lang/translations/uz.po +1 -1
- package/lang/translations/vi.po +1 -1
- package/lang/translations/zh-cn.po +1 -1
- package/lang/translations/zh.po +1 -1
- package/package.json +3 -3
- package/src/augmentation.d.ts +29 -28
- package/src/augmentation.js +1 -1
- package/src/documentlist.d.ts +9 -7
- package/src/documentlist.js +18 -7
- package/src/documentlistproperties.d.ts +9 -8
- package/src/documentlistproperties.js +18 -8
- package/src/index.d.ts +39 -37
- package/src/index.js +32 -23
- package/src/legacylist/legacyconverters.d.ts +196 -0
- package/src/legacylist/legacyconverters.js +905 -0
- package/src/{list/indentcommand.d.ts → legacylist/legacyindentcommand.d.ts} +4 -4
- package/src/{list/indentcommand.js → legacylist/legacyindentcommand.js} +5 -5
- package/src/{documentlist/documentlistcommand.d.ts → legacylist/legacylistcommand.d.ts} +5 -30
- package/src/legacylist/legacylistcommand.js +274 -0
- package/src/legacylist/legacylistediting.d.ts +32 -0
- package/src/legacylist/legacylistediting.js +161 -0
- package/src/legacylist/legacylistutils.d.ts +41 -0
- package/src/legacylist/legacylistutils.js +46 -0
- package/src/legacylist/legacyutils.d.ts +101 -0
- package/src/legacylist/legacyutils.js +347 -0
- package/src/legacylist.d.ts +26 -0
- package/src/legacylist.js +30 -0
- package/src/legacylistproperties/legacylistpropertiesediting.d.ts +72 -0
- package/src/legacylistproperties/legacylistpropertiesediting.js +696 -0
- package/src/legacylistproperties/legacylistreversedcommand.d.ts +38 -0
- package/src/legacylistproperties/legacylistreversedcommand.js +52 -0
- package/src/{documentlistproperties/documentliststartcommand.d.ts → legacylistproperties/legacyliststartcommand.d.ts} +6 -7
- package/src/legacylistproperties/legacyliststartcommand.js +51 -0
- package/src/{documentlistproperties/documentliststylecommand.d.ts → legacylistproperties/legacyliststylecommand.d.ts} +14 -19
- package/src/{documentlistproperties/documentliststylecommand.js → legacylistproperties/legacyliststylecommand.js} +22 -36
- package/src/legacylistproperties.d.ts +27 -0
- package/src/legacylistproperties.js +31 -0
- package/src/{tododocumentlist/checktododocumentlistcommand.d.ts → legacytodolist/legacychecktodolistcommand.d.ts} +17 -14
- package/src/{tododocumentlist/checktododocumentlistcommand.js → legacytodolist/legacychecktodolistcommand.js} +34 -40
- package/src/{todolist/todolistconverters.d.ts → legacytodolist/legacytodolistconverters.d.ts} +9 -8
- package/src/{todolist/todolistconverters.js → legacytodolist/legacytodolistconverters.js} +6 -5
- package/src/{tododocumentlist/tododocumentlistediting.d.ts → legacytodolist/legacytodolistediting.d.ts} +9 -8
- package/src/legacytodolist/legacytodolistediting.js +161 -0
- package/src/legacytodolist.d.ts +27 -0
- package/src/legacytodolist.js +31 -0
- package/src/{documentlist → list}/adjacentlistssupport.d.ts +2 -2
- package/src/{documentlist → list}/adjacentlistssupport.js +9 -9
- package/src/list/converters.d.ts +41 -172
- package/src/list/converters.js +357 -821
- package/src/list/listcommand.d.ts +28 -3
- package/src/list/listcommand.js +81 -205
- package/src/list/listediting.d.ts +189 -9
- package/src/list/listediting.js +592 -107
- package/src/{documentlist/documentlistindentcommand.d.ts → list/listindentcommand.d.ts} +10 -10
- package/src/{documentlist/documentlistindentcommand.js → list/listindentcommand.js} +7 -7
- package/src/{documentlist/documentlistmergecommand.d.ts → list/listmergecommand.d.ts} +10 -10
- package/src/{documentlist/documentlistmergecommand.js → list/listmergecommand.js} +7 -7
- package/src/{documentlist/documentlistsplitcommand.d.ts → list/listsplitcommand.d.ts} +10 -10
- package/src/{documentlist/documentlistsplitcommand.js → list/listsplitcommand.js} +5 -5
- package/src/list/listui.d.ts +2 -2
- package/src/list/listui.js +5 -7
- package/src/list/listutils.d.ts +22 -17
- package/src/list/listutils.js +24 -20
- package/src/{documentlist → list}/utils/listwalker.d.ts +5 -5
- package/src/{documentlist → list}/utils/listwalker.js +4 -4
- package/src/{documentlist → list}/utils/model.d.ts +4 -4
- package/src/{documentlist → list}/utils/model.js +3 -3
- package/src/{documentlist → list}/utils/postfixers.d.ts +5 -5
- package/src/{documentlist → list}/utils/postfixers.js +3 -3
- package/src/{documentlist → list}/utils/view.d.ts +3 -3
- package/src/{documentlist → list}/utils/view.js +1 -1
- package/src/list/utils.d.ts +2 -96
- package/src/list/utils.js +2 -342
- package/src/list.d.ts +6 -6
- package/src/list.js +6 -6
- package/src/listconfig.d.ts +10 -10
- package/src/listconfig.js +1 -1
- package/src/{documentlistproperties → listproperties}/converters.d.ts +5 -5
- package/src/{documentlistproperties → listproperties}/converters.js +1 -1
- package/src/listproperties/listpropertiesediting.d.ts +56 -40
- package/src/listproperties/listpropertiesediting.js +145 -575
- package/src/listproperties/listpropertiesui.d.ts +2 -2
- package/src/listproperties/listpropertiesui.js +6 -8
- package/src/{documentlistproperties/documentlistpropertiesutils.d.ts → listproperties/listpropertiesutils.d.ts} +5 -5
- package/src/{documentlistproperties/documentlistpropertiesutils.js → listproperties/listpropertiesutils.js} +6 -6
- package/src/listproperties/listreversedcommand.d.ts +4 -6
- package/src/listproperties/listreversedcommand.js +17 -14
- package/src/listproperties/liststartcommand.d.ts +4 -3
- package/src/listproperties/liststartcommand.js +17 -11
- package/src/listproperties/liststylecommand.d.ts +16 -11
- package/src/listproperties/liststylecommand.js +33 -19
- package/src/listproperties/ui/listpropertiesview.d.ts +5 -6
- package/src/listproperties/ui/listpropertiesview.js +3 -4
- package/src/{documentlistproperties → listproperties}/utils/style.d.ts +1 -1
- package/src/{documentlistproperties → listproperties}/utils/style.js +2 -2
- package/src/listproperties.d.ts +6 -5
- package/src/listproperties.js +6 -5
- package/src/tododocumentlist.d.ts +9 -8
- package/src/tododocumentlist.js +18 -8
- package/src/todolist/checktodolistcommand.d.ts +11 -14
- package/src/todolist/checktodolistcommand.js +37 -31
- package/src/{tododocumentlist → todolist}/todocheckboxchangeobserver.d.ts +6 -6
- package/src/{tododocumentlist → todolist}/todocheckboxchangeobserver.js +3 -3
- package/src/todolist/todolistediting.d.ts +5 -6
- package/src/todolist/todolistediting.js +314 -76
- package/src/todolist/todolistui.d.ts +2 -2
- package/src/todolist/todolistui.js +4 -5
- package/src/todolist.d.ts +6 -6
- package/src/todolist.js +6 -6
- package/theme/documentlist.css +1 -1
- package/theme/list.css +1 -1
- package/theme/listproperties.css +1 -1
- package/theme/liststyles.css +1 -1
- package/theme/todolist.css +1 -1
- package/src/documentlist/converters.d.ts +0 -65
- package/src/documentlist/converters.js +0 -441
- package/src/documentlist/documentlistcommand.js +0 -150
- package/src/documentlist/documentlistediting.d.ts +0 -212
- package/src/documentlist/documentlistediting.js +0 -646
- package/src/documentlist/documentlistutils.d.ts +0 -46
- package/src/documentlist/documentlistutils.js +0 -50
- package/src/documentlistproperties/documentlistpropertiesediting.d.ts +0 -88
- package/src/documentlistproperties/documentlistpropertiesediting.js +0 -266
- package/src/documentlistproperties/documentlistreversedcommand.d.ts +0 -36
- package/src/documentlistproperties/documentlistreversedcommand.js +0 -55
- package/src/documentlistproperties/documentliststartcommand.js +0 -57
- package/src/listproperties/ui/collapsibleview.d.ts +0 -63
- package/src/listproperties/ui/collapsibleview.js +0 -89
- package/src/liststyle.d.ts +0 -28
- package/src/liststyle.js +0 -36
- package/src/tododocumentlist/tododocumentlistediting.js +0 -399
- package/theme/collapsible.css +0 -10
- package/theme/icons/bulletedlist.svg +0 -1
- package/theme/icons/numberedlist.svg +0 -1
- package/theme/icons/todolist.svg +0 -1
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2024, 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
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @module list/list/listcommand
|
|
7
|
+
*/
|
|
8
|
+
import type { Element } from 'ckeditor5/src/engine.js';
|
|
9
|
+
import { Command, type Editor } from 'ckeditor5/src/core.js';
|
|
6
10
|
/**
|
|
7
11
|
* The list command. It is used by the {@link module:list/list~List list feature}.
|
|
8
12
|
*/
|
|
@@ -14,6 +18,7 @@ export default class ListCommand extends Command {
|
|
|
14
18
|
/**
|
|
15
19
|
* A flag indicating whether the command is active, which means that the selection starts in a list of the same type.
|
|
16
20
|
*
|
|
21
|
+
* @observable
|
|
17
22
|
* @readonly
|
|
18
23
|
*/
|
|
19
24
|
value: boolean;
|
|
@@ -32,14 +37,21 @@ export default class ListCommand extends Command {
|
|
|
32
37
|
* Executes the list command.
|
|
33
38
|
*
|
|
34
39
|
* @fires execute
|
|
40
|
+
* @fires afterExecute
|
|
35
41
|
* @param options Command options.
|
|
36
42
|
* @param options.forceValue If set, it will force the command behavior. If `true`, the command will try to convert the
|
|
37
|
-
* selected items and potentially the neighbor elements to the proper list items. If set to `false
|
|
43
|
+
* selected items and potentially the neighbor elements to the proper list items. If set to `false` it will convert selected elements
|
|
38
44
|
* to paragraphs. If not set, the command will toggle selected elements to list items or paragraphs, depending on the selection.
|
|
39
45
|
*/
|
|
40
46
|
execute(options?: {
|
|
41
47
|
forceValue?: boolean;
|
|
42
48
|
}): void;
|
|
49
|
+
/**
|
|
50
|
+
* Fires the `afterExecute` event.
|
|
51
|
+
*
|
|
52
|
+
* @param changedBlocks The changed list elements.
|
|
53
|
+
*/
|
|
54
|
+
private _fireAfterExecute;
|
|
43
55
|
/**
|
|
44
56
|
* Checks the command's {@link #value}.
|
|
45
57
|
*
|
|
@@ -53,3 +65,16 @@ export default class ListCommand extends Command {
|
|
|
53
65
|
*/
|
|
54
66
|
private _checkEnabled;
|
|
55
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Event fired by the {@link ~ListCommand#execute} method.
|
|
70
|
+
*
|
|
71
|
+
* It allows to execute an action after executing the {@link ~ListCommand#execute} method,
|
|
72
|
+
* for example adjusting attributes of changed list items.
|
|
73
|
+
*
|
|
74
|
+
* @internal
|
|
75
|
+
* @eventName ~ListCommand#afterExecute
|
|
76
|
+
*/
|
|
77
|
+
export type ListCommandAfterExecuteEvent = {
|
|
78
|
+
name: 'afterExecute';
|
|
79
|
+
args: [changedBlocks: Array<Element>];
|
|
80
|
+
};
|
package/src/list/listcommand.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2024, 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
|
-
import { Command } from 'ckeditor5/src/core';
|
|
6
|
-
import {
|
|
5
|
+
import { Command } from 'ckeditor5/src/core.js';
|
|
6
|
+
import { splitListItemBefore, expandListBlocksToCompleteItems, getListItemBlocks, getListItems, removeListAttributes, outdentFollowingItems, ListItemUid, sortBlocks, getSelectedBlockObject, isListItemBlock, canBecomeSimpleListItem } from './utils/model.js';
|
|
7
7
|
/**
|
|
8
8
|
* The list command. It is used by the {@link module:list/list~List list feature}.
|
|
9
9
|
*/
|
|
@@ -29,175 +29,99 @@ export default class ListCommand extends Command {
|
|
|
29
29
|
* Executes the list command.
|
|
30
30
|
*
|
|
31
31
|
* @fires execute
|
|
32
|
+
* @fires afterExecute
|
|
32
33
|
* @param options Command options.
|
|
33
34
|
* @param options.forceValue If set, it will force the command behavior. If `true`, the command will try to convert the
|
|
34
|
-
* selected items and potentially the neighbor elements to the proper list items. If set to `false
|
|
35
|
+
* selected items and potentially the neighbor elements to the proper list items. If set to `false` it will convert selected elements
|
|
35
36
|
* to paragraphs. If not set, the command will toggle selected elements to list items or paragraphs, depending on the selection.
|
|
36
37
|
*/
|
|
37
38
|
execute(options = {}) {
|
|
38
39
|
const model = this.editor.model;
|
|
39
40
|
const document = model.document;
|
|
41
|
+
const selectedBlockObject = getSelectedBlockObject(model);
|
|
40
42
|
const blocks = Array.from(document.selection.getSelectedBlocks())
|
|
41
|
-
.filter(block =>
|
|
43
|
+
.filter(block => model.schema.checkAttribute(block, 'listType') || canBecomeSimpleListItem(block, model.schema));
|
|
42
44
|
// Whether we are turning off some items.
|
|
43
45
|
const turnOff = options.forceValue !== undefined ? !options.forceValue : this.value;
|
|
44
|
-
// If we are turning off items, we are going to rename them to paragraphs.
|
|
45
46
|
model.change(writer => {
|
|
46
|
-
// If part of a list got turned off, we need to handle (outdent) all of sub-items of the last turned-off item.
|
|
47
|
-
// To be sure that model is all the time in a good state, we first fix items below turned-off item.
|
|
48
47
|
if (turnOff) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// 1. All direct sub-items of turned-off item should become indent 0, because the first item after it
|
|
56
|
-
// will be the first item of a new list. Other items are at the same level, so should have same 0 index.
|
|
57
|
-
// 2. All items with indent lower than indent of turned-off item should become indent 0, because they
|
|
58
|
-
// should not end up as a child of any of list items that they were not children of before.
|
|
59
|
-
// 3. All other items should have their indent changed relatively to it's parent.
|
|
60
|
-
//
|
|
61
|
-
// For example:
|
|
62
|
-
// 1 * --------
|
|
63
|
-
// 2 * --------
|
|
64
|
-
// 3 * -------- <-- this is turned off.
|
|
65
|
-
// 4 * -------- <-- this has to become indent = 0, because it will be first item on a new list.
|
|
66
|
-
// 5 * -------- <-- this should be still be a child of item above, so indent = 1.
|
|
67
|
-
// 6 * -------- <-- this has to become indent = 0, because it should not be a child of any of items above.
|
|
68
|
-
// 7 * -------- <-- this should be still be a child of item above, so indent = 1.
|
|
69
|
-
// 8 * -------- <-- this has to become indent = 0.
|
|
70
|
-
// 9 * -------- <-- this should still be a child of item above, so indent = 1.
|
|
71
|
-
// 10 * -------- <-- this should still be a child of item above, so indent = 2.
|
|
72
|
-
// 11 * -------- <-- this should still be at the same level as item above, so indent = 2.
|
|
73
|
-
// 12 * -------- <-- this and all below are left unchanged.
|
|
74
|
-
// 13 * --------
|
|
75
|
-
// 14 * --------
|
|
76
|
-
//
|
|
77
|
-
// After turning off 3 the list becomes:
|
|
78
|
-
//
|
|
79
|
-
// 1 * --------
|
|
80
|
-
// 2 * --------
|
|
81
|
-
//
|
|
82
|
-
// 3 --------
|
|
83
|
-
//
|
|
84
|
-
// 4 * --------
|
|
85
|
-
// 5 * --------
|
|
86
|
-
// 6 * --------
|
|
87
|
-
// 7 * --------
|
|
88
|
-
// 8 * --------
|
|
89
|
-
// 9 * --------
|
|
90
|
-
// 10 * --------
|
|
91
|
-
// 11 * --------
|
|
92
|
-
// 12 * --------
|
|
93
|
-
// 13 * --------
|
|
94
|
-
// 14 * --------
|
|
95
|
-
//
|
|
96
|
-
// Thanks to this algorithm no lists are mismatched and no items get unexpected children/parent, while
|
|
97
|
-
// those parent-child connection which are possible to maintain are still maintained. It's worth noting
|
|
98
|
-
// that this is the same effect that we would be get by multiple use of outdent command. However doing
|
|
99
|
-
// it like this is much more efficient because it's less operation (less memory usage, easier OT) and
|
|
100
|
-
// less conversion (faster).
|
|
101
|
-
while (next && next.name == 'listItem' && next.getAttribute('listIndent') !== 0) {
|
|
102
|
-
// Check each next list item, as long as its indent is bigger than 0.
|
|
103
|
-
// If the indent is 0 we are not going to change anything anyway.
|
|
104
|
-
const indent = next.getAttribute('listIndent');
|
|
105
|
-
// We check if that's item indent is lower as current relative indent.
|
|
106
|
-
if (indent < currentIndent) {
|
|
107
|
-
// If it is, current relative indent becomes that indent.
|
|
108
|
-
currentIndent = indent;
|
|
109
|
-
}
|
|
110
|
-
// Fix indent relatively to current relative indent.
|
|
111
|
-
// Note, that if we just changed the current relative indent, the newIndent will be equal to 0.
|
|
112
|
-
const newIndent = indent - currentIndent;
|
|
113
|
-
// Save the entry in changes array. We do not apply it at the moment, because we will need to
|
|
114
|
-
// reverse the changes so the last item is changed first.
|
|
115
|
-
// This is to keep model in correct state all the time.
|
|
116
|
-
changes.push({ element: next, listIndent: newIndent });
|
|
117
|
-
// Find next item.
|
|
118
|
-
next = next.nextSibling;
|
|
119
|
-
}
|
|
120
|
-
changes = changes.reverse();
|
|
121
|
-
for (const item of changes) {
|
|
122
|
-
writer.setAttribute('listIndent', item.listIndent, item.element);
|
|
48
|
+
const lastBlock = blocks[blocks.length - 1];
|
|
49
|
+
// Split the first block from the list item.
|
|
50
|
+
const itemBlocks = getListItemBlocks(lastBlock, { direction: 'forward' });
|
|
51
|
+
const changedBlocks = [];
|
|
52
|
+
if (itemBlocks.length > 1) {
|
|
53
|
+
changedBlocks.push(...splitListItemBefore(itemBlocks[1], writer));
|
|
123
54
|
}
|
|
55
|
+
// Strip list attributes.
|
|
56
|
+
changedBlocks.push(...removeListAttributes(blocks, writer));
|
|
57
|
+
// Outdent items following the selected list item.
|
|
58
|
+
changedBlocks.push(...outdentFollowingItems(lastBlock, writer));
|
|
59
|
+
this._fireAfterExecute(changedBlocks);
|
|
124
60
|
}
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
// * ------ <-- fix, because latter list item of this item's list is changed
|
|
131
|
-
// * ------ <-- do not fix, item is not affected (different list)
|
|
132
|
-
// * ------ <-- fix, because latter list item of this item's list is changed
|
|
133
|
-
// * ------ <-- fix, because latter list item of this item's list is changed
|
|
134
|
-
// * ---[-- <-- already in selection
|
|
135
|
-
// * ------ <-- already in selection
|
|
136
|
-
// * ------ <-- already in selection
|
|
137
|
-
// * ------ <-- already in selection, but does not cause other list items to change because is top-level
|
|
138
|
-
// * ---]-- <-- already in selection
|
|
139
|
-
// * ------ <-- fix, because preceding list item of this item's list is changed
|
|
140
|
-
// * ------ <-- do not fix, item is not affected (different list)
|
|
141
|
-
// * ------ <-- do not fix, top level item
|
|
142
|
-
if (!turnOff) {
|
|
143
|
-
// Find lowest indent among selected items. This will be indicator what is the indent of
|
|
144
|
-
// top-most list affected by the command.
|
|
145
|
-
let lowestIndent = Number.POSITIVE_INFINITY;
|
|
146
|
-
for (const item of blocks) {
|
|
147
|
-
if (item.is('element', 'listItem') && item.getAttribute('listIndent') < lowestIndent) {
|
|
148
|
-
lowestIndent = item.getAttribute('listIndent');
|
|
149
|
-
}
|
|
61
|
+
// Changing type of list items for a collapsed selection inside a list item.
|
|
62
|
+
else if ((selectedBlockObject || document.selection.isCollapsed) && isListItemBlock(blocks[0])) {
|
|
63
|
+
const changedBlocks = getListItems(selectedBlockObject || blocks[0]);
|
|
64
|
+
for (const block of changedBlocks) {
|
|
65
|
+
writer.setAttribute('listType', this.type, block);
|
|
150
66
|
}
|
|
151
|
-
|
|
152
|
-
lowestIndent = lowestIndent === 0 ? 1 : lowestIndent;
|
|
153
|
-
// Fix types of list items that are "before" the selected blocks.
|
|
154
|
-
_fixType(blocks, true, lowestIndent);
|
|
155
|
-
// Fix types of list items that are "after" the selected blocks.
|
|
156
|
-
_fixType(blocks, false, lowestIndent);
|
|
67
|
+
this._fireAfterExecute(changedBlocks);
|
|
157
68
|
}
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
69
|
+
// Turning on the list items for a non-collapsed selection.
|
|
70
|
+
else {
|
|
71
|
+
const changedBlocks = [];
|
|
72
|
+
for (const block of blocks) {
|
|
73
|
+
// Promote the given block to the list item.
|
|
74
|
+
if (!block.hasAttribute('listType')) {
|
|
75
|
+
// Rename block to a simple list item if this option is enabled.
|
|
76
|
+
if (!block.is('element', 'listItem') && canBecomeSimpleListItem(block, model.schema)) {
|
|
77
|
+
writer.rename(block, 'listItem');
|
|
78
|
+
}
|
|
79
|
+
writer.setAttributes({
|
|
80
|
+
listIndent: 0,
|
|
81
|
+
listItemId: ListItemUid.next(),
|
|
82
|
+
listType: this.type
|
|
83
|
+
}, block);
|
|
84
|
+
changedBlocks.push(block);
|
|
85
|
+
}
|
|
86
|
+
// Change the type of list item.
|
|
87
|
+
else {
|
|
88
|
+
for (const node of expandListBlocksToCompleteItems(block, { withNested: false })) {
|
|
89
|
+
if (node.getAttribute('listType') != this.type) {
|
|
90
|
+
writer.setAttribute('listType', this.type, node);
|
|
91
|
+
changedBlocks.push(node);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
178
95
|
}
|
|
96
|
+
this._fireAfterExecute(changedBlocks);
|
|
179
97
|
}
|
|
180
|
-
/**
|
|
181
|
-
* Event fired by the {@link #execute} method.
|
|
182
|
-
*
|
|
183
|
-
* It allows to execute an action after executing the {@link ~ListCommand#execute} method, for example adjusting
|
|
184
|
-
* attributes of changed blocks.
|
|
185
|
-
*
|
|
186
|
-
* @protected
|
|
187
|
-
* @event _executeCleanup
|
|
188
|
-
*/
|
|
189
|
-
this.fire('_executeCleanup', blocks);
|
|
190
98
|
});
|
|
191
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Fires the `afterExecute` event.
|
|
102
|
+
*
|
|
103
|
+
* @param changedBlocks The changed list elements.
|
|
104
|
+
*/
|
|
105
|
+
_fireAfterExecute(changedBlocks) {
|
|
106
|
+
this.fire('afterExecute', sortBlocks(new Set(changedBlocks)));
|
|
107
|
+
}
|
|
192
108
|
/**
|
|
193
109
|
* Checks the command's {@link #value}.
|
|
194
110
|
*
|
|
195
111
|
* @returns The current value.
|
|
196
112
|
*/
|
|
197
113
|
_getValue() {
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
|
|
114
|
+
const selection = this.editor.model.document.selection;
|
|
115
|
+
const blocks = Array.from(selection.getSelectedBlocks());
|
|
116
|
+
if (!blocks.length) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
for (const block of blocks) {
|
|
120
|
+
if (block.getAttribute('listType') != this.type) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
201
125
|
}
|
|
202
126
|
/**
|
|
203
127
|
* Checks whether the command can be enabled in the current context.
|
|
@@ -205,70 +129,22 @@ export default class ListCommand extends Command {
|
|
|
205
129
|
* @returns Whether the command should be enabled.
|
|
206
130
|
*/
|
|
207
131
|
_checkEnabled() {
|
|
132
|
+
const model = this.editor.model;
|
|
133
|
+
const schema = model.schema;
|
|
134
|
+
const selection = model.document.selection;
|
|
135
|
+
const blocks = Array.from(selection.getSelectedBlocks());
|
|
136
|
+
if (!blocks.length) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
208
139
|
// If command value is true it means that we are in list item, so the command should be enabled.
|
|
209
140
|
if (this.value) {
|
|
210
141
|
return true;
|
|
211
142
|
}
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (!firstBlock) {
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
// Otherwise, check if list item can be inserted at the position start.
|
|
219
|
-
return checkCanBecomeListItem(firstBlock, schema);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Helper function used when one or more list item have their type changed. Fixes type of other list items
|
|
224
|
-
* that are affected by the change (are in same lists) but are not directly in selection. The function got extracted
|
|
225
|
-
* not to duplicated code, as same fix has to be performed before and after selection.
|
|
226
|
-
*
|
|
227
|
-
* @param blocks Blocks that are in selection.
|
|
228
|
-
* @param isBackward Specified whether fix will be applied for blocks before first selected block (`true`)
|
|
229
|
-
* or blocks after last selected block (`false`).
|
|
230
|
-
* @param lowestIndent Lowest indent among selected blocks.
|
|
231
|
-
*/
|
|
232
|
-
function _fixType(blocks, isBackward, lowestIndent) {
|
|
233
|
-
// We need to check previous sibling of first changed item and next siblings of last changed item.
|
|
234
|
-
const startingItem = isBackward ? blocks[0] : blocks[blocks.length - 1];
|
|
235
|
-
if (startingItem.is('element', 'listItem')) {
|
|
236
|
-
let item = startingItem[isBackward ? 'previousSibling' : 'nextSibling'];
|
|
237
|
-
// During processing items, keeps the lowest indent of already processed items.
|
|
238
|
-
// This saves us from changing too many items.
|
|
239
|
-
// Following example is for going forward as it is easier to read, however same applies to going backward.
|
|
240
|
-
// * ------
|
|
241
|
-
// * ------
|
|
242
|
-
// * --[---
|
|
243
|
-
// * ------ <-- `lowestIndent` should be 1
|
|
244
|
-
// * --]--- <-- `startingItem`, `currentIndent` = 2, `lowestIndent` == 1
|
|
245
|
-
// * ------ <-- should be fixed, `indent` == 2 == `currentIndent`
|
|
246
|
-
// * ------ <-- should be fixed, set `currentIndent` to 1, `indent` == 1 == `currentIndent`
|
|
247
|
-
// * ------ <-- should not be fixed, item is in different list, `indent` = 2, `indent` != `currentIndent`
|
|
248
|
-
// * ------ <-- should be fixed, `indent` == 1 == `currentIndent`
|
|
249
|
-
// * ------ <-- break loop (`indent` < `lowestIndent`)
|
|
250
|
-
let currentIndent = startingItem.getAttribute('listIndent');
|
|
251
|
-
// Look back until a list item with indent lower than reference `lowestIndent`.
|
|
252
|
-
// That would be the parent of nested sublist which contains item having `lowestIndent`.
|
|
253
|
-
while (item && item.is('element', 'listItem') && item.getAttribute('listIndent') >= lowestIndent) {
|
|
254
|
-
if (currentIndent > item.getAttribute('listIndent')) {
|
|
255
|
-
currentIndent = item.getAttribute('listIndent');
|
|
256
|
-
}
|
|
257
|
-
// Found an item that is in the same nested sublist.
|
|
258
|
-
if (item.getAttribute('listIndent') == currentIndent) {
|
|
259
|
-
// Just add the item to selected blocks like it was selected by the user.
|
|
260
|
-
blocks[isBackward ? 'unshift' : 'push'](item);
|
|
143
|
+
for (const block of blocks) {
|
|
144
|
+
if (schema.checkAttribute(block, 'listType') || canBecomeSimpleListItem(block, schema)) {
|
|
145
|
+
return true;
|
|
261
146
|
}
|
|
262
|
-
item = item[isBackward ? 'previousSibling' : 'nextSibling'];
|
|
263
147
|
}
|
|
148
|
+
return false;
|
|
264
149
|
}
|
|
265
150
|
}
|
|
266
|
-
/**
|
|
267
|
-
* Checks whether the given block can be replaced by a listItem.
|
|
268
|
-
*
|
|
269
|
-
* @param block A block to be tested.
|
|
270
|
-
* @param schema The schema of the document.
|
|
271
|
-
*/
|
|
272
|
-
function checkCanBecomeListItem(block, schema) {
|
|
273
|
-
return schema.checkChild(block.parent, 'listItem') && !schema.isObject(block);
|
|
274
|
-
}
|
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
2
|
+
* @license Copyright (c) 2003-2024, 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
|
-
|
|
8
|
-
import {
|
|
5
|
+
/**
|
|
6
|
+
* @module list/list/listediting
|
|
7
|
+
*/
|
|
8
|
+
import { Plugin, type Editor } from 'ckeditor5/src/core.js';
|
|
9
|
+
import type { DowncastWriter, Element, ViewElement, ViewAttributeElement, Writer } from 'ckeditor5/src/engine.js';
|
|
10
|
+
import { Delete } from 'ckeditor5/src/typing.js';
|
|
11
|
+
import { Enter } from 'ckeditor5/src/enter.js';
|
|
12
|
+
import ListUtils from './listutils.js';
|
|
13
|
+
import { ListBlocksIterable } from './utils/listwalker.js';
|
|
14
|
+
import { ClipboardPipeline } from 'ckeditor5/src/clipboard.js';
|
|
15
|
+
import '../../theme/documentlist.css';
|
|
9
16
|
import '../../theme/list.css';
|
|
10
17
|
/**
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
* Map of model attributes applicable to list blocks.
|
|
19
|
+
*/
|
|
20
|
+
export interface ListItemAttributesMap {
|
|
21
|
+
listType?: 'numbered' | 'bulleted' | 'todo';
|
|
22
|
+
listIndent?: number;
|
|
23
|
+
listItemId?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The editing part of the document-list feature. It handles creating, editing and removing lists and list items.
|
|
14
27
|
*/
|
|
15
28
|
export default class ListEditing extends Plugin {
|
|
29
|
+
/**
|
|
30
|
+
* The list of registered downcast strategies.
|
|
31
|
+
*/
|
|
32
|
+
private readonly _downcastStrategies;
|
|
16
33
|
/**
|
|
17
34
|
* @inheritDoc
|
|
18
35
|
*/
|
|
@@ -20,7 +37,11 @@ export default class ListEditing extends Plugin {
|
|
|
20
37
|
/**
|
|
21
38
|
* @inheritDoc
|
|
22
39
|
*/
|
|
23
|
-
static get requires(): readonly [typeof Enter, typeof Delete, typeof ListUtils];
|
|
40
|
+
static get requires(): readonly [typeof Enter, typeof Delete, typeof ListUtils, typeof ClipboardPipeline];
|
|
41
|
+
/**
|
|
42
|
+
* @inheritDoc
|
|
43
|
+
*/
|
|
44
|
+
constructor(editor: Editor);
|
|
24
45
|
/**
|
|
25
46
|
* @inheritDoc
|
|
26
47
|
*/
|
|
@@ -29,4 +50,163 @@ export default class ListEditing extends Plugin {
|
|
|
29
50
|
* @inheritDoc
|
|
30
51
|
*/
|
|
31
52
|
afterInit(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Registers a downcast strategy.
|
|
55
|
+
*
|
|
56
|
+
* **Note**: Strategies must be registered in the `Plugin#init()` phase so that it can be applied
|
|
57
|
+
* in the `ListEditing#afterInit()`.
|
|
58
|
+
*
|
|
59
|
+
* @param strategy The downcast strategy to register.
|
|
60
|
+
*/
|
|
61
|
+
registerDowncastStrategy(strategy: DowncastStrategy): void;
|
|
62
|
+
/**
|
|
63
|
+
* Returns list of model attribute names that should affect downcast conversion.
|
|
64
|
+
*/
|
|
65
|
+
getListAttributeNames(): Array<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Attaches the listener to the {@link module:engine/view/document~Document#event:delete} event and handles backspace/delete
|
|
68
|
+
* keys in and around document lists.
|
|
69
|
+
*/
|
|
70
|
+
private _setupDeleteIntegration;
|
|
71
|
+
/**
|
|
72
|
+
* Attaches a listener to the {@link module:engine/view/document~Document#event:enter} event and handles enter key press
|
|
73
|
+
* in document lists.
|
|
74
|
+
*/
|
|
75
|
+
private _setupEnterIntegration;
|
|
76
|
+
/**
|
|
77
|
+
* Attaches a listener to the {@link module:engine/view/document~Document#event:tab} event and handles tab key and tab+shift keys
|
|
78
|
+
* presses in document lists.
|
|
79
|
+
*/
|
|
80
|
+
private _setupTabIntegration;
|
|
81
|
+
/**
|
|
82
|
+
* Registers the conversion helpers for the document-list feature.
|
|
83
|
+
*/
|
|
84
|
+
private _setupConversion;
|
|
85
|
+
/**
|
|
86
|
+
* Registers model post-fixers.
|
|
87
|
+
*/
|
|
88
|
+
private _setupModelPostFixing;
|
|
89
|
+
/**
|
|
90
|
+
* Integrates the feature with the clipboard via {@link module:engine/model/model~Model#insertContent} and
|
|
91
|
+
* {@link module:engine/model/model~Model#getSelectedContent}.
|
|
92
|
+
*/
|
|
93
|
+
private _setupClipboardIntegration;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The attribute to attribute downcast strategy for UL, OL, LI elements.
|
|
97
|
+
*/
|
|
98
|
+
export interface AttributeDowncastStrategy {
|
|
99
|
+
/**
|
|
100
|
+
* The scope of the downcast (whether it applies to LI or OL/UL).
|
|
101
|
+
*/
|
|
102
|
+
scope: 'list' | 'item';
|
|
103
|
+
/**
|
|
104
|
+
* The model attribute name.
|
|
105
|
+
*/
|
|
106
|
+
attributeName: string;
|
|
107
|
+
/**
|
|
108
|
+
* Sets the property on the view element.
|
|
109
|
+
*/
|
|
110
|
+
setAttributeOnDowncast(writer: DowncastWriter, value: unknown, element: ViewElement): void;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The custom marker downcast strategy.
|
|
114
|
+
*/
|
|
115
|
+
export interface ItemMarkerDowncastStrategy {
|
|
116
|
+
/**
|
|
117
|
+
* The scope of the downcast.
|
|
118
|
+
*/
|
|
119
|
+
scope: 'itemMarker';
|
|
120
|
+
/**
|
|
121
|
+
* The model attribute name.
|
|
122
|
+
*/
|
|
123
|
+
attributeName: string;
|
|
124
|
+
/**
|
|
125
|
+
* Creates a view element for a custom item marker.
|
|
126
|
+
*/
|
|
127
|
+
createElement(writer: DowncastWriter, modelElement: Element, { dataPipeline }: {
|
|
128
|
+
dataPipeline?: boolean;
|
|
129
|
+
}): ViewElement | null;
|
|
130
|
+
/**
|
|
131
|
+
* Creates an AttributeElement to be used for wrapping a first block of a list item.
|
|
132
|
+
*/
|
|
133
|
+
createWrapperElement?(writer: DowncastWriter, modelElement: Element, { dataPipeline }: {
|
|
134
|
+
dataPipeline?: boolean;
|
|
135
|
+
}): ViewAttributeElement;
|
|
136
|
+
/**
|
|
137
|
+
* Should return true if the given list block can be wrapped with the wrapper created by `createWrapperElement()`
|
|
138
|
+
* or only the marker element should be wrapped.
|
|
139
|
+
*/
|
|
140
|
+
canWrapElement?(modelElement: Element): boolean;
|
|
32
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* The downcast strategy.
|
|
144
|
+
*/
|
|
145
|
+
export type DowncastStrategy = AttributeDowncastStrategy | ItemMarkerDowncastStrategy;
|
|
146
|
+
/**
|
|
147
|
+
* Event fired on changes detected on the model list element to verify if the view representation of a list element
|
|
148
|
+
* is representing those attributes.
|
|
149
|
+
*
|
|
150
|
+
* It allows triggering a re-wrapping of a list item.
|
|
151
|
+
*
|
|
152
|
+
* @internal
|
|
153
|
+
* @eventName ~ListEditing#postFixer
|
|
154
|
+
* @param listHead The head element of a list.
|
|
155
|
+
* @param writer The writer to do changes with.
|
|
156
|
+
* @param seenIds The set of already known IDs.
|
|
157
|
+
* @returns If a post-fixer made a change of the model tree, it should return `true`.
|
|
158
|
+
*/
|
|
159
|
+
export type ListEditingPostFixerEvent = {
|
|
160
|
+
name: 'postFixer';
|
|
161
|
+
args: [
|
|
162
|
+
{
|
|
163
|
+
listNodes: ListBlocksIterable;
|
|
164
|
+
listHead: Element;
|
|
165
|
+
writer: Writer;
|
|
166
|
+
seenIds: Set<string>;
|
|
167
|
+
}
|
|
168
|
+
];
|
|
169
|
+
return: boolean;
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Event fired on changes detected on the model list element to verify if the view representation of a list element
|
|
173
|
+
* is representing those attributes.
|
|
174
|
+
*
|
|
175
|
+
* It allows triggering a re-wrapping of a list item.
|
|
176
|
+
*
|
|
177
|
+
* **Note**: For convenience this event is namespaced and could be captured as `checkAttributes:list` or `checkAttributes:item`.
|
|
178
|
+
*
|
|
179
|
+
* @internal
|
|
180
|
+
* @eventName ~ListEditing#checkAttributes
|
|
181
|
+
*/
|
|
182
|
+
export type ListEditingCheckAttributesEvent = {
|
|
183
|
+
name: 'checkAttributes' | 'checkAttributes:list' | 'checkAttributes:item';
|
|
184
|
+
args: [
|
|
185
|
+
{
|
|
186
|
+
viewElement: ViewElement & {
|
|
187
|
+
id?: string;
|
|
188
|
+
};
|
|
189
|
+
modelAttributes: ListItemAttributesMap;
|
|
190
|
+
}
|
|
191
|
+
];
|
|
192
|
+
return: boolean;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Event fired on changes detected on the model list element to verify if the view representation of a list block element
|
|
196
|
+
* is representing those attributes.
|
|
197
|
+
*
|
|
198
|
+
* It allows triggering a reconversion of a list item block.
|
|
199
|
+
*
|
|
200
|
+
* @internal
|
|
201
|
+
* @eventName ~ListEditing#checkElement
|
|
202
|
+
*/
|
|
203
|
+
export type ListEditingCheckElementEvent = {
|
|
204
|
+
name: 'checkElement';
|
|
205
|
+
args: [
|
|
206
|
+
{
|
|
207
|
+
viewElement: ViewElement;
|
|
208
|
+
modelElement: Element;
|
|
209
|
+
}
|
|
210
|
+
];
|
|
211
|
+
return: boolean;
|
|
212
|
+
};
|