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
styles.css
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-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" v-on: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" v-on: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" v-on: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" v-on: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" v-on: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> import Vue from "vue"; import "@mescius/spread-sheets-vue"; import GC from "@mescius/spread-sheets"; import "./styles.css"; let App = Vue.extend({ name: "app", methods: { initSpread: function (spread) { this.spread = spread; spread.suspendPaint(); let sheet = spread.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 selction 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"); } } spread.resumePaint(); let commandManager = spread.commandManager(); function customSelectLeft(workbook, options) { let sheet = workbook.getSheetFromName(options.sheetName); let activeRowIndex = sheet.getActiveRowIndex(); let activeColIndex = sheet.getActiveColumnIndex(); let selNeedAdjust = getNeedAdjustSelection(sheet.getSelections(), activeRowIndex, activeColIndex); let findFirstNotNullColIndex = function (sheet, fixRow, offset, stop) { while (offset > stop) { if (sheet.getValue(fixRow, offset) !== null) { break; } offset--; } return offset; } let rangeChangeSmall = selNeedAdjust.col === activeColIndex && selNeedAdjust.colCount > 1 ? true : false; let stopSearchIndex = rangeChangeSmall ? activeColIndex : 0; let startSearchIndex = rangeChangeSmall ? selNeedAdjust.col + selNeedAdjust.colCount - 1 - 1 : selNeedAdjust.col - 1; let 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) { let sheet = workbook.getSheetFromName(options.sheetName); let activeRowIndex = sheet.getActiveRowIndex(); let activeColIndex = sheet.getActiveColumnIndex(); let sheetColCount = sheet.getColumnCount(); let selNeedAdjust = getNeedAdjustSelection(sheet.getSelections(), activeRowIndex, activeColIndex); let findNextNotNullColIndex = function (sheet, fixRow, offset, stop) { while (offset < stop) { if (sheet.getValue(fixRow, offset) !== null) { break; } offset++; } return offset; } let rangeChangeSmall = selNeedAdjust.col + selNeedAdjust.colCount - 1 === activeColIndex && selNeedAdjust.colCount > 1 ? true : false; let stopSearchIndex = rangeChangeSmall ? activeColIndex : sheetColCount; let startSearchIndex = rangeChangeSmall ? selNeedAdjust.col + 1 : selNeedAdjust.col + selNeedAdjust.colCount; let 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) { let sheet = workbook.getSheetFromName(options.sheetName); let activeRowIndex = sheet.getActiveRowIndex(); let activeColIndex = sheet.getActiveColumnIndex(); let selNeedAdjust = getNeedAdjustSelection(sheet.getSelections(), activeRowIndex, activeColIndex); let findFirstNotNullRowIndex = function (sheet, fixCol, offset, stop) { while (offset > stop) { if (sheet.getValue(offset, fixCol) !== null) { break; } offset--; } return offset; } let rangeChangeSmall = selNeedAdjust.row === activeRowIndex && selNeedAdjust.rowCount > 1 ? true : false; let stopSearchIndex = rangeChangeSmall ? activeRowIndex : 0; let startSearchIndex = rangeChangeSmall ? selNeedAdjust.row + selNeedAdjust.rowCount - 1 - 1 : selNeedAdjust.row - 1; let 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) { let sheet = workbook.getSheetFromName(options.sheetName); let activeRowIndex = sheet.getActiveRowIndex(); let activeColIndex = sheet.getActiveColumnIndex(); let sheetRowCount = sheet.getRowCount(); let selNeedAdjust = getNeedAdjustSelection(sheet.getSelections(), activeRowIndex, activeColIndex); let findNextNotNullRowIndex = function (sheet, fixCol, offset, stop) { while (offset < stop) { if (sheet.getValue(offset, fixCol) !== null) { break; } offset++; } return offset; } let rangeChangeSmall = selNeedAdjust.row + selNeedAdjust.rowCount - 1 === activeRowIndex && selNeedAdjust.rowCount > 1 ? true : false; let stopSearchIndex = rangeChangeSmall ? activeRowIndex : sheetRowCount; let startSearchIndex = rangeChangeSmall ? selNeedAdjust.row + 1 : selNeedAdjust.row + selNeedAdjust.rowCount; let 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); }, _alertHandle(e) { let value = e.target.value; alert(value); }, _moveHandle(e) { let input = e.target; let id = input.id, isShift = id.indexOf("shift") === 0, value = parseInt(input.value, 10), actions = GC.Spread.Sheets.Commands, 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) { this.spread.commandManager().register("customCommand" + new Date().valueOf(), action, GC.Spread.Commands.Key.tab, false, isShift, false, false); } }, _handle(e) { let input = e.target; let id = input.id, isPre = id.indexOf("pre") === 0, value = input.value, control = value ? document.getElementById(value) : undefined; if (isPre) { this.spread.previousControl(control); } else { this.spread.nextControl(control); } }, hideSelection(e) { this.spread.options.hideSelection = e.target.checked; } } }); function _concat(sheet) { if (sheet) { let customFloatingObjects = sheet.floatingObjects.all(); let pictures = sheet.pictures.all(); return pictures.concat(customFloatingObjects); } return []; } new Vue({ render: h => h(App) }).$mount("#app"); </script>
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/vue/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <!-- SystemJS --> <script src="$DEMOROOT$/en/vue/node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app.vue'); System.import('$DEMOROOT$/en/lib/vue/license.js'); </script> </head> <body> <div id="app"></div> </body> </html>
.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; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, meta: { '*.css': { loader: 'css' }, '*.vue': { loader: 'vue-loader' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { '@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-vue': 'npm:@mescius/spread-sheets-vue/index.js', '@grapecity/jsob-test-dependency-package/react-components': 'npm:@grapecity/jsob-test-dependency-package/react-components/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'css': 'npm:systemjs-plugin-css/css.js', 'vue': 'npm:vue/dist/vue.min.js', 'vue-loader': 'npm:systemjs-vue-browser/index.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' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' } } }); })(this);