@ckeditor/ckeditor5-widget 46.1.1 → 47.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +81 -45
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/verticalnavigation.js +2 -5
- package/src/widget.d.ts +10 -3
- package/src/widget.js +92 -39
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ckeditor/ckeditor5-widget",
|
3
|
-
"version": "
|
3
|
+
"version": "47.0.0-alpha.0",
|
4
4
|
"description": "Widget API for CKEditor 5.",
|
5
5
|
"keywords": [
|
6
6
|
"ckeditor",
|
@@ -12,13 +12,13 @@
|
|
12
12
|
"type": "module",
|
13
13
|
"main": "src/index.js",
|
14
14
|
"dependencies": {
|
15
|
-
"@ckeditor/ckeditor5-core": "
|
16
|
-
"@ckeditor/ckeditor5-engine": "
|
17
|
-
"@ckeditor/ckeditor5-enter": "
|
18
|
-
"@ckeditor/ckeditor5-icons": "
|
19
|
-
"@ckeditor/ckeditor5-ui": "
|
20
|
-
"@ckeditor/ckeditor5-utils": "
|
21
|
-
"@ckeditor/ckeditor5-typing": "
|
15
|
+
"@ckeditor/ckeditor5-core": "47.0.0-alpha.0",
|
16
|
+
"@ckeditor/ckeditor5-engine": "47.0.0-alpha.0",
|
17
|
+
"@ckeditor/ckeditor5-enter": "47.0.0-alpha.0",
|
18
|
+
"@ckeditor/ckeditor5-icons": "47.0.0-alpha.0",
|
19
|
+
"@ckeditor/ckeditor5-ui": "47.0.0-alpha.0",
|
20
|
+
"@ckeditor/ckeditor5-utils": "47.0.0-alpha.0",
|
21
|
+
"@ckeditor/ckeditor5-typing": "47.0.0-alpha.0",
|
22
22
|
"es-toolkit": "1.39.5"
|
23
23
|
},
|
24
24
|
"author": "CKSource (http://cksource.com/)",
|
@@ -83,28 +83,26 @@ function findTextRangeFromSelection(editing, selection, isForward) {
|
|
83
83
|
const endPosition = getNearestNonInlineLimit(model, startPosition, 'forward');
|
84
84
|
// There is no limit element, browser should handle this.
|
85
85
|
if (!endPosition) {
|
86
|
-
return
|
86
|
+
return;
|
87
87
|
}
|
88
88
|
const range = model.createRange(startPosition, endPosition);
|
89
89
|
const lastRangePosition = getNearestTextPosition(model.schema, range, 'backward');
|
90
90
|
if (lastRangePosition) {
|
91
91
|
return model.createRange(startPosition, lastRangePosition);
|
92
92
|
}
|
93
|
-
return null;
|
94
93
|
}
|
95
94
|
else {
|
96
95
|
const endPosition = selection.isCollapsed ? selection.focus : selection.getFirstPosition();
|
97
96
|
const startPosition = getNearestNonInlineLimit(model, endPosition, 'backward');
|
98
97
|
// There is no limit element, browser should handle this.
|
99
98
|
if (!startPosition) {
|
100
|
-
return
|
99
|
+
return;
|
101
100
|
}
|
102
101
|
const range = model.createRange(startPosition, endPosition);
|
103
102
|
const firstRangePosition = getNearestTextPosition(model.schema, range, 'forward');
|
104
103
|
if (firstRangePosition) {
|
105
104
|
return model.createRange(firstRangePosition, endPosition);
|
106
105
|
}
|
107
|
-
return null;
|
108
106
|
}
|
109
107
|
}
|
110
108
|
/**
|
@@ -147,7 +145,6 @@ function getNearestTextPosition(schema, range, direction) {
|
|
147
145
|
return nextPosition;
|
148
146
|
}
|
149
147
|
}
|
150
|
-
return null;
|
151
148
|
}
|
152
149
|
/**
|
153
150
|
* Checks if the DOM range corresponding to the provided model range renders as a single line by analyzing DOMRects
|
package/src/widget.d.ts
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
* @module widget/widget
|
7
7
|
*/
|
8
8
|
import { Plugin } from '@ckeditor/ckeditor5-core';
|
9
|
-
import { type ModelElement, type ModelNode } from '@ckeditor/ckeditor5-engine';
|
9
|
+
import { type ModelElement, type ModelNode, type ViewPosition, type ModelRange } from '@ckeditor/ckeditor5-engine';
|
10
10
|
import { Delete } from '@ckeditor/ckeditor5-typing';
|
11
11
|
import { WidgetTypeAround } from './widgettypearound/widgettypearound.js';
|
12
12
|
import '../theme/widget.css';
|
@@ -101,9 +101,16 @@ export declare class Widget extends Plugin {
|
|
101
101
|
*/
|
102
102
|
private _clearPreviouslySelectedWidgets;
|
103
103
|
/**
|
104
|
-
* Moves the document selection into the
|
104
|
+
* Moves the document selection into the next editable or block widget.
|
105
105
|
*/
|
106
|
-
private
|
106
|
+
private _selectNextEditable;
|
107
|
+
/**
|
108
|
+
* Looks for next focus point in the document starting from the given view position and direction.
|
109
|
+
* The focus point is either a block widget or an editable.
|
110
|
+
*
|
111
|
+
* @internal
|
112
|
+
*/
|
113
|
+
_findNextFocusRange(startPosition: ViewPosition, direction: 'backward' | 'forward'): ModelRange | null;
|
107
114
|
/**
|
108
115
|
* Updates the document selection so that it selects first ancestor widget.
|
109
116
|
*/
|
package/src/widget.js
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
import { Plugin } from '@ckeditor/ckeditor5-core';
|
9
9
|
import { PointerObserver, MouseObserver, ModelTreeWalker } from '@ckeditor/ckeditor5-engine';
|
10
10
|
import { Delete } from '@ckeditor/ckeditor5-typing';
|
11
|
-
import { env, keyCodes, getLocalizedArrowKeyCodeDirection, getRangeFromMouseEvent } from '@ckeditor/ckeditor5-utils';
|
11
|
+
import { env, keyCodes, getLocalizedArrowKeyCodeDirection, getRangeFromMouseEvent, compareArrays } from '@ckeditor/ckeditor5-utils';
|
12
12
|
import { WidgetTypeAround } from './widgettypearound/widgettypearound.js';
|
13
13
|
import { verticalWidgetNavigationHandler } from './verticalnavigation.js';
|
14
14
|
import { getLabel, isWidget, WIDGET_SELECTED_CLASS_NAME } from './utils.js';
|
@@ -151,31 +151,17 @@ export class Widget extends Plugin {
|
|
151
151
|
evt.stop();
|
152
152
|
}
|
153
153
|
}, { context: '$root' });
|
154
|
-
// Handle Tab key
|
154
|
+
// Handle Tab/Shift+Tab key.
|
155
155
|
this.listenTo(viewDocument, 'tab', (evt, data) => {
|
156
|
-
|
157
|
-
|
158
|
-
if (evt.eventPhase != 'atTarget') {
|
159
|
-
return;
|
160
|
-
}
|
161
|
-
if (data.shiftKey) {
|
162
|
-
return;
|
163
|
-
}
|
164
|
-
if (this._selectFirstNestedEditable()) {
|
165
|
-
data.preventDefault();
|
166
|
-
evt.stop();
|
167
|
-
}
|
168
|
-
}, { context: isWidget, priority: 'low' });
|
169
|
-
// Handle Shift+Tab key while caret inside a widget editable.
|
170
|
-
this.listenTo(viewDocument, 'tab', (evt, data) => {
|
171
|
-
if (!data.shiftKey) {
|
172
|
-
return;
|
173
|
-
}
|
174
|
-
if (this._selectAncestorWidget()) {
|
156
|
+
if (this._selectNextEditable(data.shiftKey ? 'backward' : 'forward')) {
|
157
|
+
view.scrollToTheSelection();
|
175
158
|
data.preventDefault();
|
176
159
|
evt.stop();
|
177
160
|
}
|
178
|
-
}, {
|
161
|
+
}, {
|
162
|
+
context: node => isWidget(node) || node.is('editableElement'),
|
163
|
+
priority: 'low'
|
164
|
+
});
|
179
165
|
// Handle Esc key while inside a nested editable.
|
180
166
|
this.listenTo(viewDocument, 'keydown', (evt, data) => {
|
181
167
|
if (data.keystroke != keyCodes.esc) {
|
@@ -462,28 +448,95 @@ export class Widget extends Plugin {
|
|
462
448
|
this._previouslySelected.clear();
|
463
449
|
}
|
464
450
|
/**
|
465
|
-
* Moves the document selection into the
|
451
|
+
* Moves the document selection into the next editable or block widget.
|
466
452
|
*/
|
467
|
-
|
468
|
-
const
|
469
|
-
const view =
|
470
|
-
const
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
453
|
+
_selectNextEditable(direction) {
|
454
|
+
const editing = this.editor.editing;
|
455
|
+
const view = editing.view;
|
456
|
+
const model = this.editor.model;
|
457
|
+
const viewSelection = view.document.selection;
|
458
|
+
const modelSelection = model.document.selection;
|
459
|
+
// Find start position.
|
460
|
+
let startPosition;
|
461
|
+
// Multiple table cells are selected - use focus cell.
|
462
|
+
if (modelSelection.rangeCount > 1) {
|
463
|
+
const selectionRange = modelSelection.isBackward ?
|
464
|
+
modelSelection.getFirstRange() :
|
465
|
+
modelSelection.getLastRange();
|
466
|
+
startPosition = editing.mapper.toViewPosition(direction == 'forward' ?
|
467
|
+
selectionRange.end :
|
468
|
+
selectionRange.start);
|
469
|
+
}
|
470
|
+
else {
|
471
|
+
startPosition = direction == 'forward' ?
|
472
|
+
viewSelection.getFirstPosition() :
|
473
|
+
viewSelection.getLastPosition();
|
474
|
+
}
|
475
|
+
const modelRange = this._findNextFocusRange(startPosition, direction);
|
476
|
+
if (modelRange) {
|
477
|
+
model.change(writer => {
|
478
|
+
writer.setSelection(modelRange);
|
479
|
+
});
|
480
|
+
return true;
|
481
|
+
}
|
482
|
+
return false;
|
483
|
+
}
|
484
|
+
/**
|
485
|
+
* Looks for next focus point in the document starting from the given view position and direction.
|
486
|
+
* The focus point is either a block widget or an editable.
|
487
|
+
*
|
488
|
+
* @internal
|
489
|
+
*/
|
490
|
+
_findNextFocusRange(startPosition, direction) {
|
491
|
+
const editing = this.editor.editing;
|
492
|
+
const view = editing.view;
|
493
|
+
const model = this.editor.model;
|
494
|
+
const viewSelection = view.document.selection;
|
495
|
+
const editableElement = viewSelection.editableElement;
|
496
|
+
const editablePath = editableElement.getPath();
|
497
|
+
let selectedElement = viewSelection.getSelectedElement();
|
498
|
+
if (selectedElement && !isWidget(selectedElement)) {
|
499
|
+
selectedElement = null;
|
500
|
+
}
|
501
|
+
// Look for the next editable.
|
502
|
+
const viewRange = direction == 'forward' ?
|
503
|
+
view.createRange(startPosition, view.createPositionAt(startPosition.root, 'end')) :
|
504
|
+
view.createRange(view.createPositionAt(startPosition.root, 0), startPosition);
|
505
|
+
for (const { nextPosition } of viewRange.getWalker({ direction })) {
|
506
|
+
const item = nextPosition.parent;
|
507
|
+
// Ignore currently selected editable or widget.
|
508
|
+
if (item == editableElement || item == selectedElement) {
|
509
|
+
continue;
|
510
|
+
}
|
511
|
+
// Some widget along the way.
|
512
|
+
if (isWidget(item)) {
|
513
|
+
const modelElement = editing.mapper.toModelElement(item);
|
514
|
+
// Do not select inline widgets.
|
515
|
+
if (!model.schema.isBlock(modelElement)) {
|
476
516
|
continue;
|
477
517
|
}
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
518
|
+
// Do not select widget itself when going out of widget or iterating over sibling elements in a widget.
|
519
|
+
if (compareArrays(editablePath, item.getPath()) != 'extension') {
|
520
|
+
return model.createRangeOn(modelElement);
|
521
|
+
}
|
522
|
+
}
|
523
|
+
// Encountered an editable element.
|
524
|
+
else if (item.is('editableElement')) {
|
525
|
+
const modelPosition = editing.mapper.toModelPosition(nextPosition);
|
526
|
+
let newRange = model.schema.getNearestSelectionRange(modelPosition, direction);
|
527
|
+
// There is nothing to select so just jump to the next one.
|
528
|
+
if (!newRange) {
|
529
|
+
continue;
|
530
|
+
}
|
531
|
+
// Select the content of editable element when iterating over sibling editable elements
|
532
|
+
// or going deeper into nested widgets.
|
533
|
+
if (compareArrays(editablePath, item.getPath()) != 'extension') {
|
534
|
+
newRange = model.createRangeIn(modelPosition.parent);
|
535
|
+
}
|
536
|
+
return newRange;
|
484
537
|
}
|
485
538
|
}
|
486
|
-
return
|
539
|
+
return null;
|
487
540
|
}
|
488
541
|
/**
|
489
542
|
* Updates the document selection so that it selects first ancestor widget.
|