@ckeditor/ckeditor5-widget 46.1.1 → 47.0.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/dist/index.js CHANGED
@@ -5,7 +5,7 @@
5
5
  import { Plugin } from '@ckeditor/ckeditor5-core/dist/index.js';
6
6
  import { MouseObserver, PointerObserver, ModelTreeWalker } from '@ckeditor/ckeditor5-engine/dist/index.js';
7
7
  import { Delete } from '@ckeditor/ckeditor5-typing/dist/index.js';
8
- import { EmitterMixin, Rect, CKEditorError, toArray, isForwardArrowKeyCode, env, keyCodes, getLocalizedArrowKeyCodeDirection, getRangeFromMouseEvent, logWarning, ObservableMixin, compareArrays, global, DomEmitterMixin } from '@ckeditor/ckeditor5-utils/dist/index.js';
8
+ import { EmitterMixin, Rect, CKEditorError, toArray, isForwardArrowKeyCode, env, keyCodes, getLocalizedArrowKeyCodeDirection, compareArrays, getRangeFromMouseEvent, logWarning, ObservableMixin, global, DomEmitterMixin } from '@ckeditor/ckeditor5-utils/dist/index.js';
9
9
  import { IconDragHandle, IconReturnArrow } from '@ckeditor/ckeditor5-icons/dist/index.js';
10
10
  import { IconView, Template, ContextualBalloon, ToolbarView, BalloonPanelView, View } from '@ckeditor/ckeditor5-ui/dist/index.js';
11
11
  import { Enter } from '@ckeditor/ckeditor5-enter/dist/index.js';
@@ -1375,27 +1375,25 @@ function injectFakeCaret(wrapperDomElement) {
1375
1375
  const endPosition = getNearestNonInlineLimit(model, startPosition, 'forward');
1376
1376
  // There is no limit element, browser should handle this.
1377
1377
  if (!endPosition) {
1378
- return null;
1378
+ return;
1379
1379
  }
1380
1380
  const range = model.createRange(startPosition, endPosition);
1381
1381
  const lastRangePosition = getNearestTextPosition(model.schema, range, 'backward');
1382
1382
  if (lastRangePosition) {
1383
1383
  return model.createRange(startPosition, lastRangePosition);
1384
1384
  }
1385
- return null;
1386
1385
  } else {
1387
1386
  const endPosition = selection.isCollapsed ? selection.focus : selection.getFirstPosition();
1388
1387
  const startPosition = getNearestNonInlineLimit(model, endPosition, 'backward');
1389
1388
  // There is no limit element, browser should handle this.
1390
1389
  if (!startPosition) {
1391
- return null;
1390
+ return;
1392
1391
  }
1393
1392
  const range = model.createRange(startPosition, endPosition);
1394
1393
  const firstRangePosition = getNearestTextPosition(model.schema, range, 'forward');
1395
1394
  if (firstRangePosition) {
1396
1395
  return model.createRange(firstRangePosition, endPosition);
1397
1396
  }
1398
- return null;
1399
1397
  }
1400
1398
  }
1401
1399
  /**
@@ -1441,7 +1439,6 @@ function injectFakeCaret(wrapperDomElement) {
1441
1439
  return nextPosition;
1442
1440
  }
1443
1441
  }
1444
- return null;
1445
1442
  }
1446
1443
  /**
1447
1444
  * Checks if the DOM range corresponding to the provided model range renders as a single line by analyzing DOMRects
@@ -1636,34 +1633,15 @@ function selectionWillShrink(selection, isForward) {
1636
1633
  }, {
1637
1634
  context: '$root'
1638
1635
  });
1639
- // Handle Tab key while a widget is selected.
1640
- this.listenTo(viewDocument, 'tab', (evt, data)=>{
1641
- // This event could be triggered from inside the widget, but we are interested
1642
- // only when the widget is selected itself.
1643
- if (evt.eventPhase != 'atTarget') {
1644
- return;
1645
- }
1646
- if (data.shiftKey) {
1647
- return;
1648
- }
1649
- if (this._selectFirstNestedEditable()) {
1650
- data.preventDefault();
1651
- evt.stop();
1652
- }
1653
- }, {
1654
- context: isWidget,
1655
- priority: 'low'
1656
- });
1657
- // Handle Shift+Tab key while caret inside a widget editable.
1636
+ // Handle Tab/Shift+Tab key.
1658
1637
  this.listenTo(viewDocument, 'tab', (evt, data)=>{
1659
- if (!data.shiftKey) {
1660
- return;
1661
- }
1662
- if (this._selectAncestorWidget()) {
1638
+ if (this._selectNextEditable(data.shiftKey ? 'backward' : 'forward')) {
1639
+ view.scrollToTheSelection();
1663
1640
  data.preventDefault();
1664
1641
  evt.stop();
1665
1642
  }
1666
1643
  }, {
1644
+ context: (node)=>isWidget(node) || node.is('editableElement'),
1667
1645
  priority: 'low'
1668
1646
  });
1669
1647
  // Handle Esc key while inside a nested editable.
@@ -1955,26 +1933,84 @@ function selectionWillShrink(selection, isForward) {
1955
1933
  this._previouslySelected.clear();
1956
1934
  }
1957
1935
  /**
1958
- * Moves the document selection into the first nested editable.
1959
- */ _selectFirstNestedEditable() {
1960
- const editor = this.editor;
1961
- const view = this.editor.editing.view;
1962
- const viewDocument = view.document;
1963
- for (const item of viewDocument.selection.getFirstRange().getItems()){
1964
- if (item.is('editableElement')) {
1965
- const modelElement = editor.editing.mapper.toModelElement(item);
1966
- /* istanbul ignore next -- @preserve */ if (!modelElement) {
1936
+ * Moves the document selection into the next editable or block widget.
1937
+ */ _selectNextEditable(direction) {
1938
+ const editing = this.editor.editing;
1939
+ const view = editing.view;
1940
+ const model = this.editor.model;
1941
+ const viewSelection = view.document.selection;
1942
+ const modelSelection = model.document.selection;
1943
+ // Find start position.
1944
+ let startPosition;
1945
+ // Multiple table cells are selected - use focus cell.
1946
+ if (modelSelection.rangeCount > 1) {
1947
+ const selectionRange = modelSelection.isBackward ? modelSelection.getFirstRange() : modelSelection.getLastRange();
1948
+ startPosition = editing.mapper.toViewPosition(direction == 'forward' ? selectionRange.end : selectionRange.start);
1949
+ } else {
1950
+ startPosition = direction == 'forward' ? viewSelection.getFirstPosition() : viewSelection.getLastPosition();
1951
+ }
1952
+ const modelRange = this._findNextFocusRange(startPosition, direction);
1953
+ if (modelRange) {
1954
+ model.change((writer)=>{
1955
+ writer.setSelection(modelRange);
1956
+ });
1957
+ return true;
1958
+ }
1959
+ return false;
1960
+ }
1961
+ /**
1962
+ * Looks for next focus point in the document starting from the given view position and direction.
1963
+ * The focus point is either a block widget or an editable.
1964
+ *
1965
+ * @internal
1966
+ */ _findNextFocusRange(startPosition, direction) {
1967
+ const editing = this.editor.editing;
1968
+ const view = editing.view;
1969
+ const model = this.editor.model;
1970
+ const viewSelection = view.document.selection;
1971
+ const editableElement = viewSelection.editableElement;
1972
+ const editablePath = editableElement.getPath();
1973
+ let selectedElement = viewSelection.getSelectedElement();
1974
+ if (selectedElement && !isWidget(selectedElement)) {
1975
+ selectedElement = null;
1976
+ }
1977
+ // Look for the next editable.
1978
+ const viewRange = direction == 'forward' ? view.createRange(startPosition, view.createPositionAt(startPosition.root, 'end')) : view.createRange(view.createPositionAt(startPosition.root, 0), startPosition);
1979
+ for (const { nextPosition } of viewRange.getWalker({
1980
+ direction
1981
+ })){
1982
+ const item = nextPosition.parent;
1983
+ // Ignore currently selected editable or widget.
1984
+ if (item == editableElement || item == selectedElement) {
1985
+ continue;
1986
+ }
1987
+ // Some widget along the way.
1988
+ if (isWidget(item)) {
1989
+ const modelElement = editing.mapper.toModelElement(item);
1990
+ // Do not select inline widgets.
1991
+ if (!model.schema.isBlock(modelElement)) {
1967
1992
  continue;
1968
1993
  }
1969
- const position = editor.model.createPositionAt(modelElement, 0);
1970
- const newRange = editor.model.schema.getNearestSelectionRange(position, 'forward');
1971
- editor.model.change((writer)=>{
1972
- writer.setSelection(newRange);
1973
- });
1974
- return true;
1994
+ // Do not select widget itself when going out of widget or iterating over sibling elements in a widget.
1995
+ if (compareArrays(editablePath, item.getPath()) != 'extension') {
1996
+ return model.createRangeOn(modelElement);
1997
+ }
1998
+ } else if (item.is('editableElement')) {
1999
+ const modelPosition = editing.mapper.toModelPosition(nextPosition);
2000
+ let newRange = model.schema.getNearestSelectionRange(modelPosition, direction);
2001
+ // There is nothing to select so just jump to the next one.
2002
+ if (!newRange) {
2003
+ continue;
2004
+ }
2005
+ // Select the content of editable element when iterating over sibling editable elements
2006
+ // or going deeper into nested widgets.
2007
+ if (compareArrays(editablePath, item.getPath()) != 'extension') {
2008
+ newRange = model.createRangeIn(modelPosition.parent);
2009
+ }
2010
+ return newRange;
1975
2011
  }
1976
2012
  }
1977
- return false;
2013
+ return null;
1978
2014
  }
1979
2015
  /**
1980
2016
  * Updates the document selection so that it selects first ancestor widget.