Navigation

SpreadJS supports navigation actions defined in GC.Spread.Sheets.Commands. These actions allow you to navigate the Spread instance in script code without needing to have the user do it.

Description
app.vue
index.html
Copy to CodeMine

This can be useful when you have business logic that may depend on navigating in the Spread instance.

  • moveToNextCell: Moves to next cell (default action of Tab).
  • moveToPreviousCell: Moves to previous cell (default action of Shift + Tab).
  • selectNextControl: Selects spread.nextControl specified element or auto detected one if not set.
  • selectPreviousControl: Selects spread.previousControl specified element or auto detected one if not set.
  • moveToNextCellThenControl: Moves to next cell if the active cell is the last visible cell, then selects next control.
  • moveToPreviousCellThenControl: Moves to previous cell if the active cell is the first visible cell, then selects previous control.

Set the selected control using the nextControl and previousControl methods. For example:

    // set next & previous control
    spread.nextControl(document.getElementById('myNextControl'));
    spread.previousControl(document.getElementById('myPreviousControl'));

    // set the value to undefined without using auto detect
    spread.nextControl(undefined);

Spread allows creating custom commands. For example:

    // register a custom command called "customSelectLeft",it use customSelectLeft function as its execution function.
    commandManager.register("customSelectLeft", customSelectLeft);
    // command's execution function accept two arguments
    function customSelectLeft(context, options) {
        /* codes... */
    }

Use the register method to set navigation keys and the corresponding actions. For example:

    // set Tab to select next control
    spread.commandManager().register('selectNextControl', GC.Spread.Sheets.Commands.selectNextControl, GC.Spread.Commands.Key.tab, false, false, false, false);
    // set Shift + Tab to select previous control
    spread.commandManager().register('selectPreviousControl', GC.Spread.Sheets.Commands.selectPreviousControl, GC.Spread.Commands.Key.tab, false, true, false, false);
    // clear old commands that related to Ctrl + Shift + Left
    commandManager.setShortcutKey(null, GC.Spread.Commands.Key.left, true, true, false, false);
    // set Ctrl + Shift + Left to customSelectLeft command
    commandManager.setShortcutKey("customSelectLeft", GC.Spread.Commands.Key.left, true, true, false, false);

The arguments of register in order are:

  • name: The name of the command.
  • execute: The execution function of the command.
  • key: The unicode for the key.
  • ctrl: True if the action uses the Ctrl key; otherwise, false.
  • shift: True if the action uses the Shift key; otherwise, false.
  • alt: True if the action uses the Alt key; otherwise, false.
  • meta: True if the action uses the Command key on the Macintosh or the Windows key on Microsoft Windows; otherwise, false.

Use the hideSelection option to hide the selection when Spread loses the focus. For example:

    spread.options.hideSelection = true;
This can be useful when you have business logic that may depend on navigating in the Spread instance. moveToNextCell: Moves to next cell (default action of Tab). moveToPreviousCell: Moves to previous cell (default action of Shift + Tab). selectNextControl: Selects spread.nextControl specified element or auto detected one if not set. selectPreviousControl: Selects spread.previousControl specified element or auto detected one if not set. moveToNextCellThenControl: Moves to next cell if the active cell is the last visible cell, then selects next control. moveToPreviousCellThenControl: Moves to previous cell if the active cell is the first visible cell, then selects previous control. Set the selected control using the nextControl and previousControl methods. For example: Spread allows creating custom commands. For example: Use the register method to set navigation keys and the corresponding actions. For example: The arguments of register in order are: name: The name of the command. execute: The execution function of the command. key: The unicode for the key. ctrl: True if the action uses the Ctrl key; otherwise, false. shift: True if the action uses the Shift key; otherwise, false. alt: True if the action uses the Alt key; otherwise, false. meta: True if the action uses the Command key on the Macintosh or the Windows key on Microsoft Windows; otherwise, false. Use the hideSelection option to hide the selection when Spread loses the focus. For example:
<template> <div class="sample-tutorial"> <gc-spread-sheets class="sample-spreadsheets" @workbookInitialized="initSpread"> <gc-worksheet /> </gc-spread-sheets> <div class="options-container"> <p>Change the “Tab for:” field to “Next Control” then click the Spread instance to give it focus.</p> <p>Hit the Tab key and observe that the focus moves to the “Previous Edit” text box on this page.</p> <p>You can utilize this functionality to change what specific navigation keys do in Spread.</p> <div class="option-row" style="margin-bottom: 10px;"> <input type="text" id="preEdit" placeholder="Previous Edit" title="Candidate previous control" /> <input type="button" id="preButton" title="Candidate previous control too" value="Previous Button" @click="_alertHandle" /> </div> <div class="option-row"> <input type="text" id="nextEdit" placeholder="Next Edit" title="Candidate next control" /> <input type="button" id="nextButton" title="Candidate next control too" value="Next Button" @click="_alertHandle" /> </div> <div class="option-row"> <label>Tab for:</label> <select id="tabAction" @change="_moveHandle"> <option value="0" selected="selected">Next cell</option> <option value="1">Next control</option> <option value="2">Next cell then control</option> </select> <label class="colorLabel">This controls which navigation action happens when the user presses Tab.</label> </div> <div class="option-row"> <label>Shift + Tab for:</label> <select id="shiftTabAction" @change="_moveHandle"> <option value="0" selected="selected">Previous cell</option> <option value="1">Previous control</option> <option value="2">Previous cell then control</option> </select> <label class="colorLabel">This controls which navigation action happens when the user presses Shift+Tab.</label> </div> <div class="option-row"> <label>Next control:</label> <select id="nextControl" @change="_handle"> <option value="" selected="selected">Not set (auto detect)</option> <option value="nextEdit">Next Edit</option> <option value="nextButton">Next Button</option> </select> <label class="colorLabel">This defines which control is the next control in relation to the Spread instance.</label> </div> <div class="option-row"> <label>Previous control:</label> <select id="preControl" @change="_handle"> <option value="" selected="selected">Not set (auto detect)</option> <option value="preEdit">Previous Edit</option> <option value="preButton">Previous Button</option> </select> <label class="colorLabel">This defines which control is the previous control in relation to the Spread instance.</label> </div> <div class="option-row"> <input type="checkbox" id="hideSelection" @change="hideSelection" /> <label for="hideSelection">Hide Selection</label> <label class="colorLabel">Checking this box will hide the selection in the Spread instance.</label> </div> </div> </div> </template> <script setup> import { ref } from 'vue'; import '@mescius/spread-sheets-vue'; import GC from '@mescius/spread-sheets'; const spread = ref(null); const initSpread = (spreadInstance) => { spread.value = spreadInstance; spreadInstance.suspendPaint(); const sheet = spreadInstance.getSheet(0); sheet.setRowCount(20); sheet.setColumnCount(10); sheet.addSpan(0, 0, 1, 7); sheet.setValue(0, 0, "press the 'Tab' or 'Shift + Tab' key, the selection will move in accordance."); for (let i = 1; i < 20; i += 3) { for (let j = 1; j < 20; j += 3) { sheet.setValue(i, j, "Test"); } } spreadInstance.resumePaint(); const commandManager = spreadInstance.commandManager(); function customSelectLeft(workbook, options) { const sheet = workbook.getSheetFromName(options.sheetName); const activeRowIndex = sheet.getActiveRowIndex(); const activeColIndex = sheet.getActiveColumnIndex(); const selNeedAdjust = getNeedAdjustSelection(sheet.getSelections(), activeRowIndex, activeColIndex); function findFirstNotNullColIndex(sheet, fixRow, offset, stop) { while (offset > stop) { if (sheet.getValue(fixRow, offset) !== null) { break; } offset--; } return offset; } const rangeChangeSmall = selNeedAdjust.col === activeColIndex && selNeedAdjust.colCount > 1 ? true : false; const stopSearchIndex = rangeChangeSmall ? activeColIndex : 0; const startSearchIndex = rangeChangeSmall ? selNeedAdjust.col + selNeedAdjust.colCount - 1 - 1 : selNeedAdjust.col - 1; const findResult = findFirstNotNullColIndex(sheet, activeRowIndex, startSearchIndex, stopSearchIndex); if (selNeedAdjust !== null && findResult >= 0) { selNeedAdjust.colCount = rangeChangeSmall ? findResult - selNeedAdjust.col + 1 : selNeedAdjust.col - findResult + selNeedAdjust.colCount; selNeedAdjust.col = rangeChangeSmall ? selNeedAdjust.col : findResult; sheet.repaint(); } } function customSelectRight(workbook, options) { const sheet = workbook.getSheetFromName(options.sheetName); const activeRowIndex = sheet.getActiveRowIndex(); const activeColIndex = sheet.getActiveColumnIndex(); const sheetColCount = sheet.getColumnCount(); const selNeedAdjust = getNeedAdjustSelection(sheet.getSelections(), activeRowIndex, activeColIndex); function findNextNotNullColIndex(sheet, fixRow, offset, stop) { while (offset < stop) { if (sheet.getValue(offset, fixRow) !== null) { break; } offset++; } return offset; } const rangeChangeSmall = selNeedAdjust.col + selNeedAdjust.colCount - 1 === activeColIndex && selNeedAdjust.colCount > 1 ? true : false; const stopSearchIndex = rangeChangeSmall ? activeColIndex : sheetColCount; const startSearchIndex = rangeChangeSmall ? selNeedAdjust.col + 1 : selNeedAdjust.col + selNeedAdjust.colCount; const findResult = findNextNotNullColIndex(sheet, activeRowIndex, startSearchIndex, stopSearchIndex); if (selNeedAdjust !== null && findResult <= sheetColCount) { selNeedAdjust.colCount = rangeChangeSmall ? selNeedAdjust.colCount + selNeedAdjust.col - findResult : findResult - selNeedAdjust.col + 1; selNeedAdjust.col = rangeChangeSmall ? findResult : selNeedAdjust.col; sheet.repaint(); } } function customSelectUp(workbook, options) { const sheet = workbook.getSheetFromName(options.sheetName); const activeRowIndex = sheet.getActiveRowIndex(); const activeColIndex = sheet.getActiveColumnIndex(); const selNeedAdjust = getNeedAdjustSelection(sheet.getSelections(), activeRowIndex, activeColIndex); function findFirstNotNullRowIndex(sheet, fixCol, offset, stop) { while (offset > stop) { if (sheet.getValue(offset, fixCol) !== null) { break; } offset--; } return offset; } const rangeChangeSmall = selNeedAdjust.row === activeRowIndex && selNeedAdjust.rowCount > 1 ? true : false; const stopSearchIndex = rangeChangeSmall ? activeRowIndex : 0; const startSearchIndex = rangeChangeSmall ? selNeedAdjust.row + selNeedAdjust.rowCount - 1 - 1 : selNeedAdjust.row - 1; const findResult = findFirstNotNullRowIndex(sheet, activeColIndex, startSearchIndex, stopSearchIndex); if (selNeedAdjust !== null && findResult >= 0) { selNeedAdjust.rowCount = rangeChangeSmall ? findResult - selNeedAdjust.row + 1 : selNeedAdjust.row - findResult + selNeedAdjust.rowCount; selNeedAdjust.row = rangeChangeSmall ? selNeedAdjust.row : findResult; sheet.repaint(); } } function customSelectDown(workbook, options) { const sheet = workbook.getSheetFromName(options.sheetName); const activeRowIndex = sheet.getActiveRowIndex(); const activeColIndex = sheet.getActiveColumnIndex(); const sheetRowCount = sheet.getRowCount(); const selNeedAdjust = getNeedAdjustSelection(sheet.getSelections(), activeRowIndex, activeColIndex); function findNextNotNullRowIndex(sheet, fixCol, offset, stop) { while (offset < stop) { if (sheet.getValue(offset, fixCol) !== null) { break; } offset++; } return offset; } const rangeChangeSmall = selNeedAdjust.row + selNeedAdjust.rowCount - 1 === activeRowIndex && selNeedAdjust.rowCount > 1 ? true : false; const stopSearchIndex = rangeChangeSmall ? activeRowIndex : sheetRowCount; const startSearchIndex = rangeChangeSmall ? selNeedAdjust.row + 1 : selNeedAdjust.row + selNeedAdjust.rowCount; const findResult = findNextNotNullRowIndex(sheet, activeColIndex, startSearchIndex, stopSearchIndex); if (selNeedAdjust !== null && findResult <= sheetRowCount) { selNeedAdjust.rowCount = rangeChangeSmall ? selNeedAdjust.rowCount + selNeedAdjust.row - findResult : findResult - selNeedAdjust.row + 1; selNeedAdjust.row = rangeChangeSmall ? findResult : selNeedAdjust.row; sheet.repaint(); } } function getNeedAdjustSelection(selections, rowIndex, colIndex) { let sel = null; for (let i = 0; i < selections.length; i++) { if (selections[i].contains(rowIndex, colIndex)) { sel = selections[i]; } } return sel; } commandManager.register("customSelectLeft", customSelectLeft); commandManager.register("customSelectRight", customSelectRight); commandManager.register("customSelectDown", customSelectDown); commandManager.register("customSelectUp", customSelectUp); commandManager.setShortcutKey(null, GC.Spread.Commands.Key.left, true, true, false, false); commandManager.setShortcutKey("customSelectLeft", GC.Spread.Commands.Key.left, true, true, false, false); commandManager.setShortcutKey(null, GC.Spread.Commands.Key.right, true, true, false, false); commandManager.setShortcutKey("customSelectRight", GC.Spread.Commands.Key.right, true, true, false, false); commandManager.setShortcutKey(null, GC.Spread.Commands.Key.down, true, true, false, false); commandManager.setShortcutKey("customSelectDown", GC.Spread.Commands.Key.down, true, true, false, false); commandManager.setShortcutKey(null, GC.Spread.Commands.Key.up, true, true, false, false); commandManager.setShortcutKey("customSelectUp", GC.Spread.Commands.Key.up, true, true, false, false); }; const _alertHandle = (e) => { const value = e.target.value; alert(value); }; const _moveHandle = (e) => { const input = e.target; const id = input.id; const isShift = id.indexOf("shift") === 0; const value = parseInt(input.value, 10); const actions = GC.Spread.Sheets.Commands; let action; switch (value) { case 0: action = isShift ? actions.moveToPreviousCell : actions.moveToNextCell; break; case 1: action = isShift ? actions.selectPreviousControl : actions.selectNextControl; break; case 2: action = isShift ? actions.moveToPreviousCellThenControl : actions.moveToNextCellThenControl; break; } if (action) { spread.value.commandManager().register("customCommand" + new Date().valueOf(), action, GC.Spread.Commands.Key.tab, false, isShift, false, false); } }; const _handle = (e) => { const input = e.target; const id = input.id; const isPre = id.indexOf("pre") === 0; const value = input.value; const control = value ? document.getElementById(value) : undefined; if (isPre) { spread.value.previousControl(control); } else { spread.value.nextControl(control); } }; const hideSelection = (e) => { spread.value.options.hideSelection = e.target.checked; }; </script> <style scoped> #app { height: 100%; } .sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 280px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 280px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding: 5px; margin-top: 10px; } .options-toggle { display: none; } input, select { padding: 4px 6px; margin: 4px 0; width: 100%; box-sizing: border-box; } input[type=checkbox] { width: auto; } .colorLabel { width: auto; color: #606060; display: block; } .demo-options { margin-top: 5px; } p { padding: 2px 10px; background-color: #F4F8EB; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; } </style>
<!DOCTYPE html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>SpreadJS VUE</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/vue3/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/en/vue3/node_modules/systemjs/dist/system.src.js"></script> <script src="./systemjs.config.js"></script> <script src="./compiler.js" type="module"></script> <script> var System = SystemJS; System.import("./src/app.js"); System.import('$DEMOROOT$/en/lib/vue3/license.js'); </script> </head> <body> <div id="app"></div> </body> </html>
(function (global) { SystemJS.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, packageConfigPaths: [ './node_modules/*/package.json', "./node_modules/@mescius/*/package.json", "./node_modules/@babel/*/package.json", "./node_modules/@vue/*/package.json" ], map: { 'vue': "npm:vue/dist/vue.esm-browser.js", 'tiny-emitter': 'npm:tiny-emitter/index.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', "systemjs-babel-build": "npm:systemjs-plugin-babel/systemjs-babel-browser.js", '@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-print': 'npm:@mescius/spread-sheets-print/index.js', '@mescius/spread-sheets-vue': 'npm:@mescius/spread-sheets-vue/index.js' }, meta: { '*.css': { loader: 'systemjs-plugin-css' }, '*.vue': { loader: "../plugin-vue/index.js" } } }); })(this);