Posted 31 July 2025, 6:12 pm EST - Updated 31 July 2025, 6:27 pm EST
How would I connect my custom command for my quick math window to the undo and redo controls in addition to cntrol+Z and control+Y buttons.
In my initialization function that initializes the SpreadJS and Designer controls:
//Configuration for added features goes here:
var config = GC.Spread.Sheets.Designer.DefaultConfig;
config.commandMap = config.commandMap || {};
config.commandMap["applyMath"] = applyMathCommand();
config.contextMenu = config.contextMenu || [];
config.contextMenu.push("applyMath");
// Initialize a workbook
// Initialize the SpreadJS Designer inside the HTML element with ID 'spreadJsSpreadsheet' using the specified configuration,
// then retrieve the associated workbook instance for further interaction or manipulation.
//var spread = new GC.Spread.Sheets.Workbook(document.getElementById('spreadJsSpreadsheet'), { sheetCount: 1 });
var designer = new GC.Spread.Sheets.Designer.Designer(document.getElementById('spreadJsSpreadsheet'), config);
var spread = designer.getWorkbook();
spread.options.tabEditable = false;
spread.options.newTabVisible = false;
spread.bind(GC.Spread.Sheets.Events.SelectionChanged, function () {
designer.refresh(); // Ensures command is re-evaluated
});
then in my applyMathCommand() function I have:
//------------------------------------------------------------------------------
// applyMathCommand()
// Defines a custom SpreadJS Designer command named "Apply Math Operation".
// This command becomes available in the context menu when right-clicking on
// the viewport area. It checks if the current selection contains any non-empty
// cells and enables the command accordingly.
//
// When executed, it applies a simple math operation (incrementing numeric cells
// by 1) and supports undo by saving the original cell values to restore them
// if the user triggers Undo (e.g., Ctrl+Z).
//
// Returns:
// A command object compatible with GC.Spread.Sheets.Designer.commandMap.
//
// Usage:
// config.commandMap["applyMath"] = applyMathCommand();
//------------------------------------------------------------------------------
function applyMathCommand() {
return {
title: "Apply Math Operation",
text: "Apply Math Operation",
iconClass: "custom-icon",
commandName: "applyMath",
visibleContext: "ClickViewport",
canUndo: true,
isEnabled: function (context) {
var sheet = context.getWorkbook().getActiveSheet();
var selections = sheet.getSelections();
if (!selections || selections.length === 0) return false;
for (var s = 0; s < selections.length; s++) {
var sel = selections[s];
for (var r = sel.row; r < sel.row + sel.rowCount; r++) {
for (var c = sel.col; c < sel.col + sel.colCount; c++) {
let val = sheet.getValue(r, c);
if (val !== null && val !== "") {
return true;
}
}
}
}
return false;
},
execute: function (context, options) {
var sheet = context.getWorkbook().getActiveSheet();
// Double-check that selection has data before proceeding
if (!selectionHasData(sheet)) {
console.warn("Selected cells are blank. Command aborted.");
return;
}
// Open the popup window (assuming it's already initialized as a Kendo Window)
let mathOps = $("#math-ops-pop-up-window").data("kendoWindow");
if (mathOps) {
mathOps.center();
mathOps.open();
} else {
console.warn("Popup window 'math-ops-pop-up-window' not found or not initialized.");
}
}
};
}//end applyMathCommmand().
//HELPER FUNCTION FOR ABOVE USED IN EXECUTE:
// Checks if the current selection in the worksheet contains any non-empty cell values.
// This function is useful for validating whether a command should proceed,
// ensuring there's actual data to operate on (e.g. before applying math operations).
//
// It iterates over all selected ranges in the sheet, then over each cell within those ranges,
// checking if any cell contains a value that is not null and not an empty string.
//
// Returns true if at least one cell has usable data; false otherwise.
function selectionHasData(sheet) {
var selections = sheet.getSelections(); // Get all selected ranges
if (!selections || selections.length === 0) return false; // Return false if nothing is selected
for (var s = 0; s < selections.length; s++) {
var sel = selections[s]; // Current selection range
for (var r = sel.row; r < sel.row + sel.rowCount; r++) {
for (var c = sel.col; c < sel.col + sel.colCount; c++) {
let val = sheet.getValue(r, c); // Get cell value
if (val !== null && val !== "") { // Check if value is not null or empty
return true; // Found valid data, return true
}
}
}
}
return false; // No data found in selection
}
Now I think there is a way to connect to the listeners or something for the redo or undo buttons in the Designer and the Cntrol+Z command. I tried CoPilot on this and it took me down a terrible path where if froze up the selection box for the SpreadJS…Oof.
how do I link the custom command I have working in the context menu to trigger or have the undo, redo, and Control+Z to responed?