Google apps script 从附加工具栏打开Google文件选择器

Google apps script 从附加工具栏打开Google文件选择器,google-apps-script,google-drive-api,google-drive-picker,Google Apps Script,Google Drive Api,Google Drive Picker,我希望通过点击谷歌表单附加工具栏中的按钮来加载谷歌驱动器文件选择器 问题 我还无法解决如何直接从侧栏加载选择器(在模式对话框中),然后将文档id回调到侧栏 我已经能够成功地加载一个模态对话框,然后从模态对话框加载选择器,但是我很难理解如何直接从侧边栏加载选择器 感谢您的指导。我当前的代码如下所示 .gs文件: function onOpen(e) { FormApp.getUi() .createAddonMenu() .addItem('Picker', 'showSidebar'

我希望通过点击谷歌表单附加工具栏中的按钮来加载谷歌驱动器文件选择器

问题

我还无法解决如何直接从侧栏加载选择器(在模式对话框中),然后将文档id回调到侧栏

我已经能够成功地加载一个模态对话框,然后从模态对话框加载选择器,但是我很难理解如何直接从侧边栏加载选择器

感谢您的指导。我当前的代码如下所示

.gs文件:

function onOpen(e) {
  FormApp.getUi()
  .createAddonMenu()
  .addItem('Picker', 'showSidebar')
  .addToUi();
}

function showSidebar(){

    var ui = HtmlService.createHtmlOutputFromFile('Sidebar')
  .setSandboxMode(HtmlService.SandboxMode.IFRAME)
  .setTitle('Title');
  FormApp.getUi().showSidebar(ui);

}

function openPicker(){

  var html = HtmlService.createHtmlOutputFromFile('Picker')
  .setWidth(600)
  .setHeight(425)
  .setSandboxMode(HtmlService.SandboxMode.IFRAME);
  FormApp.getUi().showModalDialog(html, 'Select a file');

}


function getOAuthToken() {
  DriveApp.getRootFolder();
  return ScriptApp.getOAuthToken();
}
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
  <input type="button" id="button" value="Open picker">
  <div>  Selection:  <?!=  model ?> </div>  

  <script>

  window.onload = (function(){

  var button = document.getElementById('button');
  button.addEventListener('click', function(event){

  google.script.run
               .withSuccessHandler(function(){             

                 google.script.host.close();             

               })
               .showModalDialog(); 

  });


  })();  
  </script>
  </body>
</html>
侧栏html

<!DOCTYPE html>
<html>
  <head>
  <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
    <base target="_top">
  </head>
  <body>
    <button onclick='openPicker()'>Select a file</button>
  </body>
</html>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>


function openPicker() {
google.script.run
.withSuccessHandler(success)
.withFailureHandler(failure)
.openPicker();
}

function success() {
console.log('success');
}

function failure() {
console.log('failure');
}

</script>
 <!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
  <script>

    var DEVELOPER_KEY = '';
    var DIALOG_DIMENSIONS = {width: 600, height: 425};
    var pickerApiLoaded = false;


    function onApiLoad() {
      gapi.load('picker', {'callback': function() {
        pickerApiLoaded = true;
      }});
     }


    function getOAuthToken() {
      google.script.run
      .withSuccessHandler(createPicker)
      .withFailureHandler(showError)
      .getOAuthToken();
    }


    function createPicker(token) {
    console.log("here");
      if (pickerApiLoaded && token) {
        var picker = new google.picker.PickerBuilder()
            // Instruct Picker to display only spreadsheets in Drive. For other
            // views, see https://developers.google.com/picker/docs/#otherviews
            .addView(google.picker.ViewId.DOCUMENTS)
            // Hide the navigation panel so that Picker fills more of the dialog.
            .enableFeature(google.picker.Feature.NAV_HIDDEN)
            // Hide the title bar since an Apps Script dialog already has a title.
            .hideTitleBar()
            .setOAuthToken(token)
            .setDeveloperKey(DEVELOPER_KEY)
            .setCallback(pickerCallback)
            .setOrigin(google.script.host.origin)
            // Instruct Picker to fill the dialog, minus 2 pixels for the border.
            .setSize(DIALOG_DIMENSIONS.width - 2,
                DIALOG_DIMENSIONS.height - 2)
            .build();
        picker.setVisible(true);
      } else {
        showError('Unable to load the file picker.');
      }
    }


    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) {
        document.getElementById('result').innerHTML = 'Picker canceled.';
      }
    }


    function showError(message) {
      document.getElementById('result').innerHTML = 'Error: ' + message;
    }
  </script>
</head>
<body>
  <div>
    <button onclick='getOAuthToken()'>Select a file</button>
    <p id='result'></p>
  </div>
  <script src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
</html>

选择一个文件
函数openPicker(){
google.script.run
.withSuccessHandler(成功)
.withFailureHandler(失败)
.openPicker();
}
函数成功(){
console.log('success');
}
函数失效(){
console.log('failure');
}
选择器html

<!DOCTYPE html>
<html>
  <head>
  <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
    <base target="_top">
  </head>
  <body>
    <button onclick='openPicker()'>Select a file</button>
  </body>
</html>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>


function openPicker() {
google.script.run
.withSuccessHandler(success)
.withFailureHandler(failure)
.openPicker();
}

function success() {
console.log('success');
}

function failure() {
console.log('failure');
}

</script>
 <!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
  <script>

    var DEVELOPER_KEY = '';
    var DIALOG_DIMENSIONS = {width: 600, height: 425};
    var pickerApiLoaded = false;


    function onApiLoad() {
      gapi.load('picker', {'callback': function() {
        pickerApiLoaded = true;
      }});
     }


    function getOAuthToken() {
      google.script.run
      .withSuccessHandler(createPicker)
      .withFailureHandler(showError)
      .getOAuthToken();
    }


    function createPicker(token) {
    console.log("here");
      if (pickerApiLoaded && token) {
        var picker = new google.picker.PickerBuilder()
            // Instruct Picker to display only spreadsheets in Drive. For other
            // views, see https://developers.google.com/picker/docs/#otherviews
            .addView(google.picker.ViewId.DOCUMENTS)
            // Hide the navigation panel so that Picker fills more of the dialog.
            .enableFeature(google.picker.Feature.NAV_HIDDEN)
            // Hide the title bar since an Apps Script dialog already has a title.
            .hideTitleBar()
            .setOAuthToken(token)
            .setDeveloperKey(DEVELOPER_KEY)
            .setCallback(pickerCallback)
            .setOrigin(google.script.host.origin)
            // Instruct Picker to fill the dialog, minus 2 pixels for the border.
            .setSize(DIALOG_DIMENSIONS.width - 2,
                DIALOG_DIMENSIONS.height - 2)
            .build();
        picker.setVisible(true);
      } else {
        showError('Unable to load the file picker.');
      }
    }


    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) {
        document.getElementById('result').innerHTML = 'Picker canceled.';
      }
    }


    function showError(message) {
      document.getElementById('result').innerHTML = 'Error: ' + message;
    }
  </script>
</head>
<body>
  <div>
    <button onclick='getOAuthToken()'>Select a file</button>
    <p id='result'></p>
  </div>
  <script src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
</html>

var开发者_键=“”;
var对话框_维度={宽度:600,高度:425};
var pickerApiLoaded=false;
函数onapioad(){
load('picker',{'callback':函数(){
pickerApiLoaded=真;
}});
}
函数getOAuthToken(){
google.script.run
.withSuccessHandler(createPicker)
.带故障处理器(淋浴ROR)
.getOAuthToken();
}
函数createPicker(令牌){
console.log(“此处”);
if(PickerApproaded&&token){
var picker=new google.picker.PickerBuilder()
//指示选择器仅在驱动器中显示电子表格。对于其他
//视图,请参阅https://developers.google.com/picker/docs/#otherviews
.addView(google.picker.ViewId.DOCUMENTS)
//隐藏导航面板,以便选择器填充更多对话框。
.enableFeature(google.picker.Feature.NAV_隐藏)
//隐藏标题栏,因为应用程序脚本对话框已具有标题。
.hideTitleBar()
.setOAuthToken(令牌)
.setDeveloperKey(开发者密钥)
.setCallback(pickerCallback)
.setOrigin(google.script.host.origin)
//指示选择器填充对话框,边框减去2个像素。
.setSize(对话框尺寸.width-2,
对话框_DIMENSIONS.height-2)
.build();
picker.setVisible(true);
}否则{
淋浴ROR('无法加载文件选择器');
}
}
函数选择器回调(数据){
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=
“您选择:
名称:
ID:”+ID; }else if(action==google.picker.action.CANCEL){ document.getElementById('result').innerHTML='Picker cancelled'; } } 功能错误(消息){ document.getElementById('result')。innerHTML='Error:'+message; } 选择一个文件


只需修改选择器Html代码,以便在加载模式Html对话框时自动运行
getOAuthToken()
函数,如下所示:

... Code till here remains as above
<body onload = 'getOAuthToken()'>
  <div>
    <p id='result'></p>
  </div>
  <script src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
</html>
。。。在此之前的代码保持如上所述

有关
onload
事件的更多详细信息,请参阅


希望有帮助

这是我想出的又快又脏的解决办法。My'.gs'文件包含用于显示通过HtmlService提供服务的UI容器以及获取OAuth令牌的函数。请注意,在将数据模型转换为原始HTML并传递给客户端之前,可以将其传递给HtmlTemplate对象。当我们从自定义菜单调用'showSidebar'函数时,不会传递任何参数,因此这是第一次调用。如果'params'不是'undefined',我们知道调用来自模态对话框

代码.gs

var ui = SpreadsheetApp.getUi()


//add custom menu to the spreadsheet;
function onOpen() {

ui.createMenu('Sidebar')
.addItem('Show sidebar', 'showSidebar')
.addToUi();

}

function showSidebar(params){

var sidebar = HtmlService.createTemplateFromFile('sidebar');
var model = "your selection"; //default message to be displayed

  if (params) { //if arguments are passed, it's a callback from modal dialog
    model = "You selected document with id: " +     
                  params.id + ", title: " + params.title + 
                  " url: " + params.url; 
  }  

sidebar.model = model; // pass model to the template
var htmlOutput = sidebar.evaluate(); //execute inline scriplets from the template to complete DOM construction. 
ui.showSidebar(htmlOutput); //pass resulting UI object to sidebar container

}

function showModalDialog() {

// produce HtmlOutput for modal dialog
var modalDialog = HtmlService.createTemplateFromFile('modal_dialog')
                             .evaluate()
                             .setWidth(600)
                             .setHeight(425)
                             .setSandboxMode(HtmlService.SandboxMode.IFRAME); 

ui.showModalDialog(modalDialog, 'Picker');


}

function getOAuthToken() {
  DriveApp.getRootFolder();
  return ScriptApp.getOAuthToken();
}
sidebar.html:

function onOpen(e) {
  FormApp.getUi()
  .createAddonMenu()
  .addItem('Picker', 'showSidebar')
  .addToUi();
}

function showSidebar(){

    var ui = HtmlService.createHtmlOutputFromFile('Sidebar')
  .setSandboxMode(HtmlService.SandboxMode.IFRAME)
  .setTitle('Title');
  FormApp.getUi().showSidebar(ui);

}

function openPicker(){

  var html = HtmlService.createHtmlOutputFromFile('Picker')
  .setWidth(600)
  .setHeight(425)
  .setSandboxMode(HtmlService.SandboxMode.IFRAME);
  FormApp.getUi().showModalDialog(html, 'Select a file');

}


function getOAuthToken() {
  DriveApp.getRootFolder();
  return ScriptApp.getOAuthToken();
}
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
  <input type="button" id="button" value="Open picker">
  <div>  Selection:  <?!=  model ?> </div>  

  <script>

  window.onload = (function(){

  var button = document.getElementById('button');
  button.addEventListener('click', function(event){

  google.script.run
               .withSuccessHandler(function(){             

                 google.script.host.close();             

               })
               .showModalDialog(); 

  });


  })();  
  </script>
  </body>
</html>
最后,我将以下代码添加到'pickerCallback'函数中

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];

        google.script.run.withSuccessHandler(function(){

           google.script.host.close();

        }).showSidebar({id: id, url: url, title: title});
当用户进行选择时,数据将作为参数传递给'.gs'文件中的'showSideBar'函数。由于'google.script.host(run)'调用是异步的,因此我将窗口关闭调用放置在的'withSuccessHandler'中,以防止过早关闭

结果:侧栏中显示选择数据

还有一种方法我更喜欢。在GAS中,甚至文件绑定脚本也可以发布为web应用程序,因此您基本上可以通过UrlFetchApp.fetch()调用来创建多页应用程序。例如,您可以定义一个包含单个“container”div的母版页。您还可以存储所有JS代码并在母版页上加载API。如果您需要导航到另一个页面,只需通过fetch(url)查询web应用程序,并通过将生成的html粘贴到母版页上的容器中即可

containerDiv.innerHTML = html;

可以通过调用ScriptApp.getService().getUrl()动态获取web应用的url。但是,脚本必须首先作为匿名访问的web应用程序发布。希望这能有所帮助。

很抱歉我之前的评论-我没有完整阅读问题。您只需创建一个html页面并将其作为侧栏提供,然后将客户端JS移动到该页面(令牌请求等)。也许我遗漏了什么。@Anton Dementiev,当我试图调用一个html页面时,它是在侧边栏中加载选择器,而不是在新的对话框窗口中打开它。@Anton Dementiev我认为你的思路比我接受的解决方案更正确。我现在意识到,拥有两个单独的html页面会导致通过callba将文档id返回到侧栏的问题