HTML Hizmeti: Şablonlu HTML

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

Küçük komut dosyaları

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ışacak 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 yazdırma komut dosyası parçası) italik olarak görünür. İtalik olarak belirtilen kod, sayfa kullanıcıya sunulmadan önce sunucuda çalışır. Scriptlet kodu, sayfa sunulmadan önce yürütüldüğünden sayfa başına yalnızca bir kez çalıştırılabilir. google.script.run aracılığıyla çağırdığınız istemci tarafı JavaScript veya Apps Komut Dosyası işlevlerinin aksine, scriptlet'ler 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 vermeden 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 will always be served!</p>
    <? } else  { ?>
      <p>This will never be served.</p>
    <? } ?>
  </body>
</html>

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

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

Bağlama duyarlı kaçış, Apps Komut Dosyası'nın sayfadaki çıkış bağlamını (bir HTML özelliği içinde, istemci tarafı script etiketi 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 küçük komut dosyalarının yalnızca ilk ifadesinin değerini çıkardığını unutmayın. Geriye kalan tüm ifadeler, standart bir küçük komut dosyası içinde yer alıyormuş gibi davranır. Bu nedenle, örneğin <?= 'Hello, world!'; 'abc' ?> yalnızca "Hello, world!" (Merhaba dünya!) yazdırı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, komut dosyası parçacığınızın çıkışı, belirtildiği gibi eklemek istediğiniz HTML veya komut dosyalarını kasıtlı olarak içeriyorsa yazdırmayı zorlamanı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 komut dosyaları yerine yazdırma komut dosyalarını kullanın.

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

Scriptlet'ler 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 Apps Script verilerine etkileşimli olarak erişmek için google.script.run API'yi kullanın.

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

Scriptlet'ler, Apps Komut Dosyası kod 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 Script 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, şablonun kendisinde 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>

Şablonlarda hata ayıklama

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ür ve ardından ortaya çıkan kodu yürütür.

Şablonun, komut dosyalarınızı nasıl yorumladığı net değilse HtmlTemplate sınıfındaki iki hata ayıklama yöntemi, neler olduğunu 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 kaydederseniz, komut dosyası düzenleyiciye yapıştırıp normal Apps Komut Dosyası kodu gibi çalıştırabilir ve hata ayıklayabilirsiniz.

Aşağıda, Google ürünlerinin listesini tekrar gösteren basit şablon ve getCode() işleminin sonucu yer almaktadır:

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

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

Değerlendirilen kodda gezinme

Değerlendirilen kodun her iki örneğinde de ilk fark edeceğiniz şey, HtmlService.initTemplate() yöntemiyle oluşturulan örtülü output nesnesidir. Bu yöntem, yalnızca şablonların kendisi tarafından kullanılması gerektiğinden belgelenmemiştir. output, append() ve appendUntrusted()'i çağırmak için kısaltma 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ı takip etmek oldukça kolay olacaktır. Scriptlet'lerin dışındaki HTML içerikleri (ör. b etiketi) output._ = kullanılarak (bağlama göre kaçış olmadan) eklenir ve scriptlet'ler, türüne bağlı olarak bağlama göre kaçışla veya kaçış olmadan JavaScript olarak eklenir.

Değerlendirilen kodun, şablondaki satır numaralarını koruduğunu unutmayın. Değerlendirilmiş 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 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. */ ?>