سرویس HTML: HTML الگو

شما می‌توانید از قالب‌ها برای ترکیب کد اسکریپت گوگل اپس و HTML استفاده کنید تا صفحات پویا را با حداقل تلاش بسازید. اگر از زبان‌های قالب‌سازی که کد و HTML را ترکیب می‌کنند، مانند PHP، ASP یا JSP، استفاده کرده‌اید، سینتکس آنها باید برایتان آشنا باشد.

اسکریپتلت‌ها

قالب‌های اسکریپت برنامه‌ها می‌توانند شامل سه تگ ویژه به نام اسکریپت‌لت باشند. درون یک اسکریپت‌لت، می‌توانید هر کدی را که در یک فایل اسکریپت برنامه‌های معمولی کار می‌کند، بنویسید: اسکریپت‌لت‌ها می‌توانند توابع تعریف شده در فایل‌های کد دیگر را فراخوانی کنند، به متغیرهای سراسری ارجاع دهند یا از هر یک از APIهای اسکریپت برنامه‌ها استفاده کنند. شما حتی می‌توانید توابع و متغیرها را درون اسکریپت‌لت‌ها تعریف کنید، با این شرط که آنها نمی‌توانند توسط توابع تعریف شده در فایل‌های کد یا قالب‌های دیگر فراخوانی شوند.

اگر مثال زیر را در ویرایشگر اسکریپت قرار دهید، محتویات برچسب <?= ... ?> (یک اسکریپت‌لت چاپ ) به صورت ایتالیک ظاهر می‌شود. این کد قبل از اینکه صفحه به کاربر ارائه شود، روی سرور اجرا می‌شود. از آنجا که کد اسکریپت‌لت قبل از ارائه صفحه اجرا می‌شود، فقط می‌تواند یک بار در هر صفحه اجرا شود. برخلاف توابع جاوا اسکریپت سمت کلاینت یا اسکریپت برنامه‌ها که از طریق google.script.run فراخوانی می‌کنید، اسکریپت‌لت‌ها نمی‌توانند پس از بارگذاری صفحه دوباره اجرا شوند.

کد.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

فهرست.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    Hello, World! The time is <?= new Date() ?>.
  </body>
</html>

توجه داشته باشید که تابع doGet برای HTML قالب‌بندی شده با مثال‌هایی که برای ایجاد و ارائه HTML پایه ارائه می‌شوند، متفاوت است. تابعی که در اینجا نشان داده شده است، یک شیء HtmlTemplate را از فایل HTML تولید می‌کند، سپس متد evaluate خود را برای اجرای اسکریپت‌لت‌ها و تبدیل الگو به یک شیء HtmlOutput که اسکریپت می‌تواند به کاربر ارائه دهد، فراخوانی می‌کند.

اسکریپت‌های استاندارد

اسکریپت‌های استاندارد که از سینتکس <? ... ?> استفاده می‌کنند، کد را بدون ارسال صریح محتوا به صفحه اجرا می‌کنند. با این حال، همانطور که این مثال نشان می‌دهد، نتیجه کد درون یک اسکریپتلت همچنان می‌تواند بر محتوای HTML خارج از اسکریپتلت تأثیر بگذارد:

کد.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

فهرست.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>

اسکریپت‌های چاپ‌شده، که از سینتکس <?= ... ?> استفاده می‌کنند، نتایج کد خود را با استفاده از escape کردن متنی در صفحه نمایش می‌دهند.

گریز متنی به این معنی است که Apps Script متن خروجی را در صفحه - درون یک ویژگی HTML، درون یک تگ script سمت کلاینت یا هر جای دیگر - ردیابی می‌کند و به طور خودکار کاراکترهای گریز را برای محافظت در برابر حملات اسکریپت نویسی بین سایتی (XSS) اضافه می‌کند.

در این مثال، اولین اسکریپتِ چاپ، مستقیماً یک رشته را چاپ می‌کند؛ به دنبال آن یک اسکریپتِ استاندارد می‌آید که یک آرایه و یک حلقه را تنظیم می‌کند و به دنبال آن یک اسکریپتِ چاپِ دیگر برای چاپ محتویات آرایه می‌آید.

کد.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

فهرست.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>

توجه داشته باشید که یک اسکریپت چاپ فقط مقدار اولین دستور خود را چاپ می‌کند؛ سایر دستورات طوری رفتار می‌کنند که گویی در یک اسکریپت استاندارد قرار دارند. بنابراین، برای مثال، اسکریپت <?= 'Hello, world!'; 'abc' ?> فقط عبارت "Hello, world!" را چاپ می‌کند.

چاپ اجباری اسکریپتلت‌ها

اسکریپت‌لت‌های چاپ اجباری، که از سینتکس <?!= ... ?> استفاده می‌کنند، مانند اسکریپت‌لت‌های چاپ هستند، با این تفاوت که از escape کردن متن اجتناب می‌کنند.

اگر اسکریپت شما اجازه ورود ورودی‌های غیرقابل اعتماد از کاربر را می‌دهد، گریز از متن مهم است. در مقابل، اگر خروجی اسکریپت‌لت شما عمداً شامل HTML یا اسکریپت‌هایی باشد که می‌خواهید دقیقاً مطابق با مشخصات وارد کنید، باید از چاپ اجباری استفاده کنید.

به عنوان یک قاعده کلی، از چاپ اسکریپتلت‌ها به جای چاپ اجباری اسکریپتلت‌ها استفاده کنید، مگر اینکه بدانید که باید HTML یا جاوا اسکریپت را بدون تغییر چاپ کنید.

کد اسکریپت برنامه‌ها در اسکریپت‌لت‌ها

اسکریپت‌لت‌ها محدود به اجرای جاوااسکریپت معمولی نیستند؛ شما همچنین می‌توانید از هر یک از سه تکنیک زیر برای دسترسی قالب‌های خود به داده‌های اسکریپت برنامه‌ها استفاده کنید.

با این حال، به یاد داشته باشید که از آنجا که کد قالب قبل از ارائه صفحه به کاربر اجرا می‌شود، این تکنیک‌ها فقط می‌توانند محتوای اولیه را به صفحه ارائه دهند. برای دسترسی تعاملی به داده‌های اسکریپت برنامه‌ها از یک صفحه، به جای آن از API google.script.run استفاده کنید.

فراخوانی توابع اسکریپت برنامه‌ها از یک الگو

اسکریپت‌لت‌ها می‌توانند هر تابعی را که در یک فایل کد یا کتابخانه‌ی Apps Script تعریف شده است، فراخوانی کنند. این مثال یک راه برای استخراج داده‌ها از یک صفحه گسترده به یک الگو و سپس ساخت یک جدول HTML از داده‌ها را نشان می‌دهد.

کد.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

function getData() {
  return SpreadsheetApp
      .openById('1234567890abcdefghijklmnopqrstuvwxyz')
      .getActiveSheet()
      .getDataRange()
      .getValues();
}

فهرست.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>

فراخوانی مستقیم APIهای اسکریپت برنامه‌ها

همچنین می‌توانید از کد Apps Script مستقیماً در اسکریپت‌لت‌ها استفاده کنید. این مثال با بارگذاری داده‌ها در خود قالب به جای بارگذاری از طریق یک تابع جداگانه، همان نتیجه مثال قبلی را به دست می‌آورد.

کد.gs

function doGet() {
  return HtmlService
      .createTemplateFromFile('Index')
      .evaluate();
}

فهرست.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>

متغیرها را به قالب‌ها ارسال کنید

در نهایت، می‌توانید متغیرها را با اختصاص دادن آنها به عنوان ویژگی‌های شیء HtmlTemplate به یک قالب وارد کنید. بار دیگر، این مثال همان نتیجه مثال‌های قبلی را به دست می‌آورد.

کد.gs

function doGet() {
  var t = HtmlService.createTemplateFromFile('Index');
  t.data = SpreadsheetApp
      .openById('1234567890abcdefghijklmnopqrstuvwxyz')
      .getActiveSheet()
      .getDataRange()
      .getValues();
  return t.evaluate();
}

فهرست.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>

قالب‌های اشکال‌زدایی

اشکال‌زدایی قالب‌ها می‌تواند چالش‌برانگیز باشد زیرا کدی که می‌نویسید مستقیماً اجرا نمی‌شود. در عوض، سرور قالب شما را به کد تبدیل می‌کند، سپس کد حاصل را اجرا می‌کند.

اگر نحوه‌ی تفسیر اسکریپت‌های شما توسط قالب مشخص نیست، دو متد اشکال‌زدایی در کلاس HtmlTemplate می‌توانند به شما در درک بهتر اتفاقات کمک کنند.

تابع getCode

تابع getCode رشته‌ای حاوی کدی را که سرور از روی الگو ایجاد می‌کند، برمی‌گرداند. اگر کد را وارد کنید ، سپس آن را در ویرایشگر اسکریپت قرار دهید، می‌توانید آن را اجرا کرده و مانند کد اسکریپت برنامه‌های معمولی، اشکال‌زدایی کنید .

این الگویی است که دوباره لیستی از محصولات گوگل را نمایش می‌دهد و به دنبال آن نتیجه getCode نمایش داده می‌شود:

کد.gs

function myFunction() {
  Logger.log(HtmlService
      .createTemplateFromFile('Index')
      .getCode());
}

فهرست.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>

گزارش (ارزیابی شده)

(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() است، اما کد ارزیابی شده را به صورت توضیحاتی که در کنار الگوی اصلی ظاهر می‌شوند، برمی‌گرداند.

کد ارزیابی شده را بررسی کنید

اولین چیزی که در هر دو نمونه کد ارزیابی شده متوجه خواهید شد، شیء output ضمنی است که توسط متد HtmlService.initTemplate ایجاد شده است. این متد مستند نشده است زیرا فقط خود قالب‌ها باید از آن استفاده کنند. output یک شیء خاص HtmlOutput با دو ویژگی با نام‌های غیرمعمول _ و _$ است که مخفف فراخوانی append و appendUntrusted هستند.

output یک ویژگی خاص دیگر به نام $out دارد که به یک شیء HtmlOutput معمولی اشاره دارد که این ویژگی‌های خاص را ندارد. قالب، آن شیء معمولی را در انتهای کد برمی‌گرداند.

حالا که این سینتکس را متوجه شدید، می‌توانید بقیه کد را دنبال کنید. محتوای HTML خارج از اسکریپت‌لت‌ها (مانند تگ b ) با استفاده از output._ = (بدون escape متنی ) اضافه می‌شود و اسکریپت‌لت‌ها به صورت جاوا اسکریپت (با یا بدون escape متنی، بسته به نوع اسکریپت‌لت) اضافه می‌شوند.

کد ارزیابی‌شده شماره خطوط را از قالب حفظ می‌کند. اگر هنگام اجرای کد ارزیابی‌شده خطایی دریافت کردید، خط با محتوای معادل در قالب مطابقت دارد.

سلسله مراتب نظرات

از آنجا که کد ارزیابی شده شماره خط را حفظ می‌کند، این امکان وجود دارد که کامنت‌های داخل اسکریپت‌لت‌ها، اسکریپت‌لت‌های دیگر و حتی کد HTML را کامنت کنند. این مثال‌ها چند اثر شگفت‌انگیز کامنت‌ها را نشان می‌دهند:

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