HTML Hizmeti: Şablonlu HTML

Google Apps Komut Dosyası kodu ile HTML'yi karıştırarak minimum çabayla dinamik sayfalar oluşturmak için şablonları kullanabilirsiniz. PHP, ASP veya JSP gibi kod ve HTML'yi karıştıran şablon oluşturma dillerini kullandıysanız söz dizimi size tanıdık gelecektir.

Scriptlet'ler

Apps Komut Dosyası şablonları, scriptlet adı verilen üç özel etiket içerebilir. Bir komut dosyası parçacığı içinde, normal bir Apps Komut Dosyası dosyasında çalışan herhangi bir kodu yazabilirsiniz: Komut dosyası parçacıkları, diğer kod dosyalarında tanımlanan işlevleri çağırabilir, genel değişkenlere başvurabilir veya Apps Komut Dosyası API'lerinin herhangi birini kullanabilir. İşlevlerin ve değişkenlerin, kod dosyalarında veya diğer şablonlarda tanımlanan işlevler tarafından çağrılamaması koşuluyla, bunları scriptlet'lerde de tanımlayabilirsiniz.

Aşağıdaki örneği komut dosyası düzenleyiciye yapıştırırsanız <?= ... ?> etiketinin içeriği (bir print scriptlet) italik olarak görünür. Bu kod, sayfa kullanıcıya sunulmadan önce sunucuda çalışır. Scriptlet kodu, sayfa yayınlanmadan önce yürütüldüğünden sayfa başına yalnızca bir kez çalıştırılabilir. google.script.run üzerinden çağırdığınız istemci tarafı JavaScript veya Apps Komut Dosyası işlevlerinin aksine, komut dosyası parçacıkları 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ı yürütmek ve şablonu, komut dosyasının kullanıcıya sunabileceği bir HtmlOutput nesnesine dönüştürmek için evaluate yöntemini çağırır.

Standart küçük komut dosyaları

<? ... ?> söz dizimini kullanan standart küçük komut dosyaları, içeriği sayfaya açıkça aktarmadan kodu yürütür. Ancak bu örnekte gösterildiği gibi, bir scriptlet'in içindeki kodun sonucu, scriptlet'in 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 is always served!</p>
    <? } else  { ?>
      <p>This is never served.</p>
    <? } ?>
  </body>
</html>

<?= ... ?> sözdizimini kullanan yazdırma komut dosyaları, kodlarının sonuçlarını bağlamsal kaçış kullanarak sayfaya verir.

Bağlama duyarlı kaçış, Apps Komut Dosyası'nın sayfadaki çıkış bağlamını (bir HTML özelliğinin içinde, istemci tarafı script etiketinin içinde veya başka bir yerde) takip etmesi ve siteler arası komut dosyası çalıştırma (XSS) saldırılarına karşı koruma sağlamak için kaçış karakterlerini otomatik olarak eklemesi anlamına gelir.

Bu örnekte, ilk yazdırma komut dosyası doğrudan bir dize çıkışı verir. Bunu, bir dizi ve döngü oluşturan standart bir komut dosyası ve ardından dizinin içeriğini çıkış olarak veren başka bir yazdırma komut dosyası izler.

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ırma komut dosyası parçacıklarının yalnızca ilk ifadesinin değerini çıkardığını unutmayın. Geriye kalan ifadeler, standart bir komut dosyası parçacığına dahil edilmiş gibi davranır. Bu nedenle, örneğin <?= 'Hello, world!'; 'abc' ?> yalnızca "Merhaba dünya!" yazdırılır.

Küçük komut dosyalarını zorunlu olarak yazdırma

<?!= ... ?> söz dizimini kullanan zorunlu yazdırma komut dosyaları, bağlamsal kaçıştan kaçınmaları dışında yazdırma komut dosyalarına benzer.

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

Genel bir kural olarak, HTML veya JavaScript'i değiştirmeden yazdırmanız gerektiğini bilmediğiniz sürece zorunlu yazdırma küçük komut dosyaları yerine yazdırma küçük komut dosyalarını kullanın.

Komut dosyası parçacıklarındaki Apps Komut Dosyası kodu

Küçük komut dosyaları, normal JavaScript çalıştırmakla sınırlı değildir. Şablonlarınızın Apps Komut Dosyası verilerine erişmesini sağlamak için aşağıdaki üç teknikten herhangi birini de kullanabilirsiniz.

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

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

Scriptlet'ler, Apps Komut Dosyası kodu dosyasında veya kitaplığında tanımlanan herhangi bir işlevi çağırabilir. Bu örnekte, bir e-tablodaki verileri şablona aktarmanın ve ardından bu verilerden bir HTML tablosu oluşturmanın 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 dosyası parçacıklarında da kullanabilirsiniz. Bu örnek, verileri ayrı bir işlev aracılığıyla değil, doğrudan şablona yükleyerek önceki örnekle aynı sonucu elde eder.

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 ö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ğinden şablonlarda hata ayıklama yapmak zor olabilir. Bunun yerine sunucu, şablonunuzu koda dönüştürür ve sonuçtaki kodu çalıştırır.

Şablonun, küçük komut dosyalarınızı nasıl yorumladığı açıkça anlaşılmıyorsa HtmlTemplate sınıfındaki iki hata ayıklama yöntemi, neler olduğunu daha iyi anlamanıza yardımcı olabilir.

getCode işlevi

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

Aşağıda, Google ürünlerinin listesini tekrar gösteren şablon ve getCode sonucunu bulabilirsiniz:

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 (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 işlevi

getCodeWithComments işlevi getCode() işlevine benzer ancak değerlendirilen kodu, orijinal şablonla yan yana görünen yorumlar olarak döndürür.

Değerlendirilen kodu inceleme

Değerlendirilen kodun her iki örneğinde de ilk fark edeceğiniz şey, output yöntemiyle oluşturulan örtülü HtmlService.initTemplate nesnesidir. Bu yöntem, yalnızca şablonların kendisi tarafından kullanılması gerektiğinden belgelenmemiştir. output, append ve appendUntrusted işlevlerini çağırmak için kullanılan kısaltmalar olan _ ve _$ adlı iki alışılmadık adlandırılmış özelliğe sahip özel bir HtmlOutput nesnesidir.

output, bu özel özelliklere sahip olmayan normal bir HtmlOutput nesnesini ifade eden $out adlı bir özel özelliğe daha sahiptir. Şablon, kodun sonunda normal nesneyi döndürür.

Bu söz dizimini anladığınıza göre kodun geri kalanını inceleyebilirsiniz. HTML içeriği, komut dosyası parçacıkları dışında (ör. b etiketi) output._ = kullanılarak eklenir (bağlama göre kaçış olmadan) ve komut dosyası parçacıkları, JavaScript olarak eklenir (bağlama göre kaçış ile veya olmadan, komut dosyası parçacığının türüne bağlı olarak).

Değerlendirilen kod, şablondaki satır numaralarını korur. 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ğu için scriptlet'lerin içindeki yorumlar diğer scriptlet'leri ve hatta HTML kodunu yorum dışı bırakabilir. Bu örneklerde, yorumların bazı şaşırtıcı etkileri gösterilmektedir:

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