Служба HTML: HTML-шаблон

Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.

Вы можете смешивать код Apps Script и HTML для создания динамических страниц с минимальными усилиями. Если вы использовали язык шаблонов, который смешивает код и HTML, например PHP, ASP или JSP, синтаксис должен показаться вам знакомым.

скриптлеты

Шаблоны сценариев приложений могут содержать три специальных тега, называемых сценариями. Внутри скриптлета вы можете написать любой код, который будет работать в обычном файле скрипта приложений: скриптлеты могут вызывать функции, определенные в других файлах кода, ссылаться на глобальные переменные или использовать любой из API скриптов приложений. Вы даже можете определять функции и переменные внутри скриптлетов, с оговоркой, что они не могут быть вызваны функциями, определенными в файлах кода или других шаблонах.

Если вы вставите приведенный ниже пример в редактор скриптов, содержимое <?= ... ?> ( печатный скриптлет ) будет выделено курсивом. Этот код, выделенный курсивом, запускается на сервере до того, как страница будет предоставлена ​​пользователю . Поскольку код скриптлета выполняется до обслуживания страницы, он может выполняться только один раз для каждой страницы; в отличие от клиентских функций JavaScript или Apps Script, которые вы вызываете через google.script.run , скриптлеты не могут выполняться снова после загрузки страницы.

Код.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

Индекс.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    Hello, World! The time is <?= new Date() ?>.
  </body>
</html>

Обратите внимание, что функция doGet() для шаблонного HTML отличается от примеров для создания и обслуживания базового HTML . Показанная здесь функция создает объект HtmlTemplate из HTML-файла, затем вызывает его метод Assessment evaluate() для выполнения скриптлетов и преобразования шаблона в объект HtmlOutput , который сценарий может предоставить пользователю.

Стандартные скриптлеты

Стандартные скриптлеты, использующие синтаксис <? ... ?> , выполнить код без явного вывода содержимого на страницу. Однако, как показывает этот пример, результат выполнения кода внутри скриптлета может по-прежнему влиять на содержимое HTML за пределами скриптлета:

Код.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

Индекс.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <? if (true) { ?>
      <p>This will always be served!</p>
    <? } else  { ?>
      <p>This will never be served.</p>
    <? } ?>
  </body>
</html>

Печать скриптлетов

Скриптлеты печати, которые используют синтаксис <?= ... ?> , выводят результаты своего кода на страницу с использованием контекстного экранирования.

Контекстное экранирование означает, что Apps Script отслеживает контекст вывода на странице — внутри HTML-атрибута, внутри тега script на стороне клиента или где-либо еще — и автоматически добавляет escape-символы для защиты от атак межсайтового скриптинга (XSS) .

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

Код.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

Индекс.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <?= 'My favorite Google products:' ?>
    <? var data = ['Gmail', 'Docs', 'Android'];
      for (var i = 0; i < data.length; i++) { ?>
        <b><?= data[i] ?></b>
    <? } ?>
  </body>
</html>

Обратите внимание, что сценарий печати выводит только значение своего первого оператора; все остальные операторы ведут себя так, как если бы они содержались в стандартном скриптлете. Так, например, скрипт <?= 'Hello, world!'; 'abc' ?> печатает только "Hello, world!"

Принудительная печать скриптлетов

Скриптлеты с принудительной печатью, которые используют синтаксис <?!= ... ?> , аналогичны печати скриптлетов, за исключением того, что они избегают контекстного экранирования.

Контекстное экранирование важно, если ваш сценарий допускает ненадежный пользовательский ввод. Напротив, вам потребуется выполнить принудительную печать, если выходные данные скриптлета преднамеренно содержат HTML или скрипты, которые вы хотите вставить точно так, как указано.

Как правило, используйте скрипты для печати, а не принудительную печать скриптлетов, если только вы не знаете, что вам нужно печатать HTML или JavaScript без изменений.

Код скрипта приложений в скриптлетах

Скриптлеты не ограничены выполнением обычного JavaScript; вы также можете использовать любой из следующих трех методов, чтобы предоставить вашим шаблонам доступ к данным Apps Script.

Помните, однако, что, поскольку код шаблона выполняется до того, как страница будет предоставлена ​​пользователю, эти методы могут передавать на страницу только начальный контент. Для интерактивного доступа к данным Apps Script со страницы используйте API google.script.run .

Вызов функций Apps Script из шаблона

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

Код.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

function getData() {
  return SpreadsheetApp
      .openById('1234567890abcdefghijklmnopqrstuvwxyz')
      .getActiveSheet()
      .getDataRange()
      .getValues();
}

Индекс.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <? var data = getData(); ?>
    <table>
      <? for (var i = 0; i < data.length; i++) { ?>
        <tr>
          <? for (var j = 0; j < data[i].length; j++) { ?>
            <td><?= data[i][j] ?></td>
          <? } ?>
        </tr>
      <? } ?>
    </table>
  </body>
</html>

Вызов API скриптов приложений напрямую

Вы также можете использовать код Apps Script непосредственно в скриптлетах. В этом примере достигается тот же результат, что и в предыдущем примере, за счет загрузки данных в сам шаблон, а не через отдельную функцию.

Код.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

Индекс.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <? var data = SpreadsheetApp
        .openById('1234567890abcdefghijklmnopqrstuvwxyz')
        .getActiveSheet()
        .getDataRange()
        .getValues(); ?>
    <table>
      <? for (var i = 0; i < data.length; i++) { ?>
        <tr>
          <? for (var j = 0; j < data[i].length; j++) { ?>
            <td><?= data[i][j] ?></td>
          <? } ?>
        </tr>
      <? } ?>
    </table>
  </body>
</html>

Отправка переменных в шаблоны

Наконец, вы можете поместить переменные в шаблон, назначив их как свойства объекта HtmlTemplate . И снова этот пример дает тот же результат, что и предыдущие примеры.

Код.gs

function doGet() {
  var t = HtmlService.createTemplateFromFile('Index');
  t.data = SpreadsheetApp
      .openById('1234567890abcdefghijklmnopqrstuvwxyz')
      .getActiveSheet()
      .getDataRange()
      .getValues();
  return t.evaluate();
}

Индекс.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <table>
      <? for (var i = 0; i < data.length; i++) { ?>
        <tr>
          <? for (var j = 0; j < data[i].length; j++) { ?>
            <td><?= data[i][j] ?></td>
          <? } ?>
        </tr>
      <? } ?>
    </table>
  </body>
</html>

Шаблоны отладки

Шаблоны могут быть сложными для отладки, поскольку код, который вы пишете, не выполняется напрямую; вместо этого сервер преобразует ваш шаблон в код, а затем выполняет полученный код.

Если неясно, как шаблон интерпретирует ваши скриптлеты, два метода отладки в классе HtmlTemplate могут помочь вам лучше понять, что происходит.

получить код()

getCode() возвращает строку, содержащую код, созданный сервером из шаблона. Если вы зарегистрируете код, а затем вставите его в редактор скриптов, вы сможете запустить его и отладить, как обычный код скрипта приложений.

Вот простой шаблон, который снова отображает список продуктов Google, за которым следует результат getCode() :

Код.gs

function myFunction() {
  Logger.log(HtmlService
      .createTemplateFromFile('Index')
      .getCode());
}

Индекс.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <?= 'My favorite Google products:' ?>
    <? var data = ['Gmail', 'Docs', 'Android'];
      for (var i = 0; i < data.length; i++) { ?>
        <b><?= data[i] ?></b>
    <? } ?>
  </body>
</html>

ЖУРНАЛ (ОЦЕНКА)

(function() { var output = HtmlService.initTemplate(); output._ =  '<!DOCTYPE html>\n';
  output._ =  '<html>\n' +
    '  <head>\n' +
    '    <base target=\"_top\">\n' +
    '  </head>\n' +
    '  <body>\n' +
    '    '; output._$ =  'My favorite Google products:' ;
  output._ =  '    ';  var data = ['Gmail', 'Docs', 'Android'];
        for (var i = 0; i < data.length; i++) { ;
  output._ =  '        <b>'; output._$ =  data[i] ; output._ =  '</b>\n';
  output._ =  '    ';  } ;
  output._ =  '  </body>\n';
  output._ =  '</html>';
  /* End of user code */
  return output.$out.append('');
})();

получить код с комментариями ()

getCodeWithComments() похож на getCode() , но возвращает оцененный код в виде комментариев, которые отображаются рядом с исходным шаблоном.

Прогулка по оцениваемому коду

Первое, что вы заметите в любом примере оцениваемого кода, — это неявный объект output , созданный методом HtmlService.initTemplate() . Этот метод недокументирован, потому что его нужно использовать только самим шаблонам. output — это специальный объект HtmlOutput с двумя свойствами с необычными именами, _ и _$ , которые являются сокращением для вызова append() и appendUntrusted() .

output имеет еще одно специальное свойство, $out , которое ссылается на обычный объект HtmlOutput , не обладающий этими специальными свойствами. Шаблон возвращает этот обычный объект в конце кода.

Теперь, когда вы понимаете этот синтаксис, остальную часть кода должно быть довольно легко понять. Содержимое HTML за пределами скриптлетов (например, тег b ) добавляется с помощью output._ = (без контекстного экранирования ), а скриптлеты добавляются как JavaScript (с контекстным экранированием или без него, в зависимости от типа скриптлета).

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

Иерархия комментариев

Поскольку оцениваемый код сохраняет номера строк, комментарии внутри скриптлетов могут закомментировать другие скриптлеты и даже HTML-код. Эти примеры показывают несколько удивительных эффектов комментариев:

<? var x; // a comment ?> This sentence won't print because a comment begins inside a scriptlet on the same line.

<? var y; // ?> <?= "This sentence won't print because a comment begins inside a scriptlet on the same line.";
output.append("This sentence will print because it's on the next line, even though it's in the same scriptlet.”) ?>

<? doSomething(); /* ?>
This entire block is commented out,
even if you add a */ in the HTML
or in a <script> */ </script> tag,
<? until you end the comment inside a scriptlet. */ ?>