@ckeditor/ckeditor5-widget 47.1.0 → 47.2.0-alpha.1
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/README.md +1 -1
- package/dist/index.js +99 -53
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/verticalnavigation.js +2 -10
- package/src/widget.js +99 -43
- package/src/widgettypearound/widgettypearound.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-widget",
|
|
3
|
-
"version": "47.
|
|
3
|
+
"version": "47.2.0-alpha.1",
|
|
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": "47.
|
|
16
|
-
"@ckeditor/ckeditor5-engine": "47.
|
|
17
|
-
"@ckeditor/ckeditor5-enter": "47.
|
|
18
|
-
"@ckeditor/ckeditor5-icons": "47.
|
|
19
|
-
"@ckeditor/ckeditor5-ui": "47.
|
|
20
|
-
"@ckeditor/ckeditor5-utils": "47.
|
|
21
|
-
"@ckeditor/ckeditor5-typing": "47.
|
|
15
|
+
"@ckeditor/ckeditor5-core": "47.2.0-alpha.1",
|
|
16
|
+
"@ckeditor/ckeditor5-engine": "47.2.0-alpha.1",
|
|
17
|
+
"@ckeditor/ckeditor5-enter": "47.2.0-alpha.1",
|
|
18
|
+
"@ckeditor/ckeditor5-icons": "47.2.0-alpha.1",
|
|
19
|
+
"@ckeditor/ckeditor5-ui": "47.2.0-alpha.1",
|
|
20
|
+
"@ckeditor/ckeditor5-utils": "47.2.0-alpha.1",
|
|
21
|
+
"@ckeditor/ckeditor5-typing": "47.2.0-alpha.1",
|
|
22
22
|
"es-toolkit": "1.39.5"
|
|
23
23
|
},
|
|
24
24
|
"author": "CKSource (http://cksource.com/)",
|
|
@@ -22,11 +22,6 @@ export function verticalWidgetNavigationHandler(editing) {
|
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
24
|
const isForward = arrowDownPressed;
|
|
25
|
-
// Navigation is in the opposite direction than the selection direction so this is shrinking of the selection.
|
|
26
|
-
// Selection for sure will not approach any object.
|
|
27
|
-
if (expandSelection && selectionWillShrink(selection, isForward)) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
25
|
// Find a range between selection and closest limit element.
|
|
31
26
|
const range = findTextRangeFromSelection(editing, selection, isForward);
|
|
32
27
|
// There is no selection position inside the limit element.
|
|
@@ -79,7 +74,7 @@ export function verticalWidgetNavigationHandler(editing) {
|
|
|
79
74
|
function findTextRangeFromSelection(editing, selection, isForward) {
|
|
80
75
|
const model = editing.model;
|
|
81
76
|
if (isForward) {
|
|
82
|
-
const startPosition = selection.
|
|
77
|
+
const startPosition = selection.focus;
|
|
83
78
|
const endPosition = getNearestNonInlineLimit(model, startPosition, 'forward');
|
|
84
79
|
// There is no limit element, browser should handle this.
|
|
85
80
|
if (!endPosition) {
|
|
@@ -92,7 +87,7 @@ function findTextRangeFromSelection(editing, selection, isForward) {
|
|
|
92
87
|
}
|
|
93
88
|
}
|
|
94
89
|
else {
|
|
95
|
-
const endPosition = selection.
|
|
90
|
+
const endPosition = selection.focus;
|
|
96
91
|
const startPosition = getNearestNonInlineLimit(model, endPosition, 'backward');
|
|
97
92
|
// There is no limit element, browser should handle this.
|
|
98
93
|
if (!startPosition) {
|
|
@@ -188,6 +183,3 @@ function isSingleLineRange(editing, modelRange, isForward) {
|
|
|
188
183
|
}
|
|
189
184
|
return true;
|
|
190
185
|
}
|
|
191
|
-
function selectionWillShrink(selection, isForward) {
|
|
192
|
-
return !selection.isCollapsed && selection.isBackward == isForward;
|
|
193
|
-
}
|
package/src/widget.js
CHANGED
|
@@ -10,6 +10,7 @@ import { PointerObserver, MouseObserver, ModelTreeWalker } from '@ckeditor/ckedi
|
|
|
10
10
|
import { Delete } from '@ckeditor/ckeditor5-typing';
|
|
11
11
|
import { env, keyCodes, getLocalizedArrowKeyCodeDirection, getRangeFromMouseEvent, compareArrays } from '@ckeditor/ckeditor5-utils';
|
|
12
12
|
import { WidgetTypeAround } from './widgettypearound/widgettypearound.js';
|
|
13
|
+
import { getTypeAroundFakeCaretPosition } from './widgettypearound/utils.js';
|
|
13
14
|
import { verticalWidgetNavigationHandler } from './verticalnavigation.js';
|
|
14
15
|
import { getLabel, isWidget, WIDGET_SELECTED_CLASS_NAME } from './utils.js';
|
|
15
16
|
import '../theme/widget.css';
|
|
@@ -171,7 +172,10 @@ export class Widget extends Plugin {
|
|
|
171
172
|
data.preventDefault();
|
|
172
173
|
evt.stop();
|
|
173
174
|
}
|
|
174
|
-
}, {
|
|
175
|
+
}, {
|
|
176
|
+
context: node => node.is('editableElement'),
|
|
177
|
+
priority: 'low'
|
|
178
|
+
});
|
|
175
179
|
// Add the information about the keystrokes to the accessibility database.
|
|
176
180
|
editor.accessibility.addKeystrokeInfoGroup({
|
|
177
181
|
id: 'widget',
|
|
@@ -304,53 +308,69 @@ export class Widget extends Plugin {
|
|
|
304
308
|
const model = this.editor.model;
|
|
305
309
|
const schema = model.schema;
|
|
306
310
|
const modelSelection = model.document.selection;
|
|
307
|
-
const
|
|
311
|
+
const selectedElement = modelSelection.getSelectedElement();
|
|
308
312
|
const direction = getLocalizedArrowKeyCodeDirection(keyCode, this.editor.locale.contentLanguageDirection);
|
|
309
313
|
const isForward = direction == 'down' || direction == 'right';
|
|
310
314
|
const isVerticalNavigation = direction == 'up' || direction == 'down';
|
|
311
|
-
//
|
|
312
|
-
if (
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
315
|
+
// Collapsing a non-collapsed selection.
|
|
316
|
+
if (!domEventData.shiftKey && !modelSelection.isCollapsed) {
|
|
317
|
+
// If object element is selected or object is at the edge of selection.
|
|
318
|
+
if (hasObjectAtEdge(modelSelection, schema)) {
|
|
319
|
+
const position = isForward ? modelSelection.getLastPosition() : modelSelection.getFirstPosition();
|
|
320
|
+
const newRange = schema.getNearestSelectionRange(position, isForward ? 'forward' : 'backward');
|
|
321
|
+
if (newRange) {
|
|
322
|
+
model.change(writer => {
|
|
323
|
+
writer.setSelection(newRange);
|
|
324
|
+
});
|
|
325
|
+
domEventData.preventDefault();
|
|
326
|
+
eventInfo.stop();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
// Else is handled by the browser.
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
// Adjust selection for fake caret and for selection direction when single object is selected.
|
|
333
|
+
const originalSelection = getModelSelectionAdjusted(model, isForward);
|
|
334
|
+
// Clone current selection to use it as a probe. We must leave default selection as it is so it can return
|
|
335
|
+
// to its current state after undo.
|
|
336
|
+
const probe = model.createSelection(originalSelection);
|
|
337
|
+
model.modifySelection(probe, { direction: isForward ? 'forward' : 'backward' });
|
|
338
|
+
// The selection didn't change so there is nothing there.
|
|
339
|
+
if (probe.isEqual(originalSelection)) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
// Move probe one step further to make it visually recognizable.
|
|
343
|
+
if (probe.focus.isTouching(originalSelection.focus)) {
|
|
344
|
+
model.modifySelection(probe, { direction: isForward ? 'forward' : 'backward' });
|
|
345
|
+
}
|
|
346
|
+
const lastSelectedNode = isForward ? originalSelection.focus.nodeBefore : originalSelection.focus.nodeAfter;
|
|
347
|
+
const nodeBeforeProbe = probe.focus.nodeBefore;
|
|
348
|
+
const nodeAfterProbe = probe.focus.nodeAfter;
|
|
349
|
+
const lastProbeNode = isForward ? nodeBeforeProbe : nodeAfterProbe;
|
|
350
|
+
if (domEventData.shiftKey) {
|
|
351
|
+
// Expand selection from a selected object or include object in selection.
|
|
352
|
+
if (selectedElement && schema.isObject(selectedElement) ||
|
|
353
|
+
lastProbeNode && schema.isObject(lastProbeNode) ||
|
|
354
|
+
lastSelectedNode && schema.isObject(lastSelectedNode)) {
|
|
316
355
|
model.change(writer => {
|
|
317
|
-
writer.setSelection(
|
|
356
|
+
writer.setSelection(probe);
|
|
318
357
|
});
|
|
319
358
|
domEventData.preventDefault();
|
|
320
359
|
eventInfo.stop();
|
|
321
360
|
}
|
|
322
|
-
return;
|
|
323
361
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const lastSelectedNode = lastPosition.nodeBefore;
|
|
331
|
-
if (firstSelectedNode && schema.isObject(firstSelectedNode) || lastSelectedNode && schema.isObject(lastSelectedNode)) {
|
|
362
|
+
else {
|
|
363
|
+
// Select an object when moving caret over it.
|
|
364
|
+
if (lastProbeNode && schema.isObject(lastProbeNode)) {
|
|
365
|
+
if (schema.isInline(lastProbeNode) && isVerticalNavigation) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
332
368
|
model.change(writer => {
|
|
333
|
-
writer.setSelection(
|
|
369
|
+
writer.setSelection(lastProbeNode, 'on');
|
|
334
370
|
});
|
|
335
371
|
domEventData.preventDefault();
|
|
336
372
|
eventInfo.stop();
|
|
337
373
|
}
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
// Return if not collapsed.
|
|
341
|
-
if (!modelSelection.isCollapsed) {
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
// If selection is next to object element.
|
|
345
|
-
const objectElementNextToSelection = this._getObjectElementNextToSelection(isForward);
|
|
346
|
-
if (objectElementNextToSelection && schema.isObject(objectElementNextToSelection)) {
|
|
347
|
-
// Do not select an inline widget while handling up/down arrow.
|
|
348
|
-
if (schema.isInline(objectElementNextToSelection) && isVerticalNavigation) {
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
this._setSelectionOverElement(objectElementNextToSelection);
|
|
352
|
-
domEventData.preventDefault();
|
|
353
|
-
eventInfo.stop();
|
|
354
374
|
}
|
|
355
375
|
}
|
|
356
376
|
/**
|
|
@@ -433,7 +453,7 @@ export class Widget extends Plugin {
|
|
|
433
453
|
return null;
|
|
434
454
|
}
|
|
435
455
|
const objectElement = forward ? probe.focus.nodeBefore : probe.focus.nodeAfter;
|
|
436
|
-
if (
|
|
456
|
+
if (objectElement && schema.isObject(objectElement)) {
|
|
437
457
|
return objectElement;
|
|
438
458
|
}
|
|
439
459
|
return null;
|
|
@@ -504,12 +524,8 @@ export class Widget extends Plugin {
|
|
|
504
524
|
view.createRange(view.createPositionAt(startPosition.root, 0), startPosition);
|
|
505
525
|
for (const { nextPosition } of viewRange.getWalker({ direction })) {
|
|
506
526
|
const item = nextPosition.parent;
|
|
507
|
-
//
|
|
508
|
-
if (item
|
|
509
|
-
continue;
|
|
510
|
-
}
|
|
511
|
-
// Some widget along the way.
|
|
512
|
-
if (isWidget(item)) {
|
|
527
|
+
// Some widget along the way except the currently selected one.
|
|
528
|
+
if (isWidget(item) && item != selectedElement) {
|
|
513
529
|
const modelElement = editing.mapper.toModelElement(item);
|
|
514
530
|
// Do not select inline widgets.
|
|
515
531
|
if (!model.schema.isBlock(modelElement)) {
|
|
@@ -522,16 +538,26 @@ export class Widget extends Plugin {
|
|
|
522
538
|
}
|
|
523
539
|
// Encountered an editable element.
|
|
524
540
|
else if (item.is('editableElement')) {
|
|
541
|
+
// Ignore the current editable for text selection,
|
|
542
|
+
// but use it when widget was selected to be able to jump after the widget.
|
|
543
|
+
if (item == editableElement && !selectedElement) {
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
525
546
|
const modelPosition = editing.mapper.toModelPosition(nextPosition);
|
|
526
|
-
|
|
547
|
+
const newRange = model.schema.getNearestSelectionRange(modelPosition, direction);
|
|
527
548
|
// There is nothing to select so just jump to the next one.
|
|
528
549
|
if (!newRange) {
|
|
529
550
|
continue;
|
|
530
551
|
}
|
|
552
|
+
// In the same editable while widget was selected - do not select the editable content.
|
|
553
|
+
if (item == editableElement && selectedElement) {
|
|
554
|
+
return newRange;
|
|
555
|
+
}
|
|
531
556
|
// Select the content of editable element when iterating over sibling editable elements
|
|
532
557
|
// or going deeper into nested widgets.
|
|
533
558
|
if (compareArrays(editablePath, item.getPath()) != 'extension') {
|
|
534
|
-
|
|
559
|
+
// Find a limit element closest to the new selection range.
|
|
560
|
+
return model.createRangeIn(model.schema.getLimitElement(newRange));
|
|
535
561
|
}
|
|
536
562
|
return newRange;
|
|
537
563
|
}
|
|
@@ -564,6 +590,36 @@ export class Widget extends Plugin {
|
|
|
564
590
|
return true;
|
|
565
591
|
}
|
|
566
592
|
}
|
|
593
|
+
/**
|
|
594
|
+
* Returns true if there is an object on an edge of the given selection.
|
|
595
|
+
*/
|
|
596
|
+
function hasObjectAtEdge(modelSelection, schema) {
|
|
597
|
+
const firstPosition = modelSelection.getFirstPosition();
|
|
598
|
+
const lastPosition = modelSelection.getLastPosition();
|
|
599
|
+
const firstSelectedNode = firstPosition.nodeAfter;
|
|
600
|
+
const lastSelectedNode = lastPosition.nodeBefore;
|
|
601
|
+
return (!!firstSelectedNode && schema.isObject(firstSelectedNode) ||
|
|
602
|
+
!!lastSelectedNode && schema.isObject(lastSelectedNode));
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Returns new instance of the model selection adjusted for fake caret and selection direction on widgets.
|
|
606
|
+
*/
|
|
607
|
+
function getModelSelectionAdjusted(model, isForward) {
|
|
608
|
+
const modelSelection = model.document.selection;
|
|
609
|
+
const selectedElement = modelSelection.getSelectedElement();
|
|
610
|
+
// Adjust selection for fake caret.
|
|
611
|
+
const typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition(modelSelection);
|
|
612
|
+
if (selectedElement && typeAroundFakeCaretPosition == 'before') {
|
|
613
|
+
return model.createSelection(selectedElement, 'before');
|
|
614
|
+
}
|
|
615
|
+
else if (selectedElement && typeAroundFakeCaretPosition == 'after') {
|
|
616
|
+
return model.createSelection(selectedElement, 'after');
|
|
617
|
+
}
|
|
618
|
+
// Make a copy of selection with adjusted direction for object selected.
|
|
619
|
+
return model.createSelection(modelSelection.getRanges(), {
|
|
620
|
+
backward: !!selectedElement && model.schema.isObject(selectedElement) ? !isForward : modelSelection.isBackward
|
|
621
|
+
});
|
|
622
|
+
}
|
|
567
623
|
/**
|
|
568
624
|
* Finds the closest ancestor element that is either an editable element or a widget.
|
|
569
625
|
*
|
|
@@ -315,6 +315,10 @@ export class WidgetTypeAround extends Plugin {
|
|
|
315
315
|
const modelSelection = model.document.selection;
|
|
316
316
|
const schema = model.schema;
|
|
317
317
|
const editingView = editor.editing.view;
|
|
318
|
+
// Selection expanding/shrinking is handled without the fake caret by the widget plugin.
|
|
319
|
+
if (domEventData.shiftKey) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
318
322
|
const keyCode = domEventData.keyCode;
|
|
319
323
|
const isForward = isForwardArrowKeyCode(keyCode, editor.locale.contentLanguageDirection);
|
|
320
324
|
const selectedViewElement = editingView.document.selection.getSelectedElement();
|