Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can an App Script detect if the onOpen method is called with a Doc, Sheet, or other type of document?

In an onOpen method, how can the document type be determined?

From the Quickstart: Add-on for Google Docs the following code is suggested:

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

However, when a Google Sheet is opened the script throws an exception:

Exception: Cannot call DocumentApp.getUi() from this context. at onOpen(Code:9:15)

There should be a test, first, detecting the document type context that is being opened, allowing the script to select if and how it will add menu items. How to do that? The reference for onOpen indicates e.source will be a different type, but type of e.source is only object.

Desire is something like:

function onOpen(e) {
  if (/* answer to this question: test if onOpen called for Doc only */) {
    DocumentApp.getUi().createAddonMenu()
        .addItem('Start', 'showSidebar')
        .addToUi(); 
  }
}
like image 469
Vincent Scheib Avatar asked Aug 26 '19 04:08

Vincent Scheib


2 Answers

  • You want to detect the mimeType of Google Docs when the Google Docs is opened. Then, you want to retrieve the object of doc.
  • You want to achieve this using Google Apps Script.

If my understanding is correct, how about this answer? Please think of this as just one of several answers.

Solution:

In this sample script, it retrieves the active document of the container-bound script when the Google Docs is opened. As the sample situation, when this script is used for the container-bound script of Spreadsheet, DocumentApp.getActiveDocument(), SlidesApp.getActivePresentation() and FormApp.getActiveForm() return null. And only SpreadsheetApp.getActiveSpreadsheet() returns the object. This method uses this situation.

Sample script:

The sample script is as follows.

function onOpen() {
  var docObject = DocumentApp.getActiveDocument() ? DocumentApp :
      SpreadsheetApp.getActiveSpreadsheet() ? SpreadsheetApp :
      SlidesApp.getActivePresentation() ? SlidesApp :
      FormApp.getActiveForm() ? FormApp : null;

  // When this is used for your script, it becomes as follows.
  docObject.getUi().createAddonMenu()
        .addItem('Start', 'showSidebar')
        .addToUi();
}
  • For example, when above script is put to Google Document, docObject becomes the object of DocumentApp. And docObject.getUi().createAddonMenu().addItem('Start', 'showSidebar').addToUi() works for the Google Document.

Note:

  • In this script, the following 4 scopes are used.
    • https://www.googleapis.com/auth/documents
    • https://www.googleapis.com/auth/forms
    • https://www.googleapis.com/auth/presentations
    • https://www.googleapis.com/auth/spreadsheets
  • For example, if you are not required to check the Google Form, please remove FormApp.getActiveForm() ? FormApp :.
  • Above script works by the simple trigger. But if you add other methods, it might required to use the installable trigger. Please be careful this.

References:

  • Class DocumentApp
  • Class SpreadsheetApp
  • Class SlidesApp
  • Class FormApp

If I misunderstood your question and this was not the direction you want, I apologize.

Edit:

At first, I apologize I misunderstood your goal. From your updated question, I could understand as follows.

  • You want to run the script when the parent of the container-bound script is only Google Document.

If my understanding is correct, when the method of my answer is used, how about the following modification?

From:

if (/* answer to this question: test if onOpen called for Doc only */) {

To:

if (DocumentApp.getActiveDocument()) {
  • In this case, when this is used to Google Docs except for Google Document, DocumentApp.getActiveDocument() returns null. By this, the script in the if statement is not run for Google Docs except for Google Document.
like image 98
Tanaike Avatar answered Sep 20 '22 13:09

Tanaike


Inbuilt global variable's .toString() method usually gives the class name. You can use it to determine the document type.

function onOpen(e){
  const app = this[ e.source + "App" ];//automatically becomes SpreadsheetApp or DocumentApp or any other editor App
  app.getUi()/*Do whatever you want with the Ui object*/;
}
like image 21
TheMaster Avatar answered Sep 18 '22 13:09

TheMaster