Puoi combinare codice Apps Script e HTML per produrre pagine dinamiche con il minimo sforzo. Se hai utilizzato un linguaggio di templating che combina codice e HTML, ad esempio PHP, ASP o JSP, la sintassi dovrebbe esserti familiare.
Scriptlet
I modelli Apps Script possono contenere tre tag speciali, chiamati scriptlet. All'interno di uno scriptlet, puoi scrivere qualsiasi codice che funzionerebbe in un normale file Apps Script: gli scriptlet possono chiamare funzioni definite in altri file di codice, fare riferimento a variabili globali o utilizzare una qualsiasi delle API Apps Script. Puoi anche definire funzioni e variabili all'interno degli scriptlet, con l'avvertenza che non possono essere chiamate da funzioni definite in file di codice o altri modelli.
Se incolli l'esempio riportato di seguito nell'editor di script, i contenuti del tag <?= ... ?>
(uno scriptlet di stampa) verranno visualizzati in corsivo. Il codice in corsivo viene eseguito sul server prima che la pagina venga mostrata
all'utente. Poiché il codice scriptlet viene eseguito prima della pubblicazione della pagina, può essere eseguito una sola volta per pagina. A differenza delle funzioni JavaScript lato client o Apps Script che chiami tramite google.script.run
, gli scriptlet non possono essere eseguiti di nuovo dopo il caricamento della pagina.
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>
Tieni presente che la funzione doGet()
per l'HTML basato su modelli è diversa dagli esempi
per la creazione e la pubblicazione di HTML di base. La funzione
mostrata qui genera un
oggetto HtmlTemplate
dal file
HTML, quindi chiama il metodo
evaluate()
per
eseguire gli scriptlet e convertire il modello in un
oggetto HtmlOutput
che lo script
può inviare all'utente.
Scriptlet standard
Gli scriptlet standard, che utilizzano la sintassi <? ... ?>
, eseguono il codice senza
generare esplicitamente contenuti nella pagina. Tuttavia, come mostra questo esempio, il
risultato del codice all'interno di uno scriptlet può comunque influire sui contenuti HTML
al di fuori dello 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>
Scriptlet di stampa
Gli scriptlet di stampa, che utilizzano la sintassi <?= ... ?>
, restituiscono i risultati
del codice nella pagina utilizzando l'escape contestuale.
L'escape contestuale significa che Apps Script tiene traccia del contesto dell'output nella pagina, all'interno di un attributo HTML, all'interno di un tag script
lato client o in qualsiasi altro punto, e aggiunge automaticamente caratteri di escape per proteggere dagli attacchi cross-site scripting (XSS).
In questo esempio, il primo scriptlet di stampa restituisce direttamente una stringa. È seguito da uno scriptlet standard che configura un array e un ciclo, seguito da un altro scriptlet di stampa per restituire i contenuti dell'array.
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>
Tieni presente che uno scriptlet di stampa restituisce solo il valore della prima istruzione;
le istruzioni rimanenti si comportano come se fossero contenute in uno scriptlet standard. Ad esempio, lo scriptlet <?= 'Hello, world!'; 'abc' ?>
stampa
solo "Hello, world!".
Scriptlet di stampa forzata
Gli scriptlet di stampa forzata, che utilizzano la sintassi <?!= ... ?>
, sono simili agli scriptlet di stampa, ma evitano l'escape contestuale.
L'escape contestuale è importante se lo script consente l'input di utenti non attendibili. Al contrario, dovrai forzare la stampa se l'output dello scriptlet contiene intenzionalmente codice HTML o script che vuoi inserire esattamente come specificato.
Come regola generale, utilizza gli scriptlet di stampa anziché quelli di stampa forzata, a meno che tu non sappia di dover stampare HTML o JavaScript senza modifiche.
Codice Apps Script negli scriptlet
Gli scriptlet non sono limitati all'esecuzione di JavaScript normale. Puoi anche utilizzare una delle tre tecniche seguenti per consentire ai tuoi modelli di accedere ai dati di Apps Script.
Tieni presente, tuttavia, che poiché il codice del modello viene eseguito prima che la pagina venga mostrata
all'utente, queste tecniche possono fornire solo i contenuti iniziali a una pagina. Per accedere
in modo interattivo ai dati di Apps Script da una pagina, utilizza invece l'API
google.script.run
.
Chiamare le funzioni Apps Script da un modello
Gli scriptlet possono chiamare qualsiasi funzione definita in un file di codice o in una libreria Apps Script. Questo esempio mostra un modo per estrarre i dati da un foglio di lavoro in un modello, quindi costruire una tabella HTML dai dati.
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>
Chiamata diretta delle API Apps Script
Puoi anche utilizzare il codice Apps Script direttamente negli scriptlet. Questo esempio ottiene lo stesso risultato dell'esempio precedente caricando i dati nel modello stesso anziché tramite una funzione separata.
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>
Inserimento di variabili nei modelli
Infine, puoi inserire le variabili in un modello assegnandole come proprietà
dell'oggetto HtmlTemplate
. Ancora una volta, questo esempio ottiene lo stesso risultato degli esempi precedenti.
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>
Eseguire il debug dei modelli
Il debug dei modelli può essere difficile perché il codice che scrivi non viene eseguito direttamente. Il server trasforma il modello in codice, quindi esegue il codice risultante.
Se non è ovvio come il modello interpreta gli scriptlet, due metodi di debug nella classe HtmlTemplate
possono aiutarti a capire meglio cosa sta succedendo.
getCode()
getCode()
restituisce una stringa contenente il codice creato dal server dal modello. Se registri il codice e lo incolli nell'editor di script, puoi eseguirlo ed eseguire il debug come faresti con il normale codice Apps Script.
Ecco il modello semplice che mostra di nuovo un elenco di prodotti Google,
seguito dal risultato di 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 (VALUTATO)
(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()
è simile a getCode()
, ma restituisce il codice valutato come commenti che
vengono visualizzati affiancati al modello originale.
Esaminare il codice valutato
La prima cosa che noterai in entrambi i campioni di codice valutato è l'oggetto
output
implicito creato dal metodo HtmlService.initTemplate()
. Questo metodo
non è documentato perché devono utilizzarlo solo i modelli stessi. output
è un oggetto
speciale HtmlOutput
con due
proprietà con nomi insoliti, _
e _$
, che sono abbreviazioni per chiamare
append()
e
appendUntrusted()
.
output
ha un'altra proprietà speciale, $out
, che si riferisce a un oggetto HtmlOutput
normale che non possiede queste proprietà speciali. Il modello
restituisce l'oggetto normale alla fine del codice.
Ora che hai compreso questa sintassi, il resto del codice dovrebbe essere abbastanza facile
da seguire. I contenuti HTML al di fuori degli scriptlet (come il tag b
) vengono aggiunti
utilizzando output._ =
(senza escape contestuale),
mentre gli scriptlet vengono aggiunti come JavaScript (con o senza escape contestuale,
a seconda del tipo di scriptlet).
Tieni presente che il codice valutato conserva i numeri di riga del modello. Se ricevi un errore durante l'esecuzione del codice valutato, la riga corrisponderà al contenuto equivalente nel modello.
Gerarchia dei commenti
Poiché il codice valutato conserva i numeri di riga, è possibile che i commenti all'interno degli scriptlet commentino altri scriptlet e persino codice HTML. Questi esempi mostrano alcuni effetti sorprendenti dei commenti:
<? 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. */ ?>