2

我有一个非常基本的Google Workspace插件,它使用CalendarApp 类在按下按钮时切换日历事件的可见性,使用setSelected()方法

可见性切换有效,但更改仅在页面刷新时反映在 UI 中。在 UI 中手动切换复选框会立即反映更改,而无需刷新页面。

有没有办法通过我的 Workspace Add-On 复制这种即时更新行为?

一个 mwe 在下面。

function onDefaultHomePageOpen() {

  // create button
  var action = CardService.newAction().setFunctionName('toggleCalVis')
  var button = CardService.newTextButton()
    .setText("TOGGLE CAL VIS")
    .setOnClickAction(action)
    .setTextButtonStyle(CardService.TextButtonStyle.FILLED)
  var buttonSet = CardService.newButtonSet().addButton(button)

  // create CardSection
  var section = CardService.newCardSection()
    .addWidget(buttonSet)

  // create card
  var card = CardService.newCardBuilder().addSection(section)

  // call CardBuilder.call() and return card
  return card.build()

}

function toggleCalVis() {
  // fetch calendar with UI name "foo"
  var calendarName = "foo"
  var calendarsByName = CalendarApp.getCalendarsByName(calendarName)
  var namedCalendar = calendarsByName[0]

  // Toggle calendar visabilty in the UI
  if (namedCalendar.isSelected()) {
    namedCalendar.setSelected(false)
  }
  else {
    namedCalendar.setSelected(true)
  }
}
4

2 回答 2

2

简而言之:创建一个 chrome 扩展

(2021-sep-2) 原因:该setSelected()方法更改服务器上的数据。要应用它的效果,您需要刷新页面。但“出于安全原因”的 Google Workspace Extension 不允许 GAS 这样做。但是,在 Chrome 扩展程序中,您可以通过普通 JS 取消选中可见性复选框。(左侧列表的类名已编码,但对我来说是稳定的。)我有一些 Chrome 扩展程序的代码来选择节点,尽管我没有解决(见最后一部分)。

(2021 年 7 月 25 日)更糟糕的情况:默认日历不会被getAllCalendars(). 我只是尝试了与您提到的相同的事情,结果更糟。我想隐藏所有日历,我仍然很确定代码是正确的,因为我可以在控制台中看到日历名称。

const allCals = CalendarApp.getAllCalendars()
allCals.forEach(cal => {console.log(`unselected ${cal.setSelected(false).getName()}`)})

但是,主日历、提醒日历和任务日历不在控制台中。

谷歌应用程序脚本开发人员应该问自己:人们为什么要使用Calendar.setSelected() 我们不想在下次运行时隐藏日历。

官方文档中,没有提到这两种行为。

TL;DR 部分(我不使用 GAS 的原因)

GAS(google-apps-script) 的功能较少。就我所见,谷歌正在尝试建立自己的生态系统,但在 GAS 中可实现的一切也可以通过 javascript 获得。我什至可以使用 typescript 并通过创建扩展来做任何我想做的事情。

GAS容易学。学习也很痛苦,我花了 4 个小时搭建了第一张样卡,9 个小时后就可以和打开的事件正确交互了。文档远未完成。

GAS 的支持很差。基于 Web 的原生代码编辑器 ( https://script.google.com/ ) 不是为编写真正的应用程序而构建的,它在新界面中失去了版本控制自由。并且不支持跨文件搜索。而不是import,代码在列表中从上到下运行,您需要自己找到。(没有扩展,没有更漂亮,我可以容忍这些)与其他在线JS代码编辑器相比,如codepen / code sandbox / etcetera,它的功能更少。此外,VSCode 现在也有一个在线版本(github codespaces)。

我希望我在 GAS 的 13 个小时不会完全浪费。至少读过这篇文章的人可以避免遭受同样痛苦的考验。

这是禁用 Chrome 中所有检查的代码(打字稿)。 TRACKER_CAL_ID_ENCODED是我不想取消选中的日历 ID。由于它不是这个问题的主要部分,因此没有很仔细地评论。

(行更新:2022-jan-31)意识到mutationsList.length >= 3不准确,我看不出它是如何mutationsList.length工作的。

扩大:


getSelectCalendarNode()
  .then(unSelectCalendars)
function getSelectCalendarNode() {
  return new Promise((resolve) => {
    document.onreadystatechange = function () {
      if (document.readyState == "complete") {
        const leftSidebarNode = document.querySelector(
          "div.QQYuzf[jsname=QA0Szd]"
        )!;
        new MutationObserver((mutationsList, observer) => {
          for (const mutation of mutationsList) {
            if (mutation.target) {
              let _selectCalendarNode = document.querySelector("#dws12b.R16x0");
              // customized calendars will start loading on 3th+ step, hence 3, but when will they stop loading? I didn't work this out
              if (mutationsList.length >= 3) {
                // The current best workaround I saw is setTimeout after loading event... There's no event of loading complete.
                setTimeout(() => {
                  observer.disconnect();
                  resolve(_selectCalendarNode);
                }, 1000);
              }
            }
          }
        }).observe(leftSidebarNode, { childList: true, subtree: true });
      }
    };
  });
}

function unSelectCalendars(selectCalendarNode: unknown) {
  const selcar = selectCalendarNode as HTMLDivElement;
  const calwrappers = selcar.firstChild!.childNodes; // .XXcuqd
  for (const calrow of calwrappers) {
    const calLabel = calrow.firstChild!.firstChild as HTMLLabelElement;

    const calSelectWrap = calLabel.firstChild!;
    const calSelcted =
      (calSelectWrap.firstChild!.firstChild! as HTMLDivElement).getAttribute(
        "aria-checked"
      ) == "true"
        ? true
        : false;
    // const calNameSpan = calSelectWrap.nextSibling!
    //   .firstChild! as HTMLSpanElement;
    // const calName = calNameSpan.innerText;
    const encodedCalID = calLabel.getAttribute("data-id")!; // const decodedCalID = atob(encodedCalID);
    if ((encodedCalID === TRACKER_CAL_ID_ENCODED) !== calSelcted) {
      //XOR
      calLabel.click();
    }
  }
  console.log(selectCalendarNode);
  return;
}

于 2021-07-25T02:08:40.083 回答
0

无法使用 Google Apps 脚本刷新网页

可能的解决方法:

  • 从侧边栏中,为用户提供一个链接,将他们重定向到日历 UI 网页(因此将打开一个新的、刷新的版本)
  • 安装一个以指定时间间隔刷新标签的 Goole Chrome 扩展
于 2021-01-25T08:33:49.420 回答