4

我正在将我的脚本转换为附加组件。其中一个需求是配置模板,因此我编写了一个启动字段选择器的侧边栏。由于侧边栏没有足够的空间供选择器使用,我必须通过在服务器端调用以下代码从从侧边栏创建的模式对话框中启动它:

var html = HtmlService.createHtmlOutputFromFile('TemplatePicker.html')
  .setWidth(600).setHeight(425);
SpreadsheetApp.getUi().showModalDialog(html, 'Select the file with the template');

我的问题是,一旦用户选择了文件,当我拥有所选文件的 id 时,我就无法将该 id 传递给侧边栏。我尝试调用someJSFunctionOfSidebar(id)and parent.someJSFunctionOfSidebar(id),但它不起作用,所以我最终结束了将值传递到服务器端并从那里重新加载侧边栏,但它非常慢并且产生的效果很难看。

我的问题是:

有没有办法将客户端级别的值从创建的模态对话框传递SpreadsheetApp.getUi().showModalDialog给其父级?也许它实际上不是它的父母,这就是它不起作用的原因。

4

2 回答 2

8

也许它实际上不是它的父母,这就是它不起作用的原因。

对 - 这里实际上没有 DOM 父/子关系。侧边栏和模式对话框都是从服务器端脚本启动的,并且是独立的。不过,它们都可以与服务器通信,因此您可以使用存储转发技术将结果从选择器获取到侧边栏。

基本思路:

  • 侧边栏将在请求选择器启动后立即开始轮询服务器以获取选择器的结果。
  • 选择器的结果将使用google.script.run.
  • 服务器将临时存储结果 - 这可能与全局变量一样简单,具体取决于您的情况。
  • 一旦有结果,下一次轮询将检索它。

查看如何从附加组件中轮询 Google Doc,了解轮询器的基本概念。

消息顺序图

于 2014-08-14T16:25:19.487 回答
4

问题:

侧边栏和模态对话框(兄弟)尽管来源相同,但无法通信。

解决方案:

可以通过祖先 parent 从模态对话框中获取对侧边栏 html 的引用window.top,即使父级是跨源的。从那里,可以

  • 直接相互交流
  • 用来window.postMessage()互相交流

没有相互引用,仍然可以通过

  • 服务器和脚本属性服务。但是,在这里,其中一个需要以设定的时间间隔轮询服务器以从另一个获取任何更新(如此处所示
  • 使用cookies/localstorage相互通信

读书:

示例脚本(通过跨域框架直接访问window.top):

addOn.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Addon</title>
    <style>
      #spinner {
        display: none;
        background-color: tomato;
        position: absolute;
        top: 1%;
        width: 100%;
        justify-items: center;
      }
    </style>
  </head>
  <body>
    <div id="spinner"><p>Loading modal dialog...</p></div>
    <div id="output"></div>
    <script charset="utf-8">
      google.script.run.withSuccessHandler(spinner).testModal();
      function spinner(e) {
        document.getElementById('spinner').style.display = e || 'flex';
      }
      (async () => {
        //After modal dialog has finished, receiver will be resolved
        let receiver = new Promise((res, rej) => {
          window.modalDone = res;
        });
        var message = await receiver;
        document.querySelector('#output').innerHTML = message;
        //Do what you want here
      })();
    </script>
  </body>
</html>

modalAddOn.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title></title>
  </head>
  <body>
    Modal Dialog
    <script>
      (function findSideBar(limit) {
        let f = window.top.frames;
        for (let i = 0; i < limit; ++i) {
          try {
            if (
              f[i] /*/iframedAppPanel*/ &&
              f[i].length &&
              f[i][0] && //#sandboxFrame
              f[i][0][0] && //#userHtmlFrame
              window !== f[i][0][0] //!== self
            ) {
              console.info('Sidebar found ');
              alert('Removing loadbar and closing self');
              var sidebar = f[i][0][0];
              sidebar.spinner('none'); //Remove sidebar spinner
              sidebar.modalDone('Modal says Hi'); //Modal has finished
              google.script.host.close();
            }
          } catch (e) {
            console.error(e);
            continue;
          }
        }
      })(10);
    </script>
  </body>
</html>

代码.gs

function testModal() {
  SpreadsheetApp.getUi().showModelessDialog(
    HtmlService.createHtmlOutputFromFile('modalAddOn')
      .setHeight(500)
      .setWidth(300),
    ' '
  );
}

function onOpen(e) {
  SpreadsheetApp.getUi()
    .createMenu('Sidebar')
    .addItem('Show Add-On', 'showSidebar')
    .addToUi();
}

function showSidebar() {
  SpreadsheetApp.getUi().showSidebar(
    HtmlService.createTemplateFromFile('addOn.html').evaluate()
  );
}

相关问题:

于 2019-10-01T14:03:32.333 回答