mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	Support grid selection with Ctrl+Shift+Arrow (#615)
This commit is contained in:
		
							parent
							
								
									f4d2c866d2
								
							
						
					
					
						commit
						cbdffdfff8
					
				@ -316,6 +316,20 @@ GridView.gridCommands = {
 | 
			
		||||
    this._shiftSelect(-1, this.cellSelector.col.end, selector.ROW,
 | 
			
		||||
                      this.viewSection.viewFields().peekLength - 1);
 | 
			
		||||
  },
 | 
			
		||||
  ctrlShiftDown: function () {
 | 
			
		||||
    this._shiftSelectUntilContent(selector.COL, 1, this.cellSelector.row.end, this.getLastDataRowIndex());
 | 
			
		||||
  },
 | 
			
		||||
  ctrlShiftUp: function () {
 | 
			
		||||
    this._shiftSelectUntilContent(selector.COL, -1, this.cellSelector.row.end, this.getLastDataRowIndex());
 | 
			
		||||
  },
 | 
			
		||||
  ctrlShiftRight: function () {
 | 
			
		||||
    this._shiftSelectUntilContent(selector.ROW, 1, this.cellSelector.col.end,
 | 
			
		||||
      this.viewSection.viewFields().peekLength - 1);
 | 
			
		||||
  },
 | 
			
		||||
  ctrlShiftLeft: function () {
 | 
			
		||||
    this._shiftSelectUntilContent(selector.ROW, -1, this.cellSelector.col.end,
 | 
			
		||||
      this.viewSection.viewFields().peekLength - 1);
 | 
			
		||||
  },
 | 
			
		||||
  fillSelectionDown: function() { this.fillSelectionDown(); },
 | 
			
		||||
  selectAll: function() { this.selectAll(); },
 | 
			
		||||
 | 
			
		||||
@ -403,6 +417,120 @@ GridView.prototype._shiftSelect = function(step, selectObs, exemptType, maxVal)
 | 
			
		||||
  selectObs(newVal);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GridView.prototype._shiftSelectUntilContent = function(type, direction, selectObs, maxVal) {
 | 
			
		||||
  const selection = {
 | 
			
		||||
    colStart: this.cellSelector.col.start(),
 | 
			
		||||
    colEnd: this.cellSelector.col.end(),
 | 
			
		||||
    rowStart: this.cellSelector.row.start(),
 | 
			
		||||
    rowEnd: this.cellSelector.row.end(),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const steps = this._stepsToContent(type, direction, selection, maxVal);
 | 
			
		||||
  if (steps > 0) { this._shiftSelect(direction * steps, selectObs, type, maxVal); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GridView.prototype._stepsToContent = function (type, direction, selection, maxVal) {
 | 
			
		||||
  const {colEnd: colEnd, rowEnd: rowEnd} = selection;
 | 
			
		||||
  let selectionData;
 | 
			
		||||
 | 
			
		||||
  const cursorCol = this.cursor.fieldIndex();
 | 
			
		||||
  const cursorRow = this.cursor.rowIndex();
 | 
			
		||||
 | 
			
		||||
  if (type === selector.ROW && direction > 0) {
 | 
			
		||||
    if (colEnd + 1 > maxVal) { return 0; }
 | 
			
		||||
 | 
			
		||||
    selectionData = this._selectionData({colStart: colEnd, colEnd: maxVal, rowStart: cursorRow, rowEnd: cursorRow});
 | 
			
		||||
  } else if (type === selector.ROW && direction < 0) {
 | 
			
		||||
    if (colEnd - 1 < 0) { return 0; }
 | 
			
		||||
 | 
			
		||||
    selectionData = this._selectionData({colStart: 0, colEnd, rowStart: cursorRow, rowEnd: cursorRow});
 | 
			
		||||
  } else if (type === selector.COL && direction > 0) {
 | 
			
		||||
    if (rowEnd + 1 > maxVal) { return 0; }
 | 
			
		||||
 | 
			
		||||
    selectionData = this._selectionData({colStart: cursorCol, colEnd: cursorCol, rowStart: rowEnd, rowEnd: maxVal});
 | 
			
		||||
  } else if (type === selector.COL && direction < 0) {
 | 
			
		||||
    if (rowEnd - 1 > maxVal) { return 0; }
 | 
			
		||||
 | 
			
		||||
    selectionData = this._selectionData({colStart: cursorCol, colEnd: cursorCol, rowStart: 0, rowEnd});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const {fields, rowIndices} = selectionData;
 | 
			
		||||
  if (type === selector.ROW && direction < 0) {
 | 
			
		||||
    // When moving selection left, we step through fields in reverse order.
 | 
			
		||||
    fields.reverse();
 | 
			
		||||
  }
 | 
			
		||||
  if (type === selector.COL && direction < 0) {
 | 
			
		||||
    // When moving selection up, we step through rows in reverse order.
 | 
			
		||||
    rowIndices.reverse();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const colValuesByIndex = {};
 | 
			
		||||
  for (const field of fields) {
 | 
			
		||||
    const displayColId = field.displayColModel.peek().colId.peek();
 | 
			
		||||
    colValuesByIndex[field._index()] = this.tableModel.tableData.getColValues(displayColId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let steps = 0;
 | 
			
		||||
 | 
			
		||||
  if (type === selector.ROW) {
 | 
			
		||||
    const rowIndex = rowIndices[0];
 | 
			
		||||
    const isLastColEmpty = this._isCellValueEmpty(colValuesByIndex[colEnd][rowIndex]);
 | 
			
		||||
    const isNextColEmpty = this._isCellValueEmpty(colValuesByIndex[colEnd + direction][rowIndex]);
 | 
			
		||||
    const shouldStopOnEmptyValue = !isLastColEmpty && !isNextColEmpty;
 | 
			
		||||
    for (let i = 1; i < fields.length; i++) {
 | 
			
		||||
      const hasEmptyValues = this._isCellValueEmpty(colValuesByIndex[fields[i]._index()][rowIndex]);
 | 
			
		||||
      if (hasEmptyValues && shouldStopOnEmptyValue) {
 | 
			
		||||
        return steps;
 | 
			
		||||
      } else if (!hasEmptyValues && !shouldStopOnEmptyValue) {
 | 
			
		||||
        return steps + 1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      steps += 1;
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    const colValues = colValuesByIndex[fields[0]._index()];
 | 
			
		||||
    const isLastRowEmpty = this._isCellValueEmpty(colValues[rowIndices[0]]);
 | 
			
		||||
    const isNextRowEmpty = this._isCellValueEmpty(colValues[rowIndices[1]]);
 | 
			
		||||
    const shouldStopOnEmptyValue = !isLastRowEmpty && !isNextRowEmpty;
 | 
			
		||||
    for (let i = 1; i < rowIndices.length; i++) {
 | 
			
		||||
      const hasEmptyValues = this._isCellValueEmpty(colValues[rowIndices[i]]);
 | 
			
		||||
      if (hasEmptyValues && shouldStopOnEmptyValue) {
 | 
			
		||||
        return steps;
 | 
			
		||||
      } else if (!hasEmptyValues && !shouldStopOnEmptyValue) {
 | 
			
		||||
        return steps + 1;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      steps += 1;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return steps;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GridView.prototype._selectionData = function({colStart, colEnd, rowStart, rowEnd}) {
 | 
			
		||||
  const fields = [];
 | 
			
		||||
  for (let i = colStart; i <= colEnd; i++) {
 | 
			
		||||
    const field = this.viewSection.viewFields().at(i);
 | 
			
		||||
    if (!field) { continue; }
 | 
			
		||||
 | 
			
		||||
    fields.push(field);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const rowIndices = [];
 | 
			
		||||
  for (let i = rowStart; i <= rowEnd; i++) {
 | 
			
		||||
    const rowId = this.viewData.getRowId(i);
 | 
			
		||||
    if (!rowId) { continue; }
 | 
			
		||||
 | 
			
		||||
    rowIndices.push(this.tableModel.tableData.getRowIdIndex(rowId));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {fields, rowIndices};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GridView.prototype._isCellValueEmpty = function(value) {
 | 
			
		||||
  return value === null || value === undefined || value === '' || value === 'false';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Pastes the provided data at the current cursor.
 | 
			
		||||
 *
 | 
			
		||||
@ -532,15 +660,15 @@ GridView.prototype.fillSelectionDown = function() {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns a GridSelection of the selected rows and cols
 | 
			
		||||
 * Returns a CopySelection of the selected rows and cols
 | 
			
		||||
 * @returns {Object} CopySelection
 | 
			
		||||
 */
 | 
			
		||||
GridView.prototype.getSelection = function() {
 | 
			
		||||
  var rowIds = [], fields = [], rowStyle = {}, colStyle = {};
 | 
			
		||||
  var colStart = this.cellSelector.colLower();
 | 
			
		||||
  var colEnd = this.cellSelector.colUpper();
 | 
			
		||||
  var rowStart = this.cellSelector.rowLower();
 | 
			
		||||
  var rowEnd = this.cellSelector.rowUpper();
 | 
			
		||||
  let rowIds = [], fields = [], rowStyle = {}, colStyle = {};
 | 
			
		||||
  let colStart = this.cellSelector.colLower();
 | 
			
		||||
  let colEnd = this.cellSelector.colUpper();
 | 
			
		||||
  let rowStart = this.cellSelector.rowLower();
 | 
			
		||||
  let rowEnd = this.cellSelector.rowUpper();
 | 
			
		||||
 | 
			
		||||
  // If there is no selection, just copy/paste the cursor cell
 | 
			
		||||
  if (this.cellSelector.isCurrentSelectType(selector.NONE)) {
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,10 @@ export type CommandName =
 | 
			
		||||
  | 'shiftUp'
 | 
			
		||||
  | 'shiftRight'
 | 
			
		||||
  | 'shiftLeft'
 | 
			
		||||
  | 'ctrlShiftDown'
 | 
			
		||||
  | 'ctrlShiftUp'
 | 
			
		||||
  | 'ctrlShiftRight'
 | 
			
		||||
  | 'ctrlShiftLeft'
 | 
			
		||||
  | 'selectAll'
 | 
			
		||||
  | 'copyLink'
 | 
			
		||||
  | 'editField'
 | 
			
		||||
@ -373,6 +377,22 @@ export const groups: CommendGroupDef[] = [{
 | 
			
		||||
     name: 'shiftLeft',
 | 
			
		||||
     keys: ['Shift+Left'],
 | 
			
		||||
     desc: 'Adds the element to the left of the cursor to the selected range'
 | 
			
		||||
    }, {
 | 
			
		||||
      name: 'ctrlShiftDown',
 | 
			
		||||
      keys: ['Mod+Shift+Down'],
 | 
			
		||||
      desc: 'Adds all elements below the cursor to the selected range'
 | 
			
		||||
    }, {
 | 
			
		||||
      name: 'ctrlShiftUp',
 | 
			
		||||
      keys: ['Mod+Shift+Up'],
 | 
			
		||||
      desc: 'Adds all elements above the cursor to the selected range'
 | 
			
		||||
    }, {
 | 
			
		||||
      name: 'ctrlShiftRight',
 | 
			
		||||
      keys: ['Mod+Shift+Right'],
 | 
			
		||||
      desc: 'Adds all elements to the right of the cursor to the selected range'
 | 
			
		||||
    }, {
 | 
			
		||||
      name: 'ctrlShiftLeft',
 | 
			
		||||
      keys: ['Mod+Shift+Left'],
 | 
			
		||||
      desc: 'Adds all elements to the left of the cursor to the selected range'
 | 
			
		||||
    }, {
 | 
			
		||||
      name: 'selectAll',
 | 
			
		||||
      keys: ['Mod+A'],
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								test/fixtures/docs/ShiftSelection.grist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								test/fixtures/docs/ShiftSelection.grist
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										213
									
								
								test/nbrowser/ShiftSelection.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								test/nbrowser/ShiftSelection.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,213 @@
 | 
			
		||||
import {assert, driver, Key, WebElement} from 'mocha-webdriver';
 | 
			
		||||
import * as gu from 'test/nbrowser/gristUtils';
 | 
			
		||||
import {setupTestSuite} from 'test/nbrowser/testUtils';
 | 
			
		||||
 | 
			
		||||
interface CellSelection {
 | 
			
		||||
  /** 0-based column index. */
 | 
			
		||||
  colStart: number;
 | 
			
		||||
 | 
			
		||||
  /** 0-based column index. */
 | 
			
		||||
  colEnd: number;
 | 
			
		||||
 | 
			
		||||
  /** 0-based row index. */
 | 
			
		||||
  rowStart: number;
 | 
			
		||||
 | 
			
		||||
  /** 0-based row index. */
 | 
			
		||||
  rowEnd: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface SelectionRange {
 | 
			
		||||
  /** 0-based index. */
 | 
			
		||||
  start: number;
 | 
			
		||||
 | 
			
		||||
  /** 0-based index. */
 | 
			
		||||
  end: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
describe('ShiftSelection', function () {
 | 
			
		||||
  this.timeout(20000);
 | 
			
		||||
  const cleanup = setupTestSuite();
 | 
			
		||||
  gu.bigScreen();
 | 
			
		||||
 | 
			
		||||
  before(async function() {
 | 
			
		||||
    const session = await gu.session().personalSite.login();
 | 
			
		||||
    await session.tempDoc(cleanup, 'ShiftSelection.grist');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  async function getSelectionRange(parent: WebElement, selector: string): Promise<SelectionRange|undefined> {
 | 
			
		||||
    let start, end;
 | 
			
		||||
 | 
			
		||||
    let selectionActive = false;
 | 
			
		||||
    const elements = await parent.findAll(selector);
 | 
			
		||||
    for (let i = 0; i < elements.length; i++) {
 | 
			
		||||
      const element = elements[i];
 | 
			
		||||
      const isSelected = await element.matches('.selected');
 | 
			
		||||
 | 
			
		||||
      if (isSelected && !selectionActive) {
 | 
			
		||||
        start = i;
 | 
			
		||||
        selectionActive = true;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!isSelected && selectionActive) {
 | 
			
		||||
        end = i - 1;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (start === undefined) {
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (end === undefined) {
 | 
			
		||||
      end = elements.length - 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      start: start,
 | 
			
		||||
      end: end,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function getSelectedCells(): Promise<CellSelection|undefined> {
 | 
			
		||||
    const activeSection = await driver.find('.active_section');
 | 
			
		||||
 | 
			
		||||
    const colSelection = await getSelectionRange(activeSection, '.column_names .column_name');
 | 
			
		||||
    if (!colSelection) {
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const rowSelection = await getSelectionRange(activeSection, '.gridview_row .gridview_data_row_num');
 | 
			
		||||
    if (!rowSelection) {
 | 
			
		||||
      // Edge case if only a cell in the "new" row is selected
 | 
			
		||||
      // Not relevant for our tests
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      colStart: colSelection.start,
 | 
			
		||||
      colEnd: colSelection.end,
 | 
			
		||||
      rowStart: rowSelection.start,
 | 
			
		||||
      rowEnd: rowSelection.end,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function assertCellSelection(expected: CellSelection|undefined) {
 | 
			
		||||
    const currentSelection = await getSelectedCells();
 | 
			
		||||
    assert.deepEqual(currentSelection, expected);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  it('Shift+Up extends the selection up', async function () {
 | 
			
		||||
    await gu.getCell(1, 2).click();
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.UP));
 | 
			
		||||
    await assertCellSelection({colStart: 1, colEnd: 1, rowStart: 0, rowEnd: 1});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Shift+Down extends the selection down', async function () {
 | 
			
		||||
    await gu.getCell(1, 2).click();
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.DOWN));
 | 
			
		||||
    await assertCellSelection({colStart: 1, colEnd: 1, rowStart: 1, rowEnd: 2});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Shift+Left extends the selection left', async function () {
 | 
			
		||||
    await gu.getCell(1, 2).click();
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.LEFT));
 | 
			
		||||
    await assertCellSelection({colStart: 0, colEnd: 1, rowStart: 1, rowEnd: 1});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Shift+Right extends the selection right', async function () {
 | 
			
		||||
    await gu.getCell(1, 2).click();
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.RIGHT));
 | 
			
		||||
    await assertCellSelection({colStart: 1, colEnd: 2, rowStart: 1, rowEnd: 1});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Shift+Right + Shift+Left leads to the initial selection', async function () {
 | 
			
		||||
    await gu.getCell(1, 2).click();
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.RIGHT));
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.LEFT));
 | 
			
		||||
    await assertCellSelection({colStart: 1, colEnd: 1, rowStart: 1, rowEnd: 1});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Shift+Up + Shift+Down leads to the initial selection', async function () {
 | 
			
		||||
    await gu.getCell(1, 2).click();
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.UP));
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.DOWN));
 | 
			
		||||
    await assertCellSelection({colStart: 1, colEnd: 1, rowStart: 1, rowEnd: 1});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Ctrl+Shift+Up extends the selection blockwise up', async function () {
 | 
			
		||||
    await gu.getCell(5, 7).click();
 | 
			
		||||
 | 
			
		||||
    const ctrlKey = await gu.modKey();
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.UP));
 | 
			
		||||
    await assertCellSelection({colStart: 5, colEnd: 5, rowStart: 4, rowEnd: 6});
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.UP));
 | 
			
		||||
    await assertCellSelection({colStart: 5, colEnd: 5, rowStart: 2, rowEnd: 6});
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.UP));
 | 
			
		||||
    await assertCellSelection({colStart: 5, colEnd: 5, rowStart: 0, rowEnd: 6});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Ctrl+Shift+Down extends the selection blockwise down', async function () {
 | 
			
		||||
    await gu.getCell(5, 5).click();
 | 
			
		||||
 | 
			
		||||
    const ctrlKey = await gu.modKey();
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.DOWN));
 | 
			
		||||
    await assertCellSelection({colStart: 5, colEnd: 5, rowStart: 4, rowEnd: 6});
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.DOWN));
 | 
			
		||||
    await assertCellSelection({colStart: 5, colEnd: 5, rowStart: 4, rowEnd: 8});
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.DOWN));
 | 
			
		||||
    await assertCellSelection({colStart: 5, colEnd: 5, rowStart: 4, rowEnd: 10});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Ctrl+Shift+Left extends the selection blockwise left', async function () {
 | 
			
		||||
    await gu.getCell(6, 5).click();
 | 
			
		||||
 | 
			
		||||
    const ctrlKey = await gu.modKey();
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.LEFT));
 | 
			
		||||
    await assertCellSelection({colStart: 4, colEnd: 6, rowStart: 4, rowEnd: 4});
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.LEFT));
 | 
			
		||||
    await assertCellSelection({colStart: 2, colEnd: 6, rowStart: 4, rowEnd: 4});
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.LEFT));
 | 
			
		||||
    await assertCellSelection({colStart: 0, colEnd: 6, rowStart: 4, rowEnd: 4});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Ctrl+Shift+Right extends the selection blockwise right', async function () {
 | 
			
		||||
    await gu.getCell(4, 5).click();
 | 
			
		||||
 | 
			
		||||
    const ctrlKey = await gu.modKey();
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.RIGHT));
 | 
			
		||||
    await assertCellSelection({colStart: 4, colEnd: 6, rowStart: 4, rowEnd: 4});
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.RIGHT));
 | 
			
		||||
    await assertCellSelection({colStart: 4, colEnd: 8, rowStart: 4, rowEnd: 4});
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.RIGHT));
 | 
			
		||||
    await assertCellSelection({colStart: 4, colEnd: 10, rowStart: 4, rowEnd: 4});
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('Ctrl+Shift+* extends the selection until all the next cells are empty', async function () {
 | 
			
		||||
    await gu.getCell(3, 7).click();
 | 
			
		||||
 | 
			
		||||
    const ctrlKey = await gu.modKey();
 | 
			
		||||
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.RIGHT));
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.UP));
 | 
			
		||||
    await assertCellSelection({colStart: 3, colEnd: 4, rowStart: 2, rowEnd: 6});
 | 
			
		||||
 | 
			
		||||
    await gu.getCell(4, 7).click();
 | 
			
		||||
    await gu.sendKeys(Key.chord(Key.SHIFT, Key.LEFT));
 | 
			
		||||
    await gu.sendKeys(Key.chord(ctrlKey, Key.SHIFT, Key.UP));
 | 
			
		||||
    await assertCellSelection({colStart: 3, colEnd: 4, rowStart: 4, rowEnd: 6});
 | 
			
		||||
  });
 | 
			
		||||
 });
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user