打开/关闭Google Picker对话框时,如何在加载项侧栏中显示/隐藏加载微调器? [英] How to show/hide loading spinner in addon sidebar while Google Picker dialog is opened/closed?

本文介绍了打开/关闭Google Picker对话框时,如何在加载项侧栏中显示/隐藏加载微调器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遵循了本教程: https://developers.google. com/apps-script/guides/dialogs#file-open_dialogs ,然后点击插件侧边栏中的按钮即可打开Goog​​le Picker.

I followed this tutorial: https://developers.google.com/apps-script/guides/dialogs#file-open_dialogs and I can open a Google Picker after clicking a button inside my addon sidebar.

我想做两件事为用户提供更好的用户体验:

I want to do 2 things for better UX for my users:

  • 第一件事是当Google Picker打开时,我想在加载项侧边栏中显示一个加载微调器(以防止用户与侧边栏进行交互),以便用户只能与Google Picker进行交互,直到它是关闭的

  • The first thing is when the Google Picker is open, I want to show a loading spinner inside my addon sidebar (to prevent users from interacting with the sidebar), so that users can only interact with the Google Picker until it's closed

用户选择文档或直接关闭Google Picker后,插件侧边栏中的加载微调框也会立即消失(我们不应该重新加载侧边栏),用户可以与插件侧栏正常交互

After users choose a document or directly close the Google Picker, the loading spinner in the addon sidebar will also be disappeared immediately (we shouldn't reload the sidebar), and users can interact with the addon sidebar normally

请注意:加载指示器位于插件侧栏的内部 (不在选择器对话框中)

Please note: the loading indicator is inside the addon sidebar (not inside the picker dialog)

我所做的是:

我有2个文件:

  1. sidebar.html
  2. picker.html

这两个html文件都包含运行每个文件所需的html,css和js.

Both these html files contain html, css, js that you need to run each of them.

sidebar.html内,当我需要打开选择器时,我会打电话:

Inside the sidebar.html, when I need to open the Picker, I will call:

function openPicker() {
  // Show spinner here
  showSpinner()

  google.script.run
    .withSuccessHandler(function() { console.log('ok') })
    .showPicker()
}

上面的函数将在Code.gs中调用此showPicker()函数:

Above function will call this showPicker() function in Code.gs:

function showPicker() {
  var html = HtmlService.createHtmlOutputFromFile('picker.html')
    .setWidth(800)
    .setHeight(600)
  FormApp.getUi().showModalDialog(html, 'Select a file')
}

picker.html内,我有一个回调:

function pickerCallback(data) {
    var action = data[google.picker.Response.ACTION]
    if (action === google.picker.Action.PICKED) {
        var doc = data[google.picker.Response.DOCUMENTS][0]
        var id = doc[google.picker.Document.ID]
        var url = doc[google.picker.Document.URL]
        var title = doc[google.picker.Document.NAME]
        document.getElementById('result').innerHTML =
            '<b>You chose:</b><br>Name: <a href="' + url + '">' + title + '</a><br>ID: ' + id
    } else if (action === google.picker.Action.CANCEL) {
        google.script.host.close()
    }

    // This is a good place to hide the spinner, 
    // but this is picker.html, so it can not control code in sidebar.html to hide the spinner
}

这里的问题是,sidebar.html仅知道何时显示微调器,而不知道何时关闭它.

The problem here is, the sidebar.html can only know when to show the spinner, not when to close it.

检测何时应该关闭微调器的逻辑在于picker.html本身(只有选择器才知道用户何时选择了文档或取消了选择器).

The logic to detect when we should close the spinner lies in the picker.html itself (only the picker knows when the user has selected a document or canceled the picker).

而且我不知道如何将该逻辑传递给sidebar.html,以便它可以在sidebar.html内部的某个地方运行hideSpinner().

And I don't know how to pass that logic to the sidebar.html so that it can run hideSpinner() somewhere inside sidebar.html.

推荐答案

问题:

侧边栏和模式对话框尽管起源相同,但仍无法通信.

Issue:

Sidebar and modal dialog are not able to communicate despite having same origin.

可以通过window.top从模态对话框中获取对侧边栏html的引用.从那里,可以

It is possible to get a reference to the sidebar html from modal dialog through window.top. From there, it is possible to

  • 直接相互交流
  • 使用window.postMessage()相互交流
  • 使用Cookie/本地存储彼此通信
  • directly communicate with each other
  • use window.postMessage() to communicate with each other
  • use cookies/localstorage to communicate with each other

在没有相互引用的情况下,仍然可以通过

Without a reference to each other, it is still possible to communicate with each other through

  • 服务器和脚本属性服务.但是,在这里,其中一个需要按设定的时间间隔轮询服务器,以获取另一个的更新.

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>

code.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()
  );
}

阅读:

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆