HTML পরিষেবা: টেমপ্লেটেড HTML

আপনি ন্যূনতম প্রচেষ্টায় গতিশীল পৃষ্ঠাগুলি তৈরি করতে Apps স্ক্রিপ্ট কোড এবং HTML মিশ্রিত করতে পারেন। আপনি যদি একটি টেমপ্লেটিং ভাষা ব্যবহার করেন যা কোড এবং এইচটিএমএল মিশ্রিত করে, যেমন পিএইচপি, এএসপি, বা জেএসপি, সিনট্যাক্সটি পরিচিত বোধ করা উচিত।

লিপি

অ্যাপস স্ক্রিপ্ট টেমপ্লেটগুলিতে তিনটি বিশেষ ট্যাগ থাকতে পারে, যাকে স্ক্রিপ্টলেট বলা হয়। একটি স্ক্রিপ্টলেটের ভিতরে, আপনি যেকোন কোড লিখতে পারেন যা একটি সাধারণ অ্যাপস স্ক্রিপ্ট ফাইলে কাজ করবে: স্ক্রিপ্টলেটগুলি অন্যান্য কোড ফাইলে সংজ্ঞায়িত ফাংশনগুলিকে কল করতে পারে, গ্লোবাল ভেরিয়েবলগুলি উল্লেখ করতে পারে বা যেকোনও অ্যাপ স্ক্রিপ্ট API ব্যবহার করতে পারে৷ এমনকি আপনি স্ক্রিপ্টলেটগুলির মধ্যে ফাংশন এবং ভেরিয়েবলগুলিকে সংজ্ঞায়িত করতে পারেন, সতর্কতার সাথে যে সেগুলিকে কোড ফাইল বা অন্যান্য টেমপ্লেটে সংজ্ঞায়িত ফাংশন দ্বারা বলা যাবে না।

আপনি যদি স্ক্রিপ্ট সম্পাদকে নীচের উদাহরণটি পেস্ট করেন, তাহলে <?= ... ?> ট্যাগের বিষয়বস্তু (একটি মুদ্রণ স্ক্রিপ্টলেট ) তির্যক আকারে প্রদর্শিত হবে। পৃষ্ঠাটি ব্যবহারকারীকে পরিবেশন করার আগে সেই তির্যক কোডটি সার্ভারে চলে। যেহেতু স্ক্রিপ্টলেট কোড পৃষ্ঠাটি পরিবেশন করার আগে কার্যকর হয়, এটি প্রতি পৃষ্ঠায় একবার চালানো যেতে পারে; ক্লায়েন্ট-সাইড জাভাস্ক্রিপ্ট বা অ্যাপস স্ক্রিপ্ট ফাংশনগুলির বিপরীতে যা আপনি google.script.run মাধ্যমে কল করেন, পৃষ্ঠা লোড হওয়ার পরে স্ক্রিপ্টলেটগুলি আবার কার্যকর করতে পারে না।

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>

মনে রাখবেন যে টেমপ্লেটেড HTML-এর জন্য doGet() ফাংশন মৌলিক HTML তৈরি এবং পরিবেশন করার উদাহরণ থেকে আলাদা। এখানে দেখানো ফাংশনটি HTML ফাইল থেকে একটি HtmlTemplate অবজেক্ট তৈরি করে, তারপর স্ক্রিপ্টলেটগুলি চালানোর জন্য এটির evaluate() পদ্ধতিকে কল করে এবং টেমপ্লেটটিকে একটি HtmlOutput অবজেক্টে রূপান্তর করে যা স্ক্রিপ্ট ব্যবহারকারীকে পরিবেশন করতে পারে।

স্ট্যান্ডার্ড স্ক্রিপ্টলেট

স্ট্যান্ডার্ড স্ক্রিপ্টলেট, যা সিনট্যাক্স ব্যবহার করে <? ... ?> , পৃষ্ঠায় বিষয়বস্তু স্পষ্টভাবে আউটপুট না করেই কোড চালান। যাইহোক, যেমন এই উদাহরণটি দেখায়, একটি স্ক্রিপ্টলেটের ভিতরে কোডের ফলাফল এখনও স্ক্রিপ্টলেটের বাইরে HTML সামগ্রীকে প্রভাবিত করতে পারে:

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>

স্ক্রিপ্টলেট মুদ্রণ

প্রিন্টিং স্ক্রিপ্টলেট, যা সিনট্যাক্স ব্যবহার করে <?= ... ?> , প্রাসঙ্গিক এস্কেপিং ব্যবহার করে তাদের কোডের ফলাফল পৃষ্ঠায় আউটপুট করে।

প্রাসঙ্গিক এস্কেপিং এর অর্থ হল অ্যাপস স্ক্রিপ্ট পৃষ্ঠায় আউটপুটের প্রসঙ্গ ট্র্যাক করে — একটি HTML অ্যাট্রিবিউটের ভিতরে, ক্লায়েন্ট-সাইড 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' ?> শুধুমাত্র প্রিন্ট করে "হ্যালো, ওয়ার্ল্ড!"

ফোর্স-প্রিন্টিং স্ক্রিপ্টলেট

ফোর্স-প্রিন্টিং স্ক্রিপ্টলেট, যেগুলি সিনট্যাক্স ব্যবহার করে <?!= ... ?> , সেগুলি প্রিন্টিং স্ক্রিপ্টলেটের মতো, তবে তারা প্রাসঙ্গিক এস্কেপিং এড়ায়।

আপনার স্ক্রিপ্ট অবিশ্বস্ত ব্যবহারকারী ইনপুট অনুমতি দেয় যদি প্রাসঙ্গিক পালানো গুরুত্বপূর্ণ. বিপরীতে, যদি আপনার স্ক্রিপ্টলেটের আউটপুটে ইচ্ছাকৃতভাবে এইচটিএমএল বা স্ক্রিপ্ট থাকে যা আপনি ঠিক যেমন উল্লেখ করতে চান সন্নিবেশ করতে চান তাহলে আপনাকে জোর করে-মুদ্রণ করতে হবে।

একটি সাধারণ নিয়ম হিসাবে, ফোর্স-প্রিন্টিং স্ক্রিপ্টলেটের পরিবর্তে মুদ্রণ স্ক্রিপ্টলেট ব্যবহার করুন যদি না আপনি জানেন যে আপনাকে HTML বা JavaScript অপরিবর্তিত মুদ্রণ করতে হবে।

স্ক্রিপ্টলেটে অ্যাপস স্ক্রিপ্ট কোড

স্ক্রিপ্টলেটগুলি সাধারণ জাভাস্ক্রিপ্ট চালানোর জন্য সীমাবদ্ধ নয়; আপনি আপনার টেমপ্লেটগুলিকে Apps স্ক্রিপ্ট ডেটাতে অ্যাক্সেস দেওয়ার জন্য নিম্নলিখিত তিনটি কৌশলগুলির যে কোনও একটি ব্যবহার করতে পারেন৷

মনে রাখবেন, তবে, যেহেতু টেমপ্লেট কোড ব্যবহারকারীকে পৃষ্ঠাটি পরিবেশন করার আগে কার্যকর করা হয়, এই কৌশলগুলি শুধুমাত্র একটি পৃষ্ঠায় প্রাথমিক বিষয়বস্তু প্রদান করতে পারে। ইন্টারেক্টিভভাবে একটি পৃষ্ঠা থেকে Apps স্ক্রিপ্ট ডেটা অ্যাক্সেস করতে, পরিবর্তে google.script.run API ব্যবহার করুন।

একটি টেমপ্লেট থেকে Apps স্ক্রিপ্ট ফাংশন কল করা

স্ক্রিপ্টলেট একটি Apps স্ক্রিপ্ট কোড ফাইল বা লাইব্রেরিতে সংজ্ঞায়িত যেকোনো ফাংশন কল করতে পারে। এই উদাহরণটি একটি স্প্রেডশীট থেকে একটি টেমপ্লেটে ডেটা টেনে আনার একটি উপায় দেখায়, তারপর ডেটা থেকে একটি HTML টেবিল তৈরি করুন৷

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 কল করা হচ্ছে

এছাড়াও আপনি সরাসরি স্ক্রিপ্টলেটে Apps স্ক্রিপ্ট কোড ব্যবহার করতে পারেন। এই উদাহরণটি একটি পৃথক ফাংশনের পরিবর্তে টেমপ্লেটে ডেটা লোড করার মাধ্যমে পূর্ববর্তী উদাহরণের মতো একই ফলাফল অর্জন করে।

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() টেমপ্লেট থেকে সার্ভার তৈরি করা কোড সম্বলিত একটি স্ট্রিং প্রদান করে। আপনি যদি কোডটি লগ করেন , তাহলে এটি স্ক্রিপ্ট এডিটরে পেস্ট করুন, আপনি এটি চালাতে পারেন এবং সাধারণ অ্যাপস স্ক্রিপ্ট কোডের মতো ডিবাগ করতে পারেন

এখানে একটি সাধারণ টেমপ্লেট রয়েছে যা আবার 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() এর অনুরূপ, কিন্তু মূল টেমপ্লেটের সাথে পাশাপাশি প্রদর্শিত মন্তব্য হিসাবে মূল্যায়ন করা কোড প্রদান করে।

মূল্যায়ন কোড মাধ্যমে হাঁটা

মূল্যায়ন করা কোডের উভয় নমুনায় আপনি প্রথম যে জিনিসটি লক্ষ্য করবেন তা হল HtmlService.initTemplate() পদ্ধতি দ্বারা তৈরি অন্তর্নিহিত output বস্তু। এই পদ্ধতিটি নথিভুক্ত নয় কারণ শুধুমাত্র টেমপ্লেটদেরই এটি ব্যবহার করতে হবে। output হল একটি বিশেষ HtmlOutput অবজেক্ট যার দুটি অস্বাভাবিকভাবে নামকরণ করা বৈশিষ্ট্য, _ এবং _$ , যা append() এবং appendUntrusted() কল করার জন্য শর্টহ্যান্ড।

output আরও একটি বিশেষ বৈশিষ্ট্য রয়েছে, $out , যা একটি নিয়মিত HtmlOutput অবজেক্টকে বোঝায় যা এই বিশেষ বৈশিষ্ট্যগুলির অধিকারী নয়। টেমপ্লেট কোডের শেষে সেই স্বাভাবিক বস্তুটি ফেরত দেয়।

এখন আপনি এই সিনট্যাক্স বুঝতে পেরেছেন, বাকি কোড অনুসরণ করা মোটামুটি সহজ হওয়া উচিত। স্ক্রিপ্টলেটের বাইরের এইচটিএমএল কন্টেন্ট ( b ট্যাগের মতো) output._ = ( প্রসঙ্গিক এস্কেপিং ছাড়াই), এবং স্ক্রিপ্টলেটগুলি জাভাস্ক্রিপ্ট হিসাবে যুক্ত করা হয় (স্ক্রিপ্টলেটের ধরনের উপর নির্ভর করে প্রাসঙ্গিক এস্কেপিং সহ বা ছাড়া)।

নোট করুন যে মূল্যায়ন করা কোডটি টেমপ্লেট থেকে লাইন নম্বর সংরক্ষণ করে। আপনি যদি মূল্যায়ন করা কোড চালানোর সময় একটি ত্রুটি পান, লাইনটি টেমপ্লেটের সমতুল্য বিষয়বস্তুর সাথে সঙ্গতিপূর্ণ হবে।

মন্তব্যের অনুক্রম

কারণ মূল্যায়ন করা কোড লাইন নম্বর সংরক্ষণ করে, স্ক্রিপ্টলেটের ভিতরে থাকা মন্তব্যের পক্ষে অন্যান্য স্ক্রিপ্টলেট এবং এমনকি 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. */ ?>