@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.
- package/LICENSE.md +1 -1
- package/build/list.js +2 -2
- package/package.json +43 -39
- package/src/documentlist/converters.js +303 -419
- package/src/documentlist/documentlistcommand.js +136 -207
- package/src/documentlist/documentlistediting.js +538 -697
- package/src/documentlist/documentlistindentcommand.js +115 -168
- package/src/documentlist/documentlistmergecommand.js +161 -222
- package/src/documentlist/documentlistsplitcommand.js +59 -103
- package/src/documentlist/documentlistutils.js +41 -0
- package/src/documentlist/utils/listwalker.js +138 -236
- package/src/documentlist/utils/model.js +322 -421
- package/src/documentlist/utils/postfixers.js +98 -118
- package/src/documentlist/utils/view.js +74 -105
- package/src/documentlist.js +13 -19
- package/src/documentlistproperties/converters.js +33 -47
- package/src/documentlistproperties/documentlistpropertiesediting.js +266 -354
- package/src/documentlistproperties/documentlistpropertiesutils.js +44 -0
- package/src/documentlistproperties/documentlistreversedcommand.js +40 -61
- package/src/documentlistproperties/documentliststartcommand.js +42 -61
- package/src/documentlistproperties/documentliststylecommand.js +97 -147
- package/src/documentlistproperties/utils/style.js +27 -47
- package/src/documentlistproperties.js +13 -19
- package/src/index.js +4 -3
- package/src/list/converters.js +772 -929
- package/src/list/indentcommand.js +105 -140
- package/src/list/listcommand.js +262 -315
- package/src/list/listediting.js +142 -200
- package/src/list/listui.js +16 -25
- package/src/list/listutils.js +46 -0
- package/src/list/utils.js +295 -378
- package/src/list.js +13 -44
- package/src/listcommands.js +5 -0
- package/src/listconfig.js +5 -0
- package/src/listproperties/listpropertiesediting.js +656 -801
- package/src/listproperties/listpropertiesui.js +244 -296
- package/src/listproperties/listreversedcommand.js +37 -49
- package/src/listproperties/liststartcommand.js +37 -49
- package/src/listproperties/liststylecommand.js +82 -115
- package/src/listproperties/ui/collapsibleview.js +75 -138
- package/src/listproperties/ui/listpropertiesview.js +289 -414
- package/src/listproperties.js +13 -118
- package/src/liststyle.js +18 -24
- package/src/todolist/checktodolistcommand.js +60 -102
- package/src/todolist/todolistconverters.js +189 -271
- package/src/todolist/todolistediting.js +141 -206
- package/src/todolist/todolistui.js +14 -21
- package/src/todolist.js +13 -19
- package/theme/collapsible.css +1 -1
- package/theme/documentlist.css +1 -1
- package/theme/list.css +40 -0
- package/theme/listproperties.css +1 -1
- package/theme/liststyles.css +1 -37
- package/theme/todolist.css +1 -1
- package/build/list.js.map +0 -1
package/src/list/listediting.js
CHANGED
|
@@ -1,219 +1,161 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
}
|
package/src/list/listui.js
CHANGED
|
@@ -1,41 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Copyright (c) 2003-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
+
}
|