HTML Hizmeti: Şablonlu HTML

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

Komut dosyaları

Apps Script şablonları, komut dosyası küçük programları adı verilen üç özel etiket içerebilir. Komut dosyacığınıza normal bir Apps Komut Dosyası dosyasında çalışacak herhangi bir kod yazabilirsiniz: Komut dosyacıklar, diğer kod dosyalarında tanımlanan işlevleri çağırabilir, genel değişkenlere referans verebilir veya Apps Komut Dosyası API'lerinden herhangi birini kullanabilir. Hatta kod dosyalarında veya diğer şablonlarda tanımlanan işlevler tarafından çağrılamayacakları koşuluyla komut dosyalarında işlev ve değişkenler tanımlayabilirsiniz.

Aşağıdaki örneği komut dosyası düzenleyiciye yapıştırırsanız <?= ... ?> etiketinin içeriği (yazdırma komut dosyası) italik olarak görünür. İtalik olarak yazılmış bu kod, sayfa kullanıcıya sunulmadan önce sunucuda çalışır. Komut dosyası kodu, sayfa sunulmadan önce yürütüldüğü için 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 Script 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 yayınlama örneklerinden farklı olduğunu unutmayın. Burada gösterilen işlev, HTML dosyasından bir HtmlTemplate nesnesi oluşturur ve 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 komut dosyaları

<? ... ?> söz dizimini kullanan standart komut dosyaları, sayfaya içerik açıkça göndermeden kodu yürütür. Ancak bu örnekte gösterildiği gibi, komut dosyası içindeki kodun sonucu, komut dosyasının 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 dosyası yazdırma

<?= ... ?> söz dizimini kullanan baskı komut dosyaları, kodlarının sonuçlarını bağlama dayalı kaçış karakteri kullanarak sayfaya gönderir.

Bağlamsal kaçış, Apps Script'in sayfadaki çıktının bağlamını (HTML özelliği içinde, istemci tarafı script etiketi içinde veya başka bir yerde) takip ettiği ve siteler arası komut dosyası çalıştırma (XSS) saldırılarına karşı koruma sağlamak için otomatik olarak kaçış karakterleri eklediği anlamına gelir.

Bu örnekte, ilk yazdırma komut dosyası doğrudan bir dize döndürür. Ardından, bir dizi ve döngü oluşturan standart bir komut dosyası ve ardından dizinin içeriğini döndürmek için başka bir yazdırma komut dosyası gelir.

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>

Baskı komut dosyası yalnızca ilk ifadesinin değerini döndürür. Diğer tüm ifadeler standart bir komut dosyasında yer alıyormuş gibi davranır. Örneğin, <?= 'Hello, world!'; 'abc' ?> komut dosyası yalnızca "Merhaba dünya!" yazdırır.

Komut dosyalarını zorla yazdırma

<?!= ... ?> söz dizimini kullanan zorla yazdırma komut dosyaları, bağlama göre kaçış karakteri kullanmamaları dışında yazdırma komut dosyalarına benzer.

Komut dosyanız güvenilmeyen kullanıcı girişine izin veriyorsa bağlama dayalı kaçış karakteri kullanmak önemlidir. Buna karşılık, komut dosyanızın çıkışı tam olarak belirtildiği gibi eklemek istediğiniz HTML veya komut dosyaları içeriyorsa zorla yazdırmanız gerekir.

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

Komut dosyalarında Apps Komut Dosyası kodu

Komut dosyaları, normal JavaScript çalıştırmakla sınırlı değildir. Şablonlarınıza Apps Script verilerine erişim vermek için aşağıdaki üç teknikten herhangi birini de kullanabilirsiniz.

Ancak şablon kodu sayfa kullanıcıya sunulmadan önce yürütüldüğü için bu tekniklerin yalnızca bir sayfaya ilk içeriği besleyebileceğini unutmayın. Bir sayfadaki Apps Script verilerine etkileşimli olarak erişmek için bunun yerine google.script.run API'yi kullanın.

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

Komut dosyaları, Apps Komut Dosyası kod dosyasında veya kitaplığında tanımlanan tüm işlevleri çağırabilir. Bu örnekte, e-tablodan bir şablona veri çekmenin ve ardından verilerden 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 dosyalarında da kullanabilirsiniz. Bu örnekte, veriler ayrı bir işlev yerine şablonun içine yükleyerek önceki örnekle aynı sonuç elde edilir.

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 gönderme

Son olarak, değişkenleri HtmlTemplate nesnesinin özellikleri olarak atayarak şablona gönderebilirsiniz. Bu örnekte de önceki örneklerle aynı sonuç elde edilir.

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ıklama işlemi zor olabilir. Bunun yerine sunucu, şablonunuzu koda dönüştürür ve elde edilen 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 kaydedip komut dosyası düzenleyiciye yapıştırırsanız normal Apps Komut Dosyası kodları gibi çalıştırabilir ve hata ayıklayabilirsiniz.

Aşağıda, Google ürünlerinin listesini ve ardından getCode() sonucunu gösteren basit şablon verilmiştir:

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İLEN)

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

Değerlendirilen kodu inceleme

Değerlendirilen kod örneklerinin her birinde ilk fark edeceğiniz şey, HtmlService.initTemplate() yöntemi tarafından oluşturulan örtülü output nesnesi olacaktır. Yalnızca şablonların kullanması gerektiği için bu yöntemle ilgili doküman yoktur. output, append() ve appendUntrusted() çağrılarının kısaltması olan _ ve _$ adlı alışılmadık şekilde adlandırılmış iki özelliğe sahip özel bir HtmlOutput nesnesi.

output'ün $out adlı bir özel özelliği daha vardır. Bu özellik, bu özel özelliklere sahip olmayan normal bir HtmlOutput nesnesini ifade eder. Şablon, kodun sonunda bu 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. Komut dosyalarının dışındaki HTML içeriği (b etiketi gibi), output._ = kullanılarak (bağlamdan kaçınma olmadan) eklenir ve komut dosyaları JavaScript olarak eklenir (komut dosyasının türüne bağlı olarak bağlamdan kaçınma ile veya olmadan).

Değerlendirilen kodda şablondaki satır numaralarının korunduğ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.

Yorumların hiyerarşisi

Değerlendirilen kod satır numaralarını koruduğundan, komut dosyası parçaları içindeki yorumların diğer komut dosyalarını ve hatta HTML kodunu yorumlamasına izin verilir. Aşağıdaki örneklerde, yorumların şaşırtıcı etkilerinden bazıları 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. */ ?>