خدمة HTML: نموذج HTML

يمكنك المزج بين رمز "برمجة تطبيقات Google" وHTML لإنتاج صفحات ديناميكية بأقلّ والجهد. إذا كنت قد استخدمت لغة نماذج تمزج بين التعليمات البرمجية وHTML، مثل يجب أن تبدو بنية اللغة PHP أو ASP أو JSP مألوفة.

النصوص البرمجية

يمكن أن تحتوي نماذج "برمجة تطبيقات Google" على ثلاث علامات خاصة تُعرف باسم "النصوص البرمجية". داخل المنشأة نص برمجي، يمكنك كتابة أي رمز يعمل في نص برمجي عادي الملف: يمكن للنصوص البرمجية استدعاء الدوال المحددة في ملفات التعليمات البرمجية الأخرى أو الملفات المرجعية أو استخدام أي من واجهات برمجة التطبيقات لبرمجة التطبيقات. يمكنك حتى تحديد الدوال والمتغيرات داخل النصوص البرمجية، مع الانتباه إلى أنه لا يمكن عن طريق الدوال المحددة في ملفات التعليمات البرمجية أو النماذج الأخرى.

في حال لصق المثال أدناه في أداة تعديل النصوص البرمجية، سيتضمّن الحقل ستظهر علامة <?= ... ?> (نص برمجي قابل للطباعة) في المائل. يعمل هذا الرمز المائل على الخادم قبل عرض الصفحة. للمستخدم. نظرًا لتنفيذ رمز scriptlet قبل عرض الصفحة، فإنه يمكن تشغيلها مرة واحدة فقط لكل صفحة بخلاف JavaScript من جهة العميل أو برمجة التطبيقات الدوال التي تستدعيها 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>

لاحظ أن الدالة doGet() لقالب HTML النموذجي تختلف عن الأمثلة لإنشاء محتوى HTML الأساسي وعرضه. الدالة الموضح هنا ينشئ الكائن HtmlTemplate من HTML ملف، ثم يستدعي 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).

في هذا المثال، يُخرج النص البرمجي للطباعة الأول سلسلة مباشرةً؛ CANNOT TRANSLATE متبوعًا بنص برمجي قياسي يقوم بإعداد صفيف وتكرار حلقي، متبوعًا نص برمجي لطباعة آخر لإخراج محتويات الصفيفة.

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' ?> إلا تطبع "Hello, world!"

فرض طباعة النصوص البرمجية

إن فرض طباعة النصوص البرمجية، التي تستخدم البنية <?!= ... ?>، تشبه الطباعة إلا أنها تتجنب الهروب السياقي.

يُعد إلغاء السياق مهمًا إذا كان النص البرمجي يسمح بإدخال مستخدم غير موثوق به. من ستحتاج إلى فرض الطباعة إذا كان مخرج النص البرمجي الخاص بك قصدًا يحتوي على HTML أو نصوص برمجية تريد إدراجها كما هو محدد بالضبط.

كقاعدة عامة، استخدام طباعة النصوص البرمجية بدلاً من فرض طباعة النصوص البرمجية ما لم تكن تعرف أنك بحاجة إلى طباعة HTML أو JavaScript بدون أي تغيير.

رمز "برمجة تطبيقات Google" في النصوص البرمجية

لا تقتصر النصوص البرمجية على تشغيل JavaScript عادي؛ يمكنك أيضًا استخدام أي من الأساليب الثلاثة التالية لمنح النماذج إذن الوصول إلى "برمجة تطبيقات Google" البيانات.

مع ذلك، تذكَّر أنّه يتم تنفيذ رمز النموذج قبل عرض الصفحة. للمستخدم، يمكن لهذه الأساليب تقديم المحتوى الأولي فقط إلى الصفحة. للوصول إلى: يمكنك استخدام بيانات "برمجة تطبيقات Google" من إحدى الصفحات بشكل تفاعلي google.script.run API بدلاً من ذلك.

استدعاء دوال "برمجة تطبيقات Google" من نموذج

يمكن للنصوص البرمجية استدعاء أي دالة محددة في ملف رمز برمجي لبرمجة تطبيقات Google أو مكتبة. يوضح هذا المثال طريقة واحدة لسحب البيانات من جدول بيانات إلى قالب، ثم إنشاء جدول 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>

الاتصال بواجهات برمجة تطبيقات "برمجة تطبيقات Google" مباشرةً

يمكنك أيضًا استخدام رمز "برمجة تطبيقات Google" مباشرةً في النصوص البرمجية. هذا المثال نفس النتيجة التي تم تحقيقها في المثال السابق بتحميل البيانات في القالب نفسه بدلاً من استخدام دالة منفصلة.

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".

إليك النموذج البسيط الذي يعرض قائمة بمنتجات 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 (تم التقييم)

(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._ = (بدون هروب سياقي)، ويتم إلحاق النصوص البرمجية بلغة JavaScript (مع أو بدون هروب سياقي، اعتمادًا على نوع النص البرمجي).

يُرجى العلم أنّ الرمز البرمجي المقيّم يحتفظ بأرقام الأسطر من النموذج. إذا كنت تحصل على خطأ أثناء تشغيل التعليمة البرمجية المقيّمة، فسيتجاوب السطر مع محتوى مماثل في القالب.

التسلسل الهرمي للتعليقات

نظرًا لأن التعليمة البرمجية المقيّمة تحتفظ بأرقام الأسطر، فمن الممكن أن تكون التعليقات داخل النصوص البرمجية للتعليق على النصوص البرمجية الأخرى وحتى رموز 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. */ ?>