Skip to content

Commit

Permalink
Handle Up and Down in Table #2767
Browse files Browse the repository at this point in the history
  • Loading branch information
BryanValverdeU committed Aug 15, 2024
1 parent 97e65dd commit 024877f
Show file tree
Hide file tree
Showing 2 changed files with 224 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,13 @@ class SelectionPlugin implements PluginWithState<SelectionPluginState> {
key == Up ? td.childNodes.length : 0,
this.editor
);
} else if (!td && (lastCo.row == -1 || lastCo.row <= parsedTable.length)) {
this.selectBeforeOrAfterElement(
this.editor,
table,
change == 1 /* after */,
change != 1 /* setSelectionInNextSiblingElement */
);
}
} else if (key == 'TabLeft' || key == 'TabRight') {
const reverse = key == 'TabLeft';
Expand Down Expand Up @@ -568,15 +575,30 @@ class SelectionPlugin implements PluginWithState<SelectionPluginState> {
}
}

private selectBeforeOrAfterElement(editor: IEditor, element: HTMLElement, after?: boolean) {
private selectBeforeOrAfterElement(
editor: IEditor,
element: HTMLElement,
after?: boolean,
setSelectionInNextSiblingElement?: boolean
) {
const doc = editor.getDocument();
const parent = element.parentNode;
const index = parent && toArray(parent.childNodes).indexOf(element);
let sibling: Element | undefined | null;

if (parent && index !== null && index >= 0) {
const range = doc.createRange();
range.setStart(parent, index + (after ? 1 : 0));
range.collapse();
if (
setSelectionInNextSiblingElement &&
(sibling = after ? element.nextElementSibling : element.previousElementSibling) &&
isNodeOfType(sibling, 'ELEMENT_NODE')
) {
range.selectNodeContents(sibling);
range.collapse(false /* toStart */);
} else {
range.setStart(parent, index + (after ? 1 : 0));
range.collapse();
}

this.setDOMSelection(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1788,6 +1788,205 @@ describe('SelectionPlugin handle table selection', () => {
});
});

it('From Range, Press Down in the last row and move focus outside of table.', () => {
getDOMSelectionSpy.and.returnValue({
type: 'range',
range: {
startContainer: td3,
startOffset: 0,
endContainer: td3,
endOffset: 0,
commonAncestorContainer: tr2,
},
isReverted: false,
});

requestAnimationFrameSpy.and.callFake((func: Function) => {
getDOMSelectionSpy.and.returnValue({
type: 'range',
range: {
startContainer: td4,
startOffset: 0,
endContainer: td4,
endOffset: 0,
commonAncestorContainer: tr2,
collapsed: true,
},
isReverted: false,
});

func();
});

const setStartSpy = jasmine.createSpy('setStart');
const collapseSpy = jasmine.createSpy('collapse');
const mockedRange = {
setStart: setStartSpy,
collapse: collapseSpy,
} as any;

createRangeSpy.and.returnValue(mockedRange);

plugin.onPluginEvent!({
eventType: 'keyDown',
rawEvent: {
key: 'ArrowDown',
} as any,
});

expect(requestAnimationFrameSpy).toHaveBeenCalledTimes(1);
expect(plugin.getState()).toEqual({
selection: null,
tableSelection: null,
imageSelectionBorderColor: DEFAULT_SELECTION_BORDER_COLOR,
imageSelectionBorderColorDark: DEFAULT_SELECTION_BORDER_COLOR,
tableCellSelectionBackgroundColor: DEFAULT_TABLE_CELL_SELECTION_BACKGROUND_COLOR,
tableCellSelectionBackgroundColorDark: DEFAULT_TABLE_CELL_SELECTION_BACKGROUND_COLOR,
});
expect(setDOMSelectionSpy).toHaveBeenCalledTimes(1);
expect(setDOMSelectionSpy).toHaveBeenCalledWith({
type: 'range',
range: mockedRange,
isReverted: false,
});
expect(setStartSpy).toHaveBeenCalledWith(table.parentElement, 1);
});

it('From Range, Press Up in the first row and move focus outside of table, select before table as there are no elements before table.', () => {
getDOMSelectionSpy.and.returnValue({
type: 'range',
range: {
startContainer: td2,
startOffset: 0,
endContainer: td2,
endOffset: 0,
commonAncestorContainer: tr1,
},
isReverted: false,
});

requestAnimationFrameSpy.and.callFake((func: Function) => {
getDOMSelectionSpy.and.returnValue({
type: 'range',
range: {
startContainer: td1,
startOffset: 0,
endContainer: td1,
endOffset: 0,
commonAncestorContainer: tr1,
collapsed: true,
},
isReverted: false,
});

func();
});

const setStartSpy = jasmine.createSpy('setStart');
const collapseSpy = jasmine.createSpy('collapse');
const mockedRange = {
setStart: setStartSpy,
collapse: collapseSpy,
} as any;

createRangeSpy.and.returnValue(mockedRange);

plugin.onPluginEvent!({
eventType: 'keyDown',
rawEvent: {
key: 'ArrowUp',
} as any,
});

expect(requestAnimationFrameSpy).toHaveBeenCalledTimes(1);
expect(plugin.getState()).toEqual({
selection: null,
tableSelection: null,
imageSelectionBorderColor: DEFAULT_SELECTION_BORDER_COLOR,
imageSelectionBorderColorDark: DEFAULT_SELECTION_BORDER_COLOR,
tableCellSelectionBackgroundColor: DEFAULT_TABLE_CELL_SELECTION_BACKGROUND_COLOR,
tableCellSelectionBackgroundColorDark: DEFAULT_TABLE_CELL_SELECTION_BACKGROUND_COLOR,
});
expect(setDOMSelectionSpy).toHaveBeenCalledTimes(1);
expect(setDOMSelectionSpy).toHaveBeenCalledWith({
type: 'range',
range: mockedRange,
isReverted: false,
});
expect(setStartSpy).toHaveBeenCalledWith(table.parentElement, 0);
});

it('From Range, Press Up in the first row and move focus outside of table, select before table as there are no elements before table.', () => {
getDOMSelectionSpy.and.returnValue({
type: 'range',
range: {
startContainer: td2,
startOffset: 0,
endContainer: td2,
endOffset: 0,
commonAncestorContainer: tr1,
},
isReverted: false,
});

requestAnimationFrameSpy.and.callFake((func: Function) => {
getDOMSelectionSpy.and.returnValue({
type: 'range',
range: {
startContainer: td1,
startOffset: 0,
endContainer: td1,
endOffset: 0,
commonAncestorContainer: tr1,
collapsed: true,
},
isReverted: false,
});

func();
});

const setStartSpy = jasmine.createSpy('setStart');
const collapseSpy = jasmine.createSpy('collapse');
const selectNodeContentsSpy = jasmine.createSpy('selectNodeContents');

const mockedRange = {
setStart: setStartSpy,
collapse: collapseSpy,
selectNodeContents: selectNodeContentsSpy,
} as any;

const div = document.createElement('div');
table.parentElement?.insertBefore(div, table);
createRangeSpy.and.returnValue(mockedRange);

plugin.onPluginEvent!({
eventType: 'keyDown',
rawEvent: {
key: 'ArrowUp',
} as any,
});

expect(requestAnimationFrameSpy).toHaveBeenCalledTimes(1);
expect(plugin.getState()).toEqual({
selection: null,
tableSelection: null,
imageSelectionBorderColor: DEFAULT_SELECTION_BORDER_COLOR,
imageSelectionBorderColorDark: DEFAULT_SELECTION_BORDER_COLOR,
tableCellSelectionBackgroundColor: DEFAULT_TABLE_CELL_SELECTION_BACKGROUND_COLOR,
tableCellSelectionBackgroundColorDark: DEFAULT_TABLE_CELL_SELECTION_BACKGROUND_COLOR,
});
expect(setDOMSelectionSpy).toHaveBeenCalledTimes(1);
expect(setDOMSelectionSpy).toHaveBeenCalledWith({
type: 'range',
range: mockedRange,
isReverted: false,
});
expect(setStartSpy).not.toHaveBeenCalledWith(table.parentElement, 0);
expect(selectNodeContentsSpy).toHaveBeenCalledWith(div);
expect(collapseSpy).toHaveBeenCalledWith(false);
});

it('From Range, Press Shift+Up', () => {
getDOMSelectionSpy.and.returnValue({
type: 'range',
Expand Down

0 comments on commit 024877f

Please sign in to comment.