আপনি টেমপ্লেট ব্যবহার করে খুব কম পরিশ্রমে গুগল অ্যাপস স্ক্রিপ্ট কোড এবং এইচটিএমএল (HTML) মিলিয়ে ডাইনামিক পেজ তৈরি করতে পারেন। আপনি যদি পিএইচপি (PHP), এএসপি (ASP), বা জেএসপি (JSP)-এর মতো কোড ও এইচটিএমএল মিশ্রিত টেমপ্লেটিং ল্যাঙ্গুয়েজ ব্যবহার করে থাকেন, তবে এর সিনট্যাক্স আপনার কাছে পরিচিত মনে হবে।
স্ক্রিপ্টলেট
অ্যাপস স্ক্রিপ্ট টেমপ্লেটে স্ক্রিপ্টলেট নামক তিনটি বিশেষ ট্যাগ থাকতে পারে। একটি স্ক্রিপ্টলেটের ভিতরে আপনি এমন যেকোনো কোড লিখতে পারেন যা একটি সাধারণ অ্যাপস স্ক্রিপ্ট ফাইলে কাজ করে: স্ক্রিপ্টলেটগুলো অন্য কোড ফাইলে সংজ্ঞায়িত ফাংশন কল করতে পারে, গ্লোবাল ভেরিয়েবল রেফারেন্স করতে পারে, অথবা যেকোনো অ্যাপস স্ক্রিপ্ট এপিআই (API) ব্যবহার করতে পারে। এমনকি আপনি স্ক্রিপ্টলেটের ভিতরে ফাংশন এবং ভেরিয়েবলও সংজ্ঞায়িত করতে পারেন, তবে শর্ত হলো কোড ফাইল বা অন্য টেমপ্লেটে সংজ্ঞায়িত ফাংশন দ্বারা সেগুলোকে কল করা যাবে না।
আপনি যদি নিচের উদাহরণটি স্ক্রিপ্ট এডিটরে পেস্ট করেন, <?= ... ?> ট্যাগের ভেতরের লেখাগুলো (একটি প্রিন্ট স্ক্রিপ্টলেট ) ইটালিক অক্ষরে দেখা যাবে। এই কোডটি ব্যবহারকারীর কাছে পেজটি পরিবেশন করার আগে সার্ভারে চলে। যেহেতু স্ক্রিপ্টলেট কোড পেজ পরিবেশনের আগেই চলে, তাই এটি প্রতি পেজে কেবল একবারই চলতে পারে। ক্লায়েন্ট-সাইড জাভাস্ক্রিপ্ট বা অ্যাপস স্ক্রিপ্ট ফাংশনের মতো নয়, যেগুলোকে আপনি google.script.run এর মাধ্যমে কল করেন, স্ক্রিপ্টলেটগুলো পেজ লোড হওয়ার পর আর চলতে পারে না।
কোড.জিএস
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>
উল্লেখ্য যে, টেমপ্লেটেড HTML-এর জন্য doGet ফাংশনটি সাধারণ HTML তৈরি এবং পরিবেশন করার উদাহরণগুলো থেকে ভিন্ন। এখানে দেখানো ফাংশনটি HTML ফাইল থেকে একটি HtmlTemplate অবজেক্ট তৈরি করে, তারপর এর evaluate মেথডকে কল করে স্ক্রিপ্টলেটগুলো এক্সিকিউট করে এবং টেমপ্লেটটিকে একটি HtmlOutput অবজেক্টে রূপান্তর করে, যা স্ক্রিপ্টটি ব্যবহারকারীকে পরিবেশন করতে পারে।
প্রমিত লিপি
স্ট্যান্ডার্ড স্ক্রিপলেট, যা <? ... ?> সিনট্যাক্স ব্যবহার করে, পেজে সরাসরি কোনো কন্টেন্ট আউটপুট না করেই কোড এক্সিকিউট করে। তবে, এই উদাহরণটি যেমন দেখায়, একটি স্ক্রিপলেটের ভেতরের কোডের ফলাফল স্ক্রিপলেটের বাইরের HTML কন্টেন্টকেও প্রভাবিত করতে পারে:
কোড.জিএস
function doGet() {
return HtmlService
.createTemplateFromFile('Index')
.evaluate();
}
Index.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>
স্ক্রিপ্টলেট প্রিন্ট করুন
প্রিন্টিং স্ক্রিপলেট, যা <?= ... ?> সিনট্যাক্স ব্যবহার করে, কনটেক্সচুয়াল এস্কেপিং ব্যবহার করে তাদের কোডের ফলাফল পেজে আউটপুট করে।
কনটেক্সচুয়াল এস্কেপিং মানে হলো, অ্যাপস স্ক্রিপ্ট পেজের মধ্যে আউটপুটের কনটেক্সট—যেমন HTML অ্যাট্রিবিউটের ভেতরে, ক্লায়েন্ট-সাইড script ট্যাগের ভেতরে বা অন্য যেকোনো জায়গায়—এর হিসাব রাখে এবং ক্রস-সাইট স্ক্রিপ্টিং (XSS) আক্রমণ থেকে রক্ষা করার জন্য স্বয়ংক্রিয়ভাবে এস্কেপ ক্যারেক্টার যোগ করে।
এই উদাহরণে, প্রথম প্রিন্টিং স্ক্রিপ্টলেটটি সরাসরি একটি স্ট্রিং আউটপুট করে; এর পরে একটি স্ট্যান্ডার্ড স্ক্রিপ্টলেট রয়েছে যা একটি অ্যারে এবং একটি লুপ তৈরি করে, এবং তারপরে অ্যারের বিষয়বস্তু আউটপুট করার জন্য আরেকটি প্রিন্টিং স্ক্রিপ্টলেট রয়েছে।
কোড.জিএস
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!" প্রিন্ট করে।
জোরপূর্বক মুদ্রণ স্ক্রিপ্টলেট
ফোর্স-প্রিন্ট স্ক্রিপলেট, যা <?!= ... ?> সিনট্যাক্স ব্যবহার করে, স্ক্রিপলেট প্রিন্ট করার মতোই, তবে এক্ষেত্রে কনটেক্সচুয়াল এস্কেপিং পরিহার করা হয়।
আপনার স্ক্রিপ্ট যদি অবিশ্বস্ত ব্যবহারকারীর ইনপুট গ্রহণ করে, তবে কনটেক্সচুয়াল এস্কেপিং গুরুত্বপূর্ণ। এর বিপরীতে, আপনার স্ক্রিপ্টলেটের আউটপুটে যদি ইচ্ছাকৃতভাবে এমন HTML বা স্ক্রিপ্ট থাকে যা আপনি নির্দিষ্ট নির্দেশনা অনুযায়ী হুবহু সন্নিবেশ করতে চান, তবে আপনাকে ফোর্স-প্রিন্ট করতে হবে।
সাধারণত, ফোর্স-প্রিন্টিং স্ক্রিপলেটের পরিবর্তে প্রিন্টিং স্ক্রিপলেট ব্যবহার করুন, যদি না আপনি নিশ্চিত হন যে আপনাকে HTML বা জাভাস্ক্রিপ্ট অপরিবর্তিতভাবে প্রিন্ট করতে হবে।
অ্যাপস স্ক্রিপ্ট কোড স্ক্রিপ্টলেটে
স্ক্রিপ্টলেট শুধু সাধারণ জাভাস্ক্রিপ্ট চালানোর মধ্যেই সীমাবদ্ধ নয়; আপনার টেমপ্লেটগুলোকে অ্যাপস স্ক্রিপ্ট ডেটা অ্যাক্সেস দেওয়ার জন্য আপনি নিম্নলিখিত তিনটি পদ্ধতির যেকোনো একটিও ব্যবহার করতে পারেন।
তবে মনে রাখবেন, যেহেতু ব্যবহারকারীর কাছে পৃষ্ঠাটি পরিবেশন করার আগেই টেমপ্লেট কোড কার্যকর হয়, তাই এই পদ্ধতিগুলো কেবল একটি পৃষ্ঠায় প্রাথমিক বিষয়বস্তু সরবরাহ করতে পারে। কোনো পৃষ্ঠা থেকে ইন্টারেক্টিভভাবে অ্যাপস স্ক্রিপ্ট ডেটা অ্যাক্সেস করতে, এর পরিবর্তে google.script.run API ব্যবহার করুন।
একটি টেমপ্লেট থেকে অ্যাপস স্ক্রিপ্ট ফাংশন কল করুন
স্ক্রিপ্টলেটগুলো অ্যাপস স্ক্রিপ্ট কোড ফাইল বা লাইব্রেরিতে সংজ্ঞায়িত যেকোনো ফাংশনকে কল করতে পারে। এই উদাহরণটি একটি স্প্রেডশিট থেকে টেমপ্লেটে ডেটা নিয়ে আসার এবং তারপর সেই ডেটা থেকে একটি HTML টেবিল তৈরি করার একটি উপায় দেখায়।
কোড.জিএস
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>
সরাসরি অ্যাপস স্ক্রিপ্ট এপিআই কল করুন
আপনি সরাসরি স্ক্রিপ্টলেটেও অ্যাপস স্ক্রিপ্ট কোড ব্যবহার করতে পারেন। এই উদাহরণটি একটি পৃথক ফাংশনের মাধ্যমে ডেটা লোড না করে, বরং টেমপ্লেটের মধ্যেই ডেটা লোড করার মাধ্যমে পূর্ববর্তী উদাহরণের মতোই একই ফলাফল অর্জন করে।
কোড.জিএস
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 অবজেক্টের প্রপার্টি হিসেবে ভেরিয়েবল অ্যাসাইন করার মাধ্যমে সেগুলোকে একটি টেমপ্লেটে যুক্ত করতে পারেন। আবারও, এই উদাহরণটি পূর্ববর্তী উদাহরণগুলোর মতোই একই ফলাফল প্রদান করে।
কোড.জিএস
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 ফাংশনটি একটি স্ট্রিং রিটার্ন করে, যাতে সার্ভার কর্তৃক টেমপ্লেট থেকে তৈরি করা কোডটি থাকে। আপনি যদি কোডটি লগ করে স্ক্রিপ্ট এডিটরে পেস্ট করেন, তবে সাধারণ অ্যাপস স্ক্রিপ্ট কোডের মতোই এটি রান ও ডিবাগ করতে পারবেন।
এই হলো সেই টেমপ্লেট যা আবার গুগল প্রোডাক্টের একটি তালিকা প্রদর্শন করে, এবং এর পরে getCode এর ফলাফল দেখানো হয়:
কোড.জিএস
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() এর অনুরূপ, তবে এটি মূল্যায়ন করা কোডকে মন্তব্য হিসাবে ফেরত দেয় যা মূল টেমপ্লেটের পাশাপাশি প্রদর্শিত হয়।
মূল্যায়ন করা কোডটি ধাপে ধাপে পর্যালোচনা করুন
মূল্যায়ন করা কোডের যেকোনো নমুনায় আপনি প্রথমেই যেটি লক্ষ্য করবেন তা হলো HtmlService.initTemplate মেথড দ্বারা তৈরি অন্তর্নিহিত output অবজেক্টটি। এই মেথডটি নথিভুক্ত নয়, কারণ শুধুমাত্র টেমপ্লেটগুলোর নিজেদেরই এটি ব্যবহার করার প্রয়োজন হয়। output হলো একটি বিশেষ HtmlOutput অবজেক্ট, যার _ এবং _$ নামে দুটি অস্বাভাবিক নামের প্রপার্টি রয়েছে, যা যথাক্রমে append এবং appendUntrusted কল করার সংক্ষিপ্ত রূপ।
output আরও একটি বিশেষ প্রপার্টি আছে, $out , যা একটি সাধারণ HtmlOutput অবজেক্টকে নির্দেশ করে, যেটিতে এই বিশেষ প্রপার্টিগুলো থাকে না। টেমপ্লেটটি কোডের শেষে সেই সাধারণ অবজেক্টটি রিটার্ন করে।
এখন যেহেতু আপনি এই সিনট্যাক্সটি বুঝতে পেরেছেন, আপনি কোডের বাকি অংশ অনুসরণ করতে পারবেন। স্ক্রিপ্টলেটের বাইরের HTML কন্টেন্ট (যেমন 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 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. */ ?>