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

شما می‌توانید کد Apps Script و 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 will always be served!</p>
    <? } else  { ?>
      <p>This will never be 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() آمده است:

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