एचटीएमएल सेवा: टेंप्लेट वाला एचटीएमएल

कम से कम मेहनत के साथ डाइनैमिक पेज बनाने के लिए, Apps Script कोड और एचटीएमएल को मिलाया जा सकता है. अगर आपने कोड और एचटीएमएल को मिलाने वाली टेंप्लेट लैंग्वेज का इस्तेमाल किया है, जैसे कि PHP, ASP या JSP, तो आपको सिंटैक्स के बारे में पता होना चाहिए.

स्क्रिप्टलेट

Apps Script टेंप्लेट में तीन खास टैग हो सकते हैं, जिन्हें स्क्रिप्टलेट कहा जाता है. स्क्रिप्टलेट में, ऐसा कोई भी कोड लिखा जा सकता है जो सामान्य Apps Script फ़ाइल में काम करता हो: स्क्रिप्टलेट, दूसरी कोड फ़ाइलों में तय किए गए फ़ंक्शन को कॉल कर सकते हैं, ग्लोबल वैरिएबल का रेफ़रंस दे सकते हैं या Apps Script के किसी भी एपीआई का इस्तेमाल कर सकते हैं. स्क्रिप्टलेट में फ़ंक्शन और वैरिएबल भी तय किए जा सकते हैं. हालांकि, कोड फ़ाइलों या अन्य टेंप्लेट में तय किए गए फ़ंक्शन, इन फ़ंक्शन और वैरिएबल को कॉल नहीं कर सकते.

अगर नीचे दिए गए उदाहरण को स्क्रिप्ट एडिटर में चिपकाया जाता है, तो <?= ... ?> टैग (प्रिंटिंग स्क्रिप्टलेट) का कॉन्टेंट इटैलिक में दिखेगा. इटैलिक में लिखा गया यह कोड, पेज को उपयोगकर्ता को दिखाने से पहले सर्वर पर चलता है. पेज दिखाए जाने से पहले स्क्रिप्टलेट कोड लागू हो जाता है. इसलिए, यह हर पेज पर सिर्फ़ एक बार चल सकता है. google.script.run के ज़रिए कॉल किए जाने वाले क्लाइंट-साइड JavaScript या Apps Script फ़ंक्शन के उलट, स्क्रिप्टलेट पेज लोड होने के बाद फिर से लागू नहीं हो सकते.

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>

ध्यान दें कि टेंप्लेट वाले एचटीएमएल के लिए doGet() फ़ंक्शन, सामान्य एचटीएमएल बनाने और उसे दिखाने के उदाहरणों से अलग होता है. यहां दिखाया गया फ़ंक्शन, एचटीएमएल फ़ाइल से एक HtmlTemplate ऑब्जेक्ट जनरेट करता है. इसके बाद, स्क्रिप्टलेट को चलाने और टेंप्लेट को HtmlOutput ऑब्जेक्ट में बदलने के लिए, evaluate() तरीके को कॉल करता है. स्क्रिप्टलेट, उपयोगकर्ता को दिखाया जा सकता है.

स्टैंडर्ड स्क्रिप्टलेट

स्टैंडर्ड स्क्रिप्टलेट, सिंटैक्स <? ... ?> का इस्तेमाल करते हैं. ये पेज पर कॉन्टेंट को साफ़ तौर पर आउटपुट किए बिना कोड को लागू करते हैं. हालांकि, इस उदाहरण से पता चलता है कि स्क्रिप्टलेट में मौजूद कोड के नतीजे से, स्क्रिप्टलेट के बाहर मौजूद एचटीएमएल कॉन्टेंट पर अब भी असर पड़ सकता है:

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>

स्क्रिप्टलेट प्रिंट करना

<?= ... ?> सिंटैक्स का इस्तेमाल करने वाले प्रिंटिंग स्क्रिप्टलेट, कॉन्टेक्स्ट के हिसाब से एस्केपिंग का इस्तेमाल करके, अपने कोड के नतीजों को पेज पर दिखाते हैं.

कॉन्टेक्स्ट के हिसाब से एस्केप करने का मतलब है कि Apps Script, पेज पर एचटीएमएल एट्रिब्यूट, क्लाइंट-साइड script टैग या किसी और जगह पर, आउटपुट के कॉन्टेक्स्ट को ट्रैक करता है. साथ ही, क्रॉस-साइट स्क्रिप्टिंग (XSS) हमलों से बचाने के लिए, एस्केप कैरेक्टर को अपने-आप जोड़ता है.

इस उदाहरण में, पहली प्रिंटिंग स्क्रिप्टलेट सीधे स्ट्रिंग को आउटपुट करती है. इसके बाद, एक स्टैंडर्ड स्क्रिप्टलेट आता है, जो ऐरे और लूप को सेट अप करता है. इसके बाद, ऐरे के कॉन्टेंट को आउटपुट करने के लिए, एक और प्रिंटिंग स्क्रिप्टलेट आता है.

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>

ध्यान दें कि प्रिंटिंग स्क्रिप्टलेट सिर्फ़ अपने पहले स्टेटमेंट की वैल्यू दिखाता है. बाकी सभी स्टेटमेंट, स्टैंडर्ड स्क्रिप्टलेट में मौजूद स्टेटमेंट की तरह काम करते हैं. उदाहरण के लिए, स्क्रिप्टलेट <?= 'Hello, world!'; 'abc' ?> सिर्फ़ "हैलो, दुनिया!" प्रिंट करता है

स्क्रिप्टलेट को जबरदस्ती प्रिंट करना

<?!= ... ?> सिंटैक्स का इस्तेमाल करने वाले, फ़ोर्स-प्रिंटिंग स्क्रिप्टलेट, प्रिंटिंग स्क्रिप्टलेट की तरह ही होते हैं. हालांकि, इनमें कॉन्टेक्स्ट के हिसाब से एस्केप करने की सुविधा नहीं होती.

अगर आपकी स्क्रिप्ट में, उपयोगकर्ता के ऐसे इनपुट की अनुमति है जिन पर भरोसा नहीं किया जा सकता, तो संदर्भ के हिसाब से एस्केप करना ज़रूरी है. इसके उलट, अगर आपकी स्क्रिप्टलेट के आउटपुट में जान-बूझकर ऐसा एचटीएमएल या स्क्रिप्ट शामिल की गई है जिसे आपको ठीक उसी तरह डालना है जिस तरह से बताया गया है, तो आपको फ़ोर्स-प्रिंट करना होगा.

आम तौर पर, फ़ोर्स-प्रिंटिंग स्क्रिप्टलेट के बजाय, प्रिंटिंग स्क्रिप्टलेट का इस्तेमाल करें. ऐसा तब तक करें, जब तक आपको एचटीएमएल या JavaScript को बिना किसी बदलाव के प्रिंट करने की ज़रूरत न हो.

स्क्रिप्टलेट में Apps Script कोड

स्क्रिप्टलेट का इस्तेमाल, सामान्य JavaScript को चलाने के लिए ही नहीं किया जाता. अपने टेंप्लेट को Apps Script के डेटा का ऐक्सेस देने के लिए, यहां दी गई तीन में से किसी भी तकनीक का इस्तेमाल किया जा सकता है.

हालांकि, ध्यान रखें कि टेंप्लेट कोड, उपयोगकर्ता को पेज दिखाने से पहले ही लागू हो जाता है. इसलिए, इन तकनीकों से किसी पेज पर सिर्फ़ शुरुआती कॉन्टेंट फ़ीड किया जा सकता है. किसी पेज से इंटरैक्टिव तरीके से Apps Script का डेटा ऐक्सेस करने के लिए, google.script.run एपीआई का इस्तेमाल करें.

टेंप्लेट से Apps Script फ़ंक्शन को कॉल करना

स्क्रिप्टलेट, Apps Script की कोड फ़ाइल या लाइब्रेरी में तय किए गए किसी भी फ़ंक्शन को कॉल कर सकते हैं. इस उदाहरण में, स्प्रेडशीट से डेटा को टेंप्लेट में खींचने और फिर उस डेटा से एचटीएमएल टेबल बनाने का एक तरीका बताया गया है.

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 के एपीआई को सीधे तौर पर कॉल करना

Apps Script कोड का इस्तेमाल, सीधे स्क्रिप्टलेट में भी किया जा सकता है. इस उदाहरण में, डेटा को अलग फ़ंक्शन के बजाय टेंप्लेट में लोड करके, पिछले उदाहरण जैसा ही नतीजा मिलता है.

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>

टेंप्लेट में वैरिएबल डालना

आखिर में, वैरिएबल को HtmlTemplate ऑब्जेक्ट की प्रॉपर्टी के तौर पर असाइन करके, उन्हें टेंप्लेट में डाला जा सकता है. फिर से, इस उदाहरण में वही नतीजा मिलता है जो पिछले उदाहरणों में मिला था.

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>

टेंप्लेट डीबग करना

टेंप्लेट को डीबग करना मुश्किल हो सकता है, क्योंकि आपका लिखा कोड सीधे तौर पर लागू नहीं होता. इसके बजाय, सर्वर आपके टेंप्लेट को कोड में बदलता है और फिर उस कोड को लागू करता है.

अगर यह साफ़ तौर पर नहीं पता चल रहा है कि टेंप्लेट आपकी स्क्रिप्टलेट को कैसे समझ रहा है, तो HtmlTemplate क्लास में मौजूद डीबग करने के दो तरीकों से, आपको यह समझने में मदद मिल सकती है कि क्या हो रहा है.

getCode()

getCode(), एक स्ट्रिंग दिखाता है. इसमें वह कोड होता है जिसे सर्वर, टेंप्लेट से बनाता है. कोड को लॉग करने के बाद, उसे स्क्रिप्ट एडिटर में चिपकाएं. इसके बाद, उसे चलाया जा सकता है और सामान्य Apps Script कोड की तरह डीबग किया जा सकता है.

यहां एक आसान टेंप्लेट दिया गया है, जिसमें Google के प्रॉडक्ट की सूची फिर से दिखती है. इसके बाद, getCode() का नतीजा दिखता है:

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

(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() से मिलता-जुलता है. हालांकि, यह आकलन किए गए कोड को टिप्पणियों के तौर पर दिखाता है, जो ओरिजनल टेंप्लेट के साथ-साथ दिखती हैं.

आकलन किए गए कोड की जानकारी

आपको सबसे पहले, आकलन किए गए कोड के किसी भी सैंपल में, HtmlService.initTemplate() तरीके से बनाया गया output ऑब्जेक्ट दिखेगा. इस तरीके के बारे में कोई दस्तावेज़ नहीं है, क्योंकि सिर्फ़ टेंप्लेट को इसका इस्तेमाल करना होता है. output एक ऐसा HtmlOutput ऑब्जेक्ट है जिसमें दो ऐसी प्रॉपर्टी होती हैं जिनके नाम असामान्य होते हैं. ये प्रॉपर्टी, _ और _$ होती हैं. इन्हें append() और appendUntrusted() के तौर पर भी जाना जाता है.

output में एक और खास प्रॉपर्टी, $out है. यह एक सामान्य HtmlOutput ऑब्जेक्ट को रेफ़र करती है, जिसमें ये खास प्रॉपर्टी नहीं होती हैं. टेंप्लेट, कोड के आखिर में उस सामान्य ऑब्जेक्ट को दिखाता है.

अब आपको यह सिंटैक्स समझ आ गया है, इसलिए बाकी कोड को समझना आसान हो जाएगा. स्क्रिप्टलेट के बाहर मौजूद एचटीएमएल कॉन्टेंट (जैसे, b टैग) को output._ = का इस्तेमाल करके जोड़ा जाता है. इसमें कॉन्टेक्स्टल एस्केपिंग का इस्तेमाल नहीं किया जाता. साथ ही, स्क्रिप्टलेट को JavaScript के तौर पर जोड़ा जाता है. इसमें कॉन्टेक्स्टल एस्केपिंग का इस्तेमाल किया जा सकता है या नहीं, यह स्क्रिप्टलेट के टाइप पर निर्भर करता है.

ध्यान दें कि आकलन किया गया कोड, टेंप्लेट की लाइन नंबर को सुरक्षित रखता है. अगर जांचे गए कोड को चलाने के दौरान आपको कोई गड़बड़ी मिलती है, तो लाइन, टेंप्लेट में मौजूद मिलते-जुलते कॉन्टेंट से जुड़ी होगी.

टिप्पणियों की हैरारकी

आकलन किए गए कोड में लाइन नंबर सेव रहते हैं. इसलिए, स्क्रिप्टलेट में मौजूद टिप्पणियों से, अन्य स्क्रिप्टलेट और एचटीएमएल कोड पर भी टिप्पणी की जा सकती है. इन उदाहरणों से, टिप्पणियों के कुछ चौंकाने वाले असर के बारे में पता चलता है:

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