@ckeditor/ckeditor5-widget 47.1.0-alpha.2 → 47.2.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/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/README.md
CHANGED
|
@@ -2,7 +2,7 @@ CKEditor 5 widget API
|
|
|
2
2
|
========================================
|
|
3
3
|
|
|
4
4
|
[](https://www.npmjs.com/package/@ckeditor/ckeditor5-widget)
|
|
5
|
-
[](https://codecov.io/gh/ckeditor/ckeditor5)
|
|
6
6
|
[](https://app.circleci.com/pipelines/github/ckeditor/ckeditor5?branch=master)
|
|
7
7
|
|
|
8
8
|
This package implements the widget API for CKEditor 5.
|
package/dist/index.js
CHANGED
|
@@ -860,6 +860,10 @@ const PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';
|
|
|
860
860
|
const modelSelection = model.document.selection;
|
|
861
861
|
const schema = model.schema;
|
|
862
862
|
const editingView = editor.editing.view;
|
|
863
|
+
// Selection expanding/shrinking is handled without the fake caret by the widget plugin.
|
|
864
|
+
if (domEventData.shiftKey) {
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
863
867
|
const keyCode = domEventData.keyCode;
|
|
864
868
|
const isForward = isForwardArrowKeyCode(keyCode, editor.locale.contentLanguageDirection);
|
|
865
869
|
const selectedViewElement = editingView.document.selection.getSelectedElement();
|
|
@@ -1318,11 +1322,6 @@ function injectFakeCaret(wrapperDomElement) {
|
|
|
1318
1322
|
return;
|
|
1319
1323
|
}
|
|
1320
1324
|
const isForward = arrowDownPressed;
|
|
1321
|
-
// Navigation is in the opposite direction than the selection direction so this is shrinking of the selection.
|
|
1322
|
-
// Selection for sure will not approach any object.
|
|
1323
|
-
if (expandSelection && selectionWillShrink(selection, isForward)) {
|
|
1324
|
-
return;
|
|
1325
|
-
}
|
|
1326
1325
|
// Find a range between selection and closest limit element.
|
|
1327
1326
|
const range = findTextRangeFromSelection(editing, selection, isForward);
|
|
1328
1327
|
// There is no selection position inside the limit element.
|
|
@@ -1371,7 +1370,7 @@ function injectFakeCaret(wrapperDomElement) {
|
|
|
1371
1370
|
*/ function findTextRangeFromSelection(editing, selection, isForward) {
|
|
1372
1371
|
const model = editing.model;
|
|
1373
1372
|
if (isForward) {
|
|
1374
|
-
const startPosition = selection.
|
|
1373
|
+
const startPosition = selection.focus;
|
|
1375
1374
|
const endPosition = getNearestNonInlineLimit(model, startPosition, 'forward');
|
|
1376
1375
|
// There is no limit element, browser should handle this.
|
|
1377
1376
|
if (!endPosition) {
|
|
@@ -1383,7 +1382,7 @@ function injectFakeCaret(wrapperDomElement) {
|
|
|
1383
1382
|
return model.createRange(startPosition, lastRangePosition);
|
|
1384
1383
|
}
|
|
1385
1384
|
} else {
|
|
1386
|
-
const endPosition = selection.
|
|
1385
|
+
const endPosition = selection.focus;
|
|
1387
1386
|
const startPosition = getNearestNonInlineLimit(model, endPosition, 'backward');
|
|
1388
1387
|
// There is no limit element, browser should handle this.
|
|
1389
1388
|
if (!startPosition) {
|
|
@@ -1481,9 +1480,6 @@ function injectFakeCaret(wrapperDomElement) {
|
|
|
1481
1480
|
}
|
|
1482
1481
|
return true;
|
|
1483
1482
|
}
|
|
1484
|
-
function selectionWillShrink(selection, isForward) {
|
|
1485
|
-
return !selection.isCollapsed && selection.isBackward == isForward;
|
|
1486
|
-
}
|
|
1487
1483
|
|
|
1488
1484
|
/**
|
|
1489
1485
|
* The widget plugin. It enables base support for widgets.
|
|
@@ -1654,6 +1650,7 @@ function selectionWillShrink(selection, isForward) {
|
|
|
1654
1650
|
evt.stop();
|
|
1655
1651
|
}
|
|
1656
1652
|
}, {
|
|
1653
|
+
context: (node)=>node.is('editableElement'),
|
|
1657
1654
|
priority: 'low'
|
|
1658
1655
|
});
|
|
1659
1656
|
// Add the information about the keystrokes to the accessibility database.
|
|
@@ -1792,53 +1789,70 @@ function selectionWillShrink(selection, isForward) {
|
|
|
1792
1789
|
const model = this.editor.model;
|
|
1793
1790
|
const schema = model.schema;
|
|
1794
1791
|
const modelSelection = model.document.selection;
|
|
1795
|
-
const
|
|
1792
|
+
const selectedElement = modelSelection.getSelectedElement();
|
|
1796
1793
|
const direction = getLocalizedArrowKeyCodeDirection(keyCode, this.editor.locale.contentLanguageDirection);
|
|
1797
1794
|
const isForward = direction == 'down' || direction == 'right';
|
|
1798
1795
|
const isVerticalNavigation = direction == 'up' || direction == 'down';
|
|
1799
|
-
//
|
|
1800
|
-
if (
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1796
|
+
// Collapsing a non-collapsed selection.
|
|
1797
|
+
if (!domEventData.shiftKey && !modelSelection.isCollapsed) {
|
|
1798
|
+
// If object element is selected or object is at the edge of selection.
|
|
1799
|
+
if (hasObjectAtEdge(modelSelection, schema)) {
|
|
1800
|
+
const position = isForward ? modelSelection.getLastPosition() : modelSelection.getFirstPosition();
|
|
1801
|
+
const newRange = schema.getNearestSelectionRange(position, isForward ? 'forward' : 'backward');
|
|
1802
|
+
if (newRange) {
|
|
1803
|
+
model.change((writer)=>{
|
|
1804
|
+
writer.setSelection(newRange);
|
|
1805
|
+
});
|
|
1806
|
+
domEventData.preventDefault();
|
|
1807
|
+
eventInfo.stop();
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
// Else is handled by the browser.
|
|
1811
|
+
return;
|
|
1812
|
+
}
|
|
1813
|
+
// Adjust selection for fake caret and for selection direction when single object is selected.
|
|
1814
|
+
const originalSelection = getModelSelectionAdjusted(model, isForward);
|
|
1815
|
+
// Clone current selection to use it as a probe. We must leave default selection as it is so it can return
|
|
1816
|
+
// to its current state after undo.
|
|
1817
|
+
const probe = model.createSelection(originalSelection);
|
|
1818
|
+
model.modifySelection(probe, {
|
|
1819
|
+
direction: isForward ? 'forward' : 'backward'
|
|
1820
|
+
});
|
|
1821
|
+
// The selection didn't change so there is nothing there.
|
|
1822
|
+
if (probe.isEqual(originalSelection)) {
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
// Move probe one step further to make it visually recognizable.
|
|
1826
|
+
if (probe.focus.isTouching(originalSelection.focus)) {
|
|
1827
|
+
model.modifySelection(probe, {
|
|
1828
|
+
direction: isForward ? 'forward' : 'backward'
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
const lastSelectedNode = isForward ? originalSelection.focus.nodeBefore : originalSelection.focus.nodeAfter;
|
|
1832
|
+
const nodeBeforeProbe = probe.focus.nodeBefore;
|
|
1833
|
+
const nodeAfterProbe = probe.focus.nodeAfter;
|
|
1834
|
+
const lastProbeNode = isForward ? nodeBeforeProbe : nodeAfterProbe;
|
|
1835
|
+
if (domEventData.shiftKey) {
|
|
1836
|
+
// Expand selection from a selected object or include object in selection.
|
|
1837
|
+
if (selectedElement && schema.isObject(selectedElement) || lastProbeNode && schema.isObject(lastProbeNode) || lastSelectedNode && schema.isObject(lastSelectedNode)) {
|
|
1804
1838
|
model.change((writer)=>{
|
|
1805
|
-
writer.setSelection(
|
|
1839
|
+
writer.setSelection(probe);
|
|
1806
1840
|
});
|
|
1807
1841
|
domEventData.preventDefault();
|
|
1808
1842
|
eventInfo.stop();
|
|
1809
1843
|
}
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
const lastPosition = modelSelection.getLastPosition();
|
|
1817
|
-
const firstSelectedNode = firstPosition.nodeAfter;
|
|
1818
|
-
const lastSelectedNode = lastPosition.nodeBefore;
|
|
1819
|
-
if (firstSelectedNode && schema.isObject(firstSelectedNode) || lastSelectedNode && schema.isObject(lastSelectedNode)) {
|
|
1844
|
+
} else {
|
|
1845
|
+
// Select an object when moving caret over it.
|
|
1846
|
+
if (lastProbeNode && schema.isObject(lastProbeNode)) {
|
|
1847
|
+
if (schema.isInline(lastProbeNode) && isVerticalNavigation) {
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1820
1850
|
model.change((writer)=>{
|
|
1821
|
-
writer.setSelection(
|
|
1851
|
+
writer.setSelection(lastProbeNode, 'on');
|
|
1822
1852
|
});
|
|
1823
1853
|
domEventData.preventDefault();
|
|
1824
1854
|
eventInfo.stop();
|
|
1825
1855
|
}
|
|
1826
|
-
return;
|
|
1827
|
-
}
|
|
1828
|
-
// Return if not collapsed.
|
|
1829
|
-
if (!modelSelection.isCollapsed) {
|
|
1830
|
-
return;
|
|
1831
|
-
}
|
|
1832
|
-
// If selection is next to object element.
|
|
1833
|
-
const objectElementNextToSelection = this._getObjectElementNextToSelection(isForward);
|
|
1834
|
-
if (objectElementNextToSelection && schema.isObject(objectElementNextToSelection)) {
|
|
1835
|
-
// Do not select an inline widget while handling up/down arrow.
|
|
1836
|
-
if (schema.isInline(objectElementNextToSelection) && isVerticalNavigation) {
|
|
1837
|
-
return;
|
|
1838
|
-
}
|
|
1839
|
-
this._setSelectionOverElement(objectElementNextToSelection);
|
|
1840
|
-
domEventData.preventDefault();
|
|
1841
|
-
eventInfo.stop();
|
|
1842
1856
|
}
|
|
1843
1857
|
}
|
|
1844
1858
|
/**
|
|
@@ -1919,7 +1933,7 @@ function selectionWillShrink(selection, isForward) {
|
|
|
1919
1933
|
return null;
|
|
1920
1934
|
}
|
|
1921
1935
|
const objectElement = forward ? probe.focus.nodeBefore : probe.focus.nodeAfter;
|
|
1922
|
-
if (
|
|
1936
|
+
if (objectElement && schema.isObject(objectElement)) {
|
|
1923
1937
|
return objectElement;
|
|
1924
1938
|
}
|
|
1925
1939
|
return null;
|
|
@@ -1980,12 +1994,8 @@ function selectionWillShrink(selection, isForward) {
|
|
|
1980
1994
|
direction
|
|
1981
1995
|
})){
|
|
1982
1996
|
const item = nextPosition.parent;
|
|
1983
|
-
//
|
|
1984
|
-
if (item
|
|
1985
|
-
continue;
|
|
1986
|
-
}
|
|
1987
|
-
// Some widget along the way.
|
|
1988
|
-
if (isWidget(item)) {
|
|
1997
|
+
// Some widget along the way except the currently selected one.
|
|
1998
|
+
if (isWidget(item) && item != selectedElement) {
|
|
1989
1999
|
const modelElement = editing.mapper.toModelElement(item);
|
|
1990
2000
|
// Do not select inline widgets.
|
|
1991
2001
|
if (!model.schema.isBlock(modelElement)) {
|
|
@@ -1996,16 +2006,26 @@ function selectionWillShrink(selection, isForward) {
|
|
|
1996
2006
|
return model.createRangeOn(modelElement);
|
|
1997
2007
|
}
|
|
1998
2008
|
} else if (item.is('editableElement')) {
|
|
2009
|
+
// Ignore the current editable for text selection,
|
|
2010
|
+
// but use it when widget was selected to be able to jump after the widget.
|
|
2011
|
+
if (item == editableElement && !selectedElement) {
|
|
2012
|
+
continue;
|
|
2013
|
+
}
|
|
1999
2014
|
const modelPosition = editing.mapper.toModelPosition(nextPosition);
|
|
2000
|
-
|
|
2015
|
+
const newRange = model.schema.getNearestSelectionRange(modelPosition, direction);
|
|
2001
2016
|
// There is nothing to select so just jump to the next one.
|
|
2002
2017
|
if (!newRange) {
|
|
2003
2018
|
continue;
|
|
2004
2019
|
}
|
|
2020
|
+
// In the same editable while widget was selected - do not select the editable content.
|
|
2021
|
+
if (item == editableElement && selectedElement) {
|
|
2022
|
+
return newRange;
|
|
2023
|
+
}
|
|
2005
2024
|
// Select the content of editable element when iterating over sibling editable elements
|
|
2006
2025
|
// or going deeper into nested widgets.
|
|
2007
2026
|
if (compareArrays(editablePath, item.getPath()) != 'extension') {
|
|
2008
|
-
|
|
2027
|
+
// Find a limit element closest to the new selection range.
|
|
2028
|
+
return model.createRangeIn(model.schema.getLimitElement(newRange));
|
|
2009
2029
|
}
|
|
2010
2030
|
return newRange;
|
|
2011
2031
|
}
|
|
@@ -2034,6 +2054,32 @@ function selectionWillShrink(selection, isForward) {
|
|
|
2034
2054
|
return true;
|
|
2035
2055
|
}
|
|
2036
2056
|
}
|
|
2057
|
+
/**
|
|
2058
|
+
* Returns true if there is an object on an edge of the given selection.
|
|
2059
|
+
*/ function hasObjectAtEdge(modelSelection, schema) {
|
|
2060
|
+
const firstPosition = modelSelection.getFirstPosition();
|
|
2061
|
+
const lastPosition = modelSelection.getLastPosition();
|
|
2062
|
+
const firstSelectedNode = firstPosition.nodeAfter;
|
|
2063
|
+
const lastSelectedNode = lastPosition.nodeBefore;
|
|
2064
|
+
return !!firstSelectedNode && schema.isObject(firstSelectedNode) || !!lastSelectedNode && schema.isObject(lastSelectedNode);
|
|
2065
|
+
}
|
|
2066
|
+
/**
|
|
2067
|
+
* Returns new instance of the model selection adjusted for fake caret and selection direction on widgets.
|
|
2068
|
+
*/ function getModelSelectionAdjusted(model, isForward) {
|
|
2069
|
+
const modelSelection = model.document.selection;
|
|
2070
|
+
const selectedElement = modelSelection.getSelectedElement();
|
|
2071
|
+
// Adjust selection for fake caret.
|
|
2072
|
+
const typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition(modelSelection);
|
|
2073
|
+
if (selectedElement && typeAroundFakeCaretPosition == 'before') {
|
|
2074
|
+
return model.createSelection(selectedElement, 'before');
|
|
2075
|
+
} else if (selectedElement && typeAroundFakeCaretPosition == 'after') {
|
|
2076
|
+
return model.createSelection(selectedElement, 'after');
|
|
2077
|
+
}
|
|
2078
|
+
// Make a copy of selection with adjusted direction for object selected.
|
|
2079
|
+
return model.createSelection(modelSelection.getRanges(), {
|
|
2080
|
+
backward: !!selectedElement && model.schema.isObject(selectedElement) ? !isForward : modelSelection.isBackward
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2037
2083
|
/**
|
|
2038
2084
|
* Finds the closest ancestor element that is either an editable element or a widget.
|
|
2039
2085
|
*
|