HTML Hizmeti: Şablonlu HTML

Minimum çabayla dinamik sayfalar oluşturmak için Apps Komut Dosyası kodunu ve HTML'yi karıştırabilirsiniz. PHP, ASP veya JSP gibi kod ile HTML'yi karıştıran bir şablon oluşturma dili kullandıysanız söz dizimi size tanıdık gelecektir.

Komut dosyaları

Apps Komut Dosyası şablonları, komut dosyası adı verilen üç özel etiket içerebilir. Bir komut dosyası içinde, normal bir Apps Komut Dosyası'nda çalışacak herhangi bir kod yazabilirsiniz: Komut dosyaları diğer kod dosyalarında tanımlanan işlevleri çağırabilir, genel değişkenlere başvurabilir veya Apps Komut Dosyası API'lerinden herhangi birini kullanabilir. Hatta komut dosyaları içinde işlev ve değişkenler de tanımlayabilirsiniz. Ancak bu öğelerin kod dosyalarında veya diğer şablonlarda tanımlanan işlevler tarafından çağrılamayacağına dikkat edin.

Aşağıdaki örneği komut dosyası düzenleyiciye yapıştırırsanız <?= ... ?> etiketinin (yazdırma komut dosyası) içeriği italik olarak görünür. Bu italik kod, sayfa kullanıcıya sunulmadan önce sunucuda çalışır. Komut dosyası kodu, sayfa sunulmadan önce çalıştığı için sayfa başına yalnızca bir kez çalışabilir. google.script.run üzerinden çağırdığınız istemci taraflı JavaScript veya Apps Komut Dosyası işlevlerinin aksine, komut dosyaları sayfa yüklendikten sonra tekrar yürütülemez.

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>

Şablonlu HTML için doGet() işlevinin, temel HTML oluşturma ve sunma örneklerinden farklı olduğunu unutmayın. Burada gösterilen işlev, HTML dosyasından bir HtmlTemplate nesnesi oluşturur, ardından komut dosyalarını çalıştırmak ve şablonu, komut dosyasının kullanıcıya sunulabileceği bir HtmlOutput nesnesine dönüştürmek için evaluate() yöntemini çağırır.

Standart komut dosyaları

<? ... ?> söz dizimini kullanan standart komut dosyaları, sayfaya açıkça içerik çıkışı olmadan kod yürütür. Ancak bu örnekte gösterildiği gibi, bir komut dosyası içindeki kodun sonucu, komut dosyası dışındaki HTML içeriğini etkilemeye devam edebilir:

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>

Komut dosyalarını yazdırma

<?= ... ?> söz dizimini kullanan komut dosyalarını yazdırmak, içeriğe dayalı kaçış yöntemini kullanarak kodlarının sonuçlarını sayfaya çıkarır.

İçeriğe dayalı çıkış, Apps Komut Dosyası'nın sayfadaki (bir HTML özelliğinin içinde, istemci tarafı script etiketinin içinde veya başka herhangi bir yerde) çıkış bağlamını izlediği ve siteler arası komut dosyası çalıştırma (XSS) saldırılarına karşı koruma sağlamak için otomatik olarak çıkış karakterleri eklediği anlamına gelir.

Bu örnekte, yazdırılan ilk komut dosyası doğrudan bir dize oluşturur. Bunun ardından, bir dizi ve döngü oluşturan standart bir komut dosyası, ardından da dizinin içeriğinin çıktısını almak için başka bir yazdırma komut dosyası uygulanır.

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>

Yazdırılan komut dosyası uygulamasının yalnızca ilk ifadesinin değerini ürettiğini unutmayın. Geri kalan tüm ifadeler standart bir komut dosyası içinde yer alıyormuş gibi davranır. Örneğin, <?= 'Hello, world!'; 'abc' ?> adlı komut dosyası yalnızca "Merhaba dünya!" yazar

Komut dosyalarını zorunlu olarak yazdırma

<?!= ... ?> söz dizimini kullanan komut dosyalarını zorla yazdırmak, bağlamsal çıkışlardan kaçınmaları dışında komut dosyaları yazdırmaya benzer.

Komut dosyanız güvenilmeyen kullanıcı girişine izin veriyorsa bağlamsal çıkış önemlidir. Buna karşın, komut dosyanızın çıktısı, tam olarak belirtildiği gibi eklemek istediğiniz HTML veya komut dosyalarını kasıtlı olarak içeriyorsa zorla yazdırma işlemi yapmanız gerekir.

Genel bir kural olarak, HTML veya JavaScript'i değiştirmeden yazdırmanız gerektiğini bilmiyorsanız komut dosyalarını zorunlu olarak yazdırmak yerine komut dosyalarını yazdırmayı kullanın.

Komut dosyalarındaki Apps Komut Dosyası kodu

Komut dosyaları normal JavaScript'i çalıştırmakla sınırlı değildir. Şablonlarınızın Apps Komut Dosyası verilerine erişmesine izin vermek için aşağıdaki üç teknikten herhangi birini de kullanabilirsiniz.

Ancak şablon kodu, sayfa kullanıcıya sunulmadan önce çalıştırıldığı için bu tekniklerin sayfaya yalnızca ilk içeriği aktarabileceğini unutmayın. Bir sayfadan Apps Komut Dosyası verilerine etkileşimli olarak erişmek için bunun yerine google.script.run API'yi kullanın.

Bir şablondan Apps Komut Dosyası işlevlerini çağırma

Komut dosyası uygulamaları, Apps Komut Dosyası kod dosyasında veya kitaplığında tanımlanan herhangi bir işlevi çağırabilir. Bu örnekte, e-tablodan veri çekip şablona dönüştürmenin bir yolu gösterilmektedir.

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>

Apps Komut Dosyası API'lerini doğrudan çağırma

Apps Komut Dosyası kodunu doğrudan komut dosyalarında da kullanabilirsiniz. Bu örnekte, önceki örnekle aynı sonuca ulaşmak için veriler ayrı bir işlev yerine şablonun içinde yüklenir.

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>

Değişkenleri şablonlara aktarma

Son olarak, değişkenleri HtmlTemplate nesnesinin özellikleri olarak atayarak bir şablona aktarabilirsiniz. Bu örnek de aynı şekilde önceki örneklerle aynı sonucu verir.

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>

Hata ayıklama şablonları

Yazdığınız kod doğrudan yürütülmediği için şablonlarda hata ayıklamak zor olabilir. Bunun yerine sunucu, şablonunuzu koda dönüştürüp ortaya çıkan kodu yürütür.

Şablonun komut dosyalarınızı nasıl yorumladığı tam olarak anlaşılmıyorsa HtmlTemplate sınıfındaki iki hata ayıklama yöntemi, neler olup bittiğini daha iyi anlamanıza yardımcı olabilir.

getCode()

getCode(), sunucunun şablondan oluşturduğu kodu içeren bir dize döndürür. Kodu günlüğe kaydeder ve ardından komut dosyası düzenleyiciye yapıştırırsanız kodu çalıştırabilir ve normal Apps Komut Dosyası kodu gibi hata ayıklama yapabilirsiniz.

Google ürünlerinin listesini ve ardından getCode() sonucunu gösteren basit şablonu burada görebilirsiniz:

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>

GÜNLÜK (DEĞERLENDİRİLDİ)

(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(), getCode() özelliğine benzer, ancak değerlendirilen kodu orijinal şablonla yan yana görünen yorumlar olarak döndürür.

Değerlendirilen kodun gözden geçirmesi

Değerlendirilen kod örneğinde ilk olarak HtmlService.initTemplate() yöntemiyle oluşturulan örtülü output nesnesini görürsünüz. Bu yöntem yalnızca şablonların kullanması gerektirdiğinden belgelenmemiştir. output, append() ve appendUntrusted() çağrısının kısaltması olan _ ve _$ adlı, olağan dışı iki özelliğe sahip özel bir HtmlOutput nesnesidir.

output, $out adlı özel bir özelliğe daha sahiptir. Bu özellik, bu özel özelliklere sahip olmayan normal HtmlOutput nesnesine işaret eder. Şablon, kodun sonunda bu normal nesneyi döndürür.

Artık bu söz dizimini anladığınıza göre, kodun geri kalanının takibi biraz kolay olacaktır. Komut dosyaları dışındaki HTML içeriği (b etiketi gibi) output._ = kullanılarak eklenir (içeriğe dayalı çıkış yapılmadan) ve komut dosyaları JavaScript olarak eklenir (komut dosyası türüne bağlı olarak bağlamsal çıkış yapılarak veya olmadan).

Değerlendirilen kodun şablondaki satır numaralarını koruduğunu unutmayın. Değerlendirilen kodu çalıştırırken hata alırsanız satır, şablondaki eşdeğer içeriğe karşılık gelir.

Yorum hiyerarşisi

Değerlendirilen kod satır numaralarını koruduğundan, komut dosyalarındaki yorumlar diğer komut dosyalarını, hatta HTML kodunu yorumlayabilir. Aşağıdaki örneklerde yorumların birkaç şaşırtıcı etkisini görebilirsiniz:

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