Custom MenuView

You can customize the built-in context menu by adding or removing items from the MenuView.

Description
app.vue
index.html
Copy to CodeMine

You can rewrite the defined context menu style class to apply different styles. For example:

    .gc-ui-contextmenu-group-header {
            font-weight:normal;
            background-color:none;
    }

You can customize the menu item's view structure by overwriting the MenuView's createMenuItemElement function:

    var spread = new GC.Spread.Sheets.Workbook(document.getElementById('ss'));
    function CustomMenuView() {}
    CustomMenuView.prototype = new GC.Spread.Sheets.ContextMenu.MenuView();
    CustomMenuView.prototype.createMenuItemElement = function (menuItemData) {
        // create menu item view by your self
        // you can call super's createMenuItemElement here and only customize a few of menu item
        // should return menu item view back
    };
    spread.contextMenu.menuView = new CustomMenuView();

You can overwrite the MenuView's getCommandOptions function to show the options when the command is executed:

    var spread = new GC.Spread.Sheets.Workbook(document.getElementById('ss'));
    function CustomMenuView() {}
    CustomMenuView.prototype = new GC.Spread.Sheets.ContextMenu.MenuView();
    CustomMenuView.prototype.getCommandOptions = function (menuItemData, host, event) {
        // For most of the menu items, only the selections on sheets or the active sheet’s name are needed
        // but there may be some menu items need special parameters,like color picker,change color
        // To change colors, the command needs to know which color the user clicked on, so overwrite this function and return this
        // parameter's value here.
    };
    spread.contextMenu.menuView = new CustomMenuView();
You can rewrite the defined context menu style class to apply different styles. For example: You can customize the menu item's view structure by overwriting the MenuView's createMenuItemElement function: You can overwrite the MenuView's getCommandOptions function to show the options when the command is executed:
<template> <div class="sample-tutorial"> <gc-spread-sheets class="sample-spreadsheets" @workbookInitialized="initSpread"> <gc-worksheet> </gc-worksheet> </gc-spread-sheets> <div class="options-container"> <div class="options-row"> Right click any cell to bring up the context menu.You can easily modify the context menu depending on your needs. Select the option below to add a new context menu item on viewport that will allow the user to change the background color of the cell and a new context menu item on rowHeader that will allow the user to add row count by specified number. </div> <div class="options-row"> <input type="checkbox" id="addMoreMenuItems" v-model="addMoreMenuItems"> <label for="addMoreMenuItems">Add background color menu selection</label> </div> </div> </div> </template> <script setup> import { ref, watch } from "vue"; import "@mescius/spread-sheets-vue"; import GC from '@mescius/spread-sheets'; let colors = ['rgb(255,255,255)', 'rgb(0,255,255)', 'rgb(255,0,255)', 'rgb(255,255,0)', 'rgb(255,0,0)', 'rgb(0,255,0)', 'rgb(0,0,255)', 'rgb(0,0,0)']; const spreadRef = ref(null); const addMoreMenuItems = ref(false); watch(addMoreMenuItems, (value) => { let spread = spreadRef.value; if (isMenuItemExist(spread.contextMenu.menuData, "selectColorWithBg") || isMenuItemExist(spread.contextMenu.menuData, "insertRows")) { spread.contextMenu.menuData.forEach(function (item, index) { if (item && (item.name === "selectColorWithBg" || item.name === "insertRows")) { spread.contextMenu.menuData.splice(index, 1); } }); return; } let commandManager = spread.commandManager(); // prepair select with a background color command and menu item let selectWithABackgroundColor = { text: "Select Color", name: "selectColorWithBg", workArea: "viewport", subMenu: [ { name: "selectColorPicker", command: "selectWithBg" } ] }; spread.contextMenu.menuData.push(selectWithABackgroundColor); let selectWithABackgroundColorCommand = { canUndo: false, execute: function (spread, options) { if (options.commandOptions) { let style = new GC.Spread.Sheets.Style(); style.name = 'style1'; style.backColor = options.commandOptions; let sheet = spread.getActiveSheet(); sheet.suspendPaint(); let selections = sheet.getSelections(); let selectionIndex = 0, selectionCount = selections.length; for (; selectionIndex < selectionCount; selectionIndex++) { let selection = selections[selectionIndex]; for (let i = selection.row; i < (selection.row + selection.rowCount); i++) { for (let j = selection.col; j < (selection.col + selection.colCount); j++) { sheet.setStyle(i, j, style, GC.Spread.Sheets.SheetArea.viewport); } } } sheet.resumePaint(); } } }; commandManager.register("selectWithBg", selectWithABackgroundColorCommand, null, false, false, false, false); // prepair insert rows by specified row count command and menu item let insertRows = { text: "insertRows", name: "insertRows", command: "insertRows", workArea: "rowHeader" }; spread.contextMenu.menuData.push(insertRows); let insertRowsCommand = { canUndo: false, execute: function (spread, options) { let rowCount = parseInt(options.commandOptions); if (!isNaN(rowCount)) { let sheet = spread.getSheetFromName(options.sheetName); sheet.suspendPaint(); sheet.addRows(options.activeRow, rowCount); sheet.resumePaint(); } } }; commandManager.register("insertRows", insertRowsCommand, null, false, false, false, false); // customize context menu function CustomMenuView() { } CustomMenuView.prototype = new GC.Spread.Sheets.ContextMenu.MenuView(); CustomMenuView.prototype.createMenuItemElement = function (menuItemData) { let self = this; if (menuItemData.name === "selectColorPicker") { let containers = GC.Spread.Sheets.ContextMenu.MenuView.prototype.createMenuItemElement.call(self, menuItemData); let supMenuItemContainer = containers[0]; while (supMenuItemContainer.firstChild) { supMenuItemContainer.removeChild(supMenuItemContainer.firstChild); } let colorPicker = createColorpicker(); supMenuItemContainer.appendChild(colorPicker); return supMenuItemContainer; } else if (menuItemData.name === "insertRows") { let containers = GC.Spread.Sheets.ContextMenu.MenuView.prototype.createMenuItemElement.call(self, menuItemData); let supMenuItemContainer = containers[0]; supMenuItemContainer.appendChild(createInput()); return supMenuItemContainer; } else { let menuItemView = GC.Spread.Sheets.ContextMenu.MenuView.prototype.createMenuItemElement.call(self, menuItemData); return menuItemView; } }; CustomMenuView.prototype.getCommandOptions = function (menuItemData, host, event) { if (menuItemData && menuItemData.name === "selectColorPicker") { let ele = event.target || event.srcElement; return ele.style.backgroundColor; } else if (menuItemData && menuItemData.name === "insertRows") { return host.getElementsByClassName("inputBlock")[0].value; } }; spread.contextMenu.menuView = new CustomMenuView(); }); let initSpread = function (spread) { spreadRef.value = spread; } function createColorpicker() { let colorPicker = document.createElement('div'); colorPicker.className = 'colorPickerContent'; for (let j = 0; j < 8; j++) { let colorDom = document.createElement("div"); colorDom.className = 'colorDom'; colorDom.style['backgroundColor'] = colors[j]; colorPicker.appendChild(colorDom); } return colorPicker; } function isMenuItemExist(menuData, menuItemName) { let i = 0, count = menuData.length; for (; i < count; i++) { if (menuItemName === menuData[i].name) { return true; } } } function createInput() { let inputBlock = document.createElement('input'); inputBlock.className = 'inputBlock'; inputBlock.type = 'text'; inputBlock.value = '1'; inputBlock.setAttribute('gcUIElement', 'gcContextMenu'); inputBlock.style = 'width: 20px'; inputBlock.onclick = function (ev) { if (ev.target) { ev.stopPropagation() } } return inputBlock; } </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; } .options-row { font-size: 14px; padding: 5px; margin-top: 10px; } input { display: inline-block; } input[type="text"] { width: 200px; } label { margin-bottom: 6px; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; } .colorPickerContent { width: 100%; background-color: white; } .colorDom { width: 14px; height: 14px; margin: 0 0 0 6px; display: inline-block; border: solid 1px #333333; vertical-align: top; } </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 src="$DEMOROOT$/spread/source/data/sorting.js" type="text/javascript"></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-resources-en': 'npm:@mescius/spread-sheets-resources-en/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);