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

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

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

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 ऑब्जेक्ट जनरेट करता है. इसके बाद, इसके evaluate() तरीके का इस्तेमाल करके स्क्रिप्टलेट लागू करता है और टेंप्लेट को HtmlOutput ऑब्जेक्ट में बदल देता है, ताकि स्क्रिप्ट उपयोगकर्ता को दिखाया जा सके.

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

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

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 API का इस्तेमाल करें.

किसी टेंप्लेट से 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>

लॉग (परफ़ॉर्मेंस की जांच की गई)

(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 ऑब्जेक्ट के बारे में बताती है जिसमें ये खास प्रॉपर्टी नहीं होती हैं. टेंप्लेट, कोड के आखिर में वह सामान्य ऑब्जेक्ट दिखाता है.

अब आपको यह सिंटैक्स समझ आ गया है, इसलिए बाकी कोड को समझना आसान होना चाहिए. स्क्रिप्टलेट के बाहर के एचटीएमएल कॉन्टेंट (जैसे कि 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. */ ?>