【问题标题】:Google Sheets undo/redo function谷歌表格撤消/重做功能
【发布时间】:2019-11-27 21:33:24
【问题描述】:

我正在查看网络选项卡以查看是否将重做/撤消数据发送到 Google 表格中的服务器,但它似乎不是 - 它似乎是本地用户/设备正在修改信息.

实现撤消/重做功能的数据结构是什么样的?我的猜测是它将是一个堆栈(即数组),最后一个可撤消的操作被推到堆栈中,如下所示:

actions = [
    action_1,
    action_2
]

但是对于这些操作中的每一个,实际的数据结构是什么样的呢?我想对于单元格的基本修改可以存储文本,但是在 Google 表格中有很多可能的事情要做,所以看起来“动作”可能几乎是无限复杂的。

【问题讨论】:

  • 虽然我不确定我是否能正确理解您的目标,例如,如何使用 Google Apps 脚本的 OnEdit 事件触发器和 OnChange 事件触发器创建操作日志?使用事件触发器时,当用户编辑 Google 电子表格时,可以检索每个操作的日志。使用它创建撤消/重做功能怎么样?如果我误解了您的目标,我深表歉意。 Ref1, Ref2
  • @Tanaike 是的,那实际上很棒。您能否展示一个记录上次撤消/重做操作的示例脚本?
  • 感谢您的回复。在我准备示例脚本之前,我有我想要确认的内容。在这种情况下,将使用 Google Apps 脚本。这是否包含在您期望的方向中?
  • @Tanaike 很好——我更感兴趣的是只看到将被记录的数据结构。也许只是显示一个基本日志,用于添加单元格值或在多个单元格上执行查找替换。
  • 我提出了一个示例脚本作为答案。你能确认一下吗?如果我误解了您的目标并且这不是您想要的方向,我深表歉意。

标签: javascript google-apps-script google-sheets stack


【解决方案1】:
  • 您希望实现 Google 电子表格的撤消和重做功能。
  • 您可以使用 Google Apps 脚本。

我可以像上面那样理解。为此,这个示例脚本怎么样?因此,请将此视为几个可能的答案之一。

用法:

请按照以下流程使用示例脚本。

  1. 创建新的电子表格并打开脚本编辑器。
    • 如果第一个标签不是Sheet1的名称,请将其更改为Sheet1。在这个示例脚本中,作为测试情况,undo和redo函数用于运行到活动电子表格中Sheet1的工作表。请注意这一点。
  2. 将以下示例脚本复制并粘贴到脚本编辑器中,然后保存脚本。
  3. 将可安装的 OnEdit 事件触发器安装到函数 installedOnEdit。
    • 您可以在here 上查看相关文档。请将installedOnEdit 设置为 OnEdit 事件触发器。
    • 安装可安装的 OnEdit 事件触发器时,会打开授权屏幕。所以请授权范围。
  4. 请关闭电子表格并重新打开电子表格。这样,onOpen() 由简单触发器运行。并且offset 被清除。然后,请打开脚本编辑器。
  5. 在电子表格中,手动将“foo”放入单元格“A1”。
    • 由此,logSpreadsheet 的电子表格被创建到根文件夹。这用作日志。
    • 所以只有这一次,请等待创建电子表格。
  6. 确认根文件夹中创建的电子表格后,手动将“bar”放入单元格“A1”。
  7. 手动将“baz”放入单元格“A1”。

    • 此时,当您看到日志电子表格时,您可以看到单元格“A1:A3”的以下值。这用于撤消和重做功能。

      {"range":"A1","value":"foo","oldValue":""}
      {"range":"A1","value":"bar","oldValue":"foo"}
      {"range":"A1","value":"baz","oldValue":"bar"}
      
  8. 在脚本编辑器中运行函数undo。

    • 由此,单元格“A1”的值从baz 更改为bar。
  9. 在脚本编辑器中运行函数undo。
    • 由此,单元格“A1”的值从bar 更改为foo。
  10. 在脚本编辑器中运行函数undo。
    • 由此,单元格“A1”的值从foo 变为空。因为初始情况是空的。
  11. 在脚本编辑器中运行函数redo。
    • 由此,单元格“A1”的值从foo 更改为bar。
  12. 在脚本编辑器中运行函数redo。
    • 由此,单元格“A1”的值从bar 更改为baz。
  13. 在脚本编辑器中运行函数redo。
    • 这样,单元格“A1”的值不会改变。因为这种情况是最新的。

示例脚本:

var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var prop = PropertiesService.getScriptProperties();

function onOpen() {
  prop.setProperty("offset", "0");
}

function getSheet() {
  var logId = prop.getProperty("logSpreadsheetId");
  if (logId) {
    return SpreadsheetApp.openById(logId).getSheets()[0];
  }
  throw new Error("Please edit a cell in the Spreadsheet. By this, the Spreadsheet for logging is created.");
}

// Undo function
function undo() {
  var logsheet = getSheet();
  var offset = Number(prop.getProperty("offset"));
  var lastRow = logsheet.getLastRow();
  if (lastRow + offset > 0) {
    var log = logsheet.getRange(lastRow, 1).offset(offset, 0).getValue();
    var obj = JSON.parse(log);
    sheet.getRange(obj.range).setValue(obj.oldValue);
    prop.setProperty("offset", offset - 1);
  }
}

// Redo function
function redo() {
  var logsheet = getSheet();
  var offset = Number(prop.getProperty("offset")) + 1;
  var lastRow = logsheet.getLastRow();
  if (lastRow + offset <= lastRow) {
    var log = logsheet.getRange(lastRow, 1).offset(offset, 0).getValue();
    var obj = JSON.parse(log);
    sheet.getRange(obj.range).setValue(obj.value);
    prop.setProperty("offset", offset);
  }
}

// Please set the installable OnEdit event trigger to this function.
function installedOnEdit(e) {
  var logId = prop.getProperty("logSpreadsheetId")
  var ss;
  if (logId) {
    ss = SpreadsheetApp.openById(logId);
  } else {
    ss = SpreadsheetApp.create("logSpreadsheet");
    prop.setProperty("logSpreadsheetId", ss.getId());
  }
  var log = {range: e.range.getA1Notation(), value: "value" in e ? e.value : "", oldValue: "oldValue" in e ? e.oldValue : ""};
  ss.getSheets()[0].appendRow([JSON.stringify(log)]);
}

注意:

  • 这是一个简单的示例脚本。不幸的是,复杂的动作可能无法使用。例如,在当前脚本中不能使用编辑多个单元格。我对此深表歉意。当您想添加更复杂的动作时,需要针对每种情况修改脚本。请注意这一点。
  • 在当前阶段,当通过单击删除按钮删除单元格值时,旧值不包含在事件对象中。所以当你想测试值的删除时,请点击单元格并通过退格按钮删除单元格中的每个字符。这样,旧值将包含在事件对象中。请注意这一点。
  • 我认为,如果您想进行更复杂的操作,使用修订数据覆盖电子表格可能是合适的。 Ref

参考:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 2014-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多