Service HTML: code HTML basé sur un modèle

Vous pouvez combiner du code Apps Script et du code HTML pour créer des pages dynamiques avec un minimum d'efforts. Si vous avez utilisé un langage de création de modèles qui combine du code et du HTML, tel que PHP, ASP ou JSP, la syntaxe doit vous sembler familière.

Scriptlets

Les modèles Apps Script peuvent contenir trois balises spéciales, appelées scriptlets. À l'intérieur un scriptlet, vous pouvez écrire n'importe quel code compatible avec un script Apps Script normal : les scriptlets peuvent appeler des fonctions définies dans d'autres fichiers de code, référencer des variables globales ou utiliser l'une des API Apps Script. Vous pouvez même définir des fonctions et des variables dans des scriptlets, la mise en garde étant qu'elles ne peuvent pas appelées par des fonctions définies dans des fichiers de code ou d'autres modèles.

Si vous collez l'exemple ci-dessous dans l'éditeur de scripts, le contenu du fichier Le tag <?= ... ?> (un scriptlet d'impression) apparaîtra dans en italique. Ce code en italique est exécuté sur le serveur avant que la page ne soit diffusée. pour l'utilisateur. Comme le code de scriptlet s'exécute avant que la page ne soit diffusée, ne peuvent s'exécuter qu'une seule fois par page. contrairement au code JavaScript côté client ou à Apps Script des fonctions que vous appelez google.script.run, les scriptlets ne peuvent pas à nouveau après le chargement de la page.

Code.gs

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

Index.html

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

Notez que la fonction doGet() pour le code HTML modélisé diffère des exemples pour créer et diffuser du code HTML simplifié. La fonction génère une l'objet HtmlTemplate du code HTML fichier, puis appelle sa fonction evaluate() pour exécuter les scriptlets et convertir le modèle en HtmlOutput que le script peuvent être diffusées auprès de l'utilisateur.

Scriptlets standards

Les scriptlets standards, qui utilisent la syntaxe <? ... ?>, exécutent du code sans renvoyant explicitement du contenu sur la page. Toutefois, comme le montre cet exemple, result du code à l'intérieur d'un scriptlet peut quand même avoir une incidence sur le contenu HTML. en dehors du scriptlet:

Code.gs

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

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

Imprimer des scriptlets

Les scriptslets d'impression, qui utilisent la syntaxe <?= ... ?>, génèrent les résultats de leur code dans la page à l'aide de l'échappement contextuel.

Avec l'échappement contextuel, Apps Script garde une trace du contexte de la sortie sur la page, dans un attribut HTML, dans une balise script côté client ou et ajoute automatiquement des caractères d'échappement pour vous protéger contre les attaques par script intersites (XSS).

Dans cet exemple, le premier scriptlet d'impression génère directement une chaîne : c'est suivie d'un scriptlet standard qui configure un tableau et une boucle, puis un autre scriptlet d'impression pour générer le contenu du tableau.

Code.gs

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

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

Notez qu'un scriptlet d'impression n'affiche que la valeur de sa première instruction. toutes les instructions restantes se comportent comme si elles étaient contenues dans un scriptlet. Ainsi, par exemple, le scriptlet <?= 'Hello, world!'; 'abc' ?> uniquement affiche "Hello, world!"

Forcer l'impression de scriptlets

L'impression forcée de scriptlets, qui utilisent la syntaxe <?!= ... ?>, est semblable à l'impression. scriptlets, sauf qu'ils évitent l'échappement contextuel.

L'échappement contextuel est important si votre script autorise des entrées utilisateur non fiables. Par le contraste, vous devrez forcer l'impression si la sortie de votre scriptlet s'affiche de manière intentionnelle contient du code HTML ou des scripts à insérer exactement comme spécifié.

En règle générale, utilisez des scriptlets d'impression plutôt que de forcer l'impression de scriptlets. à moins que vous ne sachiez que vous devez imprimer HTML ou JavaScript tel quel.

Code Apps Script dans des scriptslets

Les scriptlets ne sont pas limités à l'exécution de JavaScript normal. vous pouvez également utiliser des trois techniques suivantes pour permettre à vos modèles d'accéder à Apps Script données.

Gardez toutefois à l'esprit que le code du modèle s'exécute avant que la page ne soit diffusée. pour l'utilisateur, ces techniques permettent uniquement d'alimenter une page avec du contenu initial. Pour y accéder les données Apps Script d'une page de manière interactive, utilisez la google.script.run à la place.

Appeler des fonctions Apps Script à partir d'un modèle

Les scriptlets peuvent appeler n'importe quelle fonction définie dans un fichier de code ou une bibliothèque Apps Script. Cet exemple montre une façon d'extraire les données d'une feuille de calcul dans un modèle, puis créer un tableau HTML à partir des données.

Code.gs

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

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

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

Appeler directement les API Apps Script

Vous pouvez également utiliser le code Apps Script directement dans des scriptlets. Cet exemple produit le même résultat que dans l'exemple précédent en chargeant les données dans le un modèle lui-même plutôt que via une fonction distincte.

Code.gs

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

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

Transférer des variables vers des modèles

Enfin, vous pouvez transférer des variables dans un modèle en les attribuant en tant que propriétés de l'objet HtmlTemplate. Une fois Là encore, cet exemple donne le même résultat que les exemples précédents.

Code.gs

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

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

Modèles de débogage

Les modèles peuvent être difficiles à déboguer, car le code que vous écrivez n'est pas exécuté directement ; le serveur transforme votre modèle en code, puis exécute au code qui en résulte.

S'il n'est pas évident de savoir comment le modèle interprète vos scriptlets, deux de débogage dans La classe HtmlTemplate peut vous aider de mieux comprendre ce qui se passe.

getCode()

getCode() renvoie une chaîne contenant le code que le serveur crée à partir du modèle. Si vous enregistrer les puis collez-le dans l'éditeur de script. Vous pouvez l'exécuter déboguez-la comme d'habitude Code Apps Script.

Voici le modèle simple qui affiche à nouveau une liste de produits Google, suivi du résultat de getCode():

Code.gs

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

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

LOG (ÉVALUÉ)

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

getCodeWithComments() est semblable à getCode(), mais renvoie le code évalué sous forme de commentaires qui apparaîtront à côté du modèle original.

Parcourir le code évalué

La première chose que vous remarquerez dans l'un ou l'autre des exemples de code évalué est l'analyse Objet output créé par la méthode HtmlService.initTemplate(). Cette méthode n'est pas documentée, car seuls les modèles eux-mêmes ont besoin de l'utiliser. output est un un objet HtmlOutput spécial avec des propriétés au nom inhabituel, _ et _$, qui sont un raccourci pour appeler append() et appendUntrusted().

output comporte une autre propriété spéciale, $out, qui fait référence à une propriété HtmlOutput qui ne possède pas ces propriétés spéciales. Le modèle renvoie cet objet normal à la fin du code.

Maintenant que vous comprenez cette syntaxe, le reste du code devrait être assez facile à suivre. Le contenu HTML en dehors des scriptlets (comme la balise b) est ajouté. en utilisant output._ = (sans échappement contextuel) ; et les scriptlets sont ajoutés en tant que JavaScript (avec ou sans échappement contextuel, selon le type de scriptlet).

Notez que le code évalué conserve les numéros de ligne du modèle. Si vous recevez un message d'erreur lors de l'exécution du code évalué, la ligne correspond à la un contenu équivalent dans le modèle.

Hiérarchie des commentaires

Comme le code évalué conserve les numéros de ligne, il est possible que les commentaires à l'intérieur de scriptlets pour mettre en commentaire d'autres scriptlets et même du code HTML. Ces exemples montrent quelques effets surprenants des commentaires:

<? 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. */ ?>