2017-12-15 3 views
0

Ich suche eine Google Drive Dateiauswahl zu laden, indem Sie auf eine Schaltfläche in einem Google-Formular Add-on Seitenleiste klicken.öffnen Sie Google Dateiauswahl von Add-on-Sidebar

Problem

Ich habe zu arbeiten, nicht in der Lage gewesen, wie die Kommissionierer (in einem modalen Dialog) zu laden direkt aus dem Sidebar Rückruf, dann die Dokument-ID in die Seitenleiste.

Ich konnte erfolgreich einen modalen Dialog laden und dann den Picker aus dem modalen Dialog laden, aber ich habe Mühe zu verstehen, wie man den Picker direkt aus der Sidebar lädt.

Jede Anleitung wird geschätzt. Mein aktueller Code ist unten abgebildet.

.gs Datei:

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

Sidebar 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> 

Picker html

<!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> 
+0

Entschuldigung für meinen vorherigen Kommentar - Ich habe die Frage nicht vollständig gelesen. Sie können einfach eine einzelne HTML-Seite als Seitenleiste erstellen und bereitstellen und das clientseitige JS auf diese Seite verschieben (Token-Anfrage usw.). Vielleicht vermisse ich etwas. –

+0

@Anton Dementiev, als ich versuchte, eine einzelne HTML-Seite aufzurufen, wurde die Auswahl in der Seitenleiste geladen, anstatt sie in einem neuen Dialogfenster zu öffnen. – Johnny

+0

@AntonDementiev Ich glaube, Sie waren mehr auf dem richtigen Weg als die Lösung, die ich akzeptierte. Ich erkenne jetzt, zwei getrennte HTML-Seiten verursachen Probleme, die Dokument-ID zurück zu der Seitenleiste durch die Rückruffunktion zu erhalten. Irgendwelche Hinweise, was ich zwischen den Dateien bewegen muss? – Johnny

Antwort

1

einfach Ihre picke ändern r Html-Code auszuführen automatisch getOAuthToken() Funktionen, wenn die HTML-Datei auf modalen Dialog Lasten, etwa so:

... 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> 

Weitere Einzelheiten zu onload Ereignis beziehen here

Hoffnung, das hilft.

+0

Hallo Jack, jede Anleitung, wie Sie die Dokument-ID zurück in die Sidebar durch die Callback-Funktion erhalten (da es auf einer anderen HTML-Seite ist)? – Johnny

1

Hier ist die schnelle und schmutzige Lösung kam ich mit. Meine ‘.gs' Datei enthält Funktionen für über Htmlservice und Erhalten die OAuth-Token bedient UI-Container anzuzeigen. Beachten Sie, dass Sie Datenmodelle an HtmlTemplate Objekte übergeben können, bevor sie in Raw-HTML konvertiert und an den Client übergeben werden. Wenn wir die 'showSidebar' Funktion aus dem benutzerdefinierten Menü aufrufen, werden keine Argumente übergeben, so dass es der erste Aufruf ist. Wenn 'params' nicht 'undefiniert' ist, wissen wir, dass der Aufruf aus dem modalen Dialog kommt.

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

seitenleiste.html:

<!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> 

Die Scriptlets zwischen <? ?> wird ausgelöst, wenn ‚evaluate()‘ auf das Objekt der Klasse HtmlTemplate gehören, aufgerufen wird.Es gibt mehrere Arten von Scriptlets - mehr auf Scriptlets hier:

https://developers.google.com/apps-script/guides/html/templates#scriptlets

Hinzufügen '!' unmittelbar nach dem ersten '?' wird das Ergebnis auf die Seite drucken. Nachdem die DOM-Struktur geladen wurde, füge ich den Ereignis-Listener hinzu, der die Funktion 'showDialog()' in der Datei '.gs' ausführt, wenn der Benutzer auf die Schaltfläche klickt.

Die Vorlage für das Dialogfenster wird vom Kommissionierer Quickstart hier

https://developers.google.com/apps-script/guides/dialogs

I die ‚onApiLoaded‘ Funktion modifiziert den Picker unmittelbar nach dem Laden anzuzeigen.

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

     }}); 
    } 

Schließlich habe ich hinzugefügt, um den folgenden Code zum Funktion '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}); 

Wenn Benutzer eine Auswahl treffen, werden die Daten als Parameter an die Funktion'showSideBar' passed in Datei‘.gs'. Da die Aufrufe von 'google.script.host (run)' asynchron sind, habe ich den Aufruf zum Schließen der Fenster innerhalb von 'withSuccessHandler' platziert, um eine vorzeitige Schließung zu verhindern.

Ergebnis: Auswahldaten werden in der Seitenleiste angezeigt.

Es gibt einen anderen Ansatz, den ich besser mag. In GAS können sogar dateigebundene Skripts als Web-Apps veröffentlicht werden. Sie können also mehrseitige Apps erstellen, indem Sie über UrlFetchApp.fetch() aufrufen. Sie können beispielsweise eine Masterseite definieren, die ein einzelnes "Container" -Div enthält. Sie können auch den gesamten JS-Code speichern und die APIs auf der Masterseite laden. Wenn Sie auf eine andere Seite navigieren müssen, können Sie einfach die Web-App abfragen über holen (url) und fügen Sie den resultierenden HTML-Code in Container auf der Masterseite über

containerDiv.innerHTML = html; 

die URL für die Web-App dynamisch erhalten werden kann durch Aufruf von ScriptApp.getService(). getUrl(). Das Skript muss jedoch zunächst als eine Web-App veröffentlicht werden, die anonym zugänglich ist. Hoffe das hilft.

+0

Danke Anton. Gibt es eine Möglichkeit, die Seitenleiste während des Rückrufs nicht zu aktualisieren? – Johnny

+0

Wie bereits erwähnt, können Sie das Verhalten einer einzelnen Seite in HTML simulieren, solange es sich in einem einzelnen GAS-Container befindet. In Ihrem Fall gibt es zwei Container für HTML - die Seitenleiste und den Dialog. Ich sehe keine offensichtliche Möglichkeit, dieses Verhalten nachzubilden. Außerdem geht es über den Umfang der gestellten Frage hinaus. –

+0

Was ist falsch daran, den Dialog und die Renderauswahl als zweite Seite in der Seitenleiste loszuwerden? Siehe oben. In diesem Fall können alle Eingabedaten in der Web-App gespeichert werden –

Verwandte Themen