Может ли библиотека скриптов Google Spreadsheet Apps содержать диалог пользователя?

Существуют ли ограничения на то, что может быть в библиотеке скриптов приложений, которая будет использоваться таблицами Google? В частности, может ли библиотека включать HTML-диалог?

Я создал скрипт электронной таблицы, который добавляет пункт меню, чтобы предоставить пользователю диалоговое окно. Оно использует HtmlService.createHtmlOutputFromFile('mappingForm').setSandboxMode(HtmlService.SandboxMode.IFRAME)

как описано в https://developers.google.com/apps-script/guides/html/communication. HTML-файл включает в себя HTML, CSS и JavaScript с jQuery. Оно использует google.script.run заполнить диалог данными из электронной таблицы и отправить в нее форму.

Это все прекрасно работает в оригинальной таблице.

Однако мне нужно несколько таблиц, чтобы использовать один и тот же код, поэтому я пытаюсь следовать общей идее сценариев Google Spreadsheet, распространяемых по таблицам (не библиотекам), чтобы иметь основной сценарий с шаблоном электронной таблицы и несколькими копиями.

Я следовал инструкциям на https://developers.google.com/apps-script/guide_libraries чтобы создать библиотеку из исходной электронной таблицы. Когда другая электронная таблица использует библиотеку, я могу отобразить диалоговое окно, но все обратные вызовы на сервер (либо для заполнения диалогового окна, либо для отправки формы) завершаются ошибкой с ошибкой, обнаруженной на стороне браузера google.script.run.withFailureHandler как Error объект со свойствами:

message: "We're sorry, a server error occurred. Please wait a bit and try again."
name: "ScriptError"

Я поместил вызовы Logger в скрипт приложения, чтобы увидеть, вызываются ли функции на стороне сервера, но ни одна из них не срабатывает. Стенограмма выполнения редактора скриптов показывает:

[14-12-27 19: 38: 05: 340 PST] Начало выполнения

[14-12-27 19:38:05:372 PST] Ошибка выполнения: извините, произошла ошибка сервера. Пожалуйста, подождите немного и попробуйте снова. [0,0 секунд всего времени выполнения]

Клиент выполняет вызов, но что-то не удается, прежде чем он достигнет сценария электронной таблицы.

Это заставляет меня задуматься,

  1. Мне нужно сделать что-то по-другому, чтобы код работал как библиотека.
  2. В библиотеках не может быть диалогов.
  3. Есть ошибка сервера.

Спасибо заранее за любые предложения.

1 ответ

Решение

Я смог получить рабочую библиотеку, содержащую диалог HTML, выполнив следующее.

  1. Переместите сценарий и файлы HTML из исходной электронной таблицы в отдельный проект сценария. Обратите внимание на ключ проекта библиотеки на вкладке " Информация " в меню "Файл"> "Свойства проекта...". Это понадобится любой электронной таблице, которая намеревается использовать библиотеку.

  2. Если автономный проект сценария предназначен для использования другими, нажмите кнопку " Поделиться", чтобы сделать его доступным для всех, у кого есть ссылка, иначе он молча потерпит неудачу для них.

  3. Если HTML-диалог должен вызывать функцию библиотеки (для получения или отправки данных), функция библиотеки должна присутствовать в электронной таблице, которая использует библиотеку, или вы получите сообщение об ошибке в консоли JavaScript браузера.

  4. В электронной таблице, которая использует библиотеку: Инструменты> Редактор сценариев... Нажмите Ресурсы> Библиотеки.... В диалоговом окне "Включенные библиотеки" введите ключ автономного проекта в текстовом поле " Найти библиотеку", нажмите " Выбрать", затем выберите соответствующую версию, при необходимости измените идентификатор и сохраните. Значение идентификатора создает объект с тем же именем для использования сценарием электронной таблицы для вызова функций библиотеки. В моем случае это SignupFormResponsesSheet,

  5. В том же редакторе кода редактора сценариев добавьте функции-оболочки, которые вызывают функции библиотеки, в том числе те, которые будут вызываться из диалога HTML. В моей библиотеке есть onOpen() который создает два пункта меню для отображения диалогов HTML, поэтому я добавил

function onOpen() {
    SignupFormResponsesSheet.onOpen();
}

function showMappingForm() {
    SignupFormResponsesSheet.showMappingForm();
}

function showSubmitForm() {
    SignupFormResponsesSheet.showSubmitForm();
}

  1. Мой HTML-диалог имеет несколько обратных вызовов для получения и отправки данных, поэтому вместо написания функции-обертки для каждой из них я добавил одну функцию, чтобы охватить все из них, воспользовавшись тем, как сценарий Apps обрабатывает библиотеку как объект, содержащий функции. Первый аргумент - это строка с именем библиотечной функции для вызова. Любые дополнительные аргументы передаются в библиотечную функцию.

function runSignupFormResponseFunction(funcName, varargs) {
  return SignupFormResponsesSheet[funcName].apply(this,
    Array.prototype.slice.call(arguments, 1));
}

  1. Из-за ограничения, определенного на шаге 3 выше, JavaScript в диалоге HTML использует google.script.run для вызова runSignupFormResponseFunction всякий раз, когда необходимо получить или представить данные. Например, у него есть два списка, которые динамически заполняются данными сервера из библиотеки. getRangeLabels а также getColumnExamples функции (и одна должна быть заполнена до другой), поэтому код

google.script.run
  .withFailureHandler(showError)
  .withSuccessHandler(function(ranges) {
    loadRanges(ranges);
    // once ranges are loaded, load columns
    google.script.run
      .withSuccessHandler(loadColumns)
      .withFailureHandler(showError)
      .runSignupFormResponseFunction("getColumnExamples");
  })
  .runSignupFormResponseFunction("getRangeLabels");

Это сработало для меня сегодня. Я надеюсь, что это работает для тех, кто может найти этот вопрос.

Другие вопросы по тегам