النصوص البرمجية للمحتوى

نصوص المحتوى البرمجية هي ملفات يتم تشغيلها في سياق صفحات الويب. باستخدام نموذج كائن المستند (DOM) العادي، يمكنها قراءة تفاصيل صفحات الويب التي يتصفّحها المتصفّح وإجراء تغييرات عليها ونقل المعلومات إلى الإضافة الرئيسية.

التعرّف على إمكانات النصوص البرمجية للمحتوى

يمكن لبرامج النصوص الخاصة بالمحتوى الوصول إلى واجهات برمجة تطبيقات Chrome التي تستخدمها الإضافة الرئيسية من خلال تبادل الرسائل مع الإضافة. يمكنهم أيضًا الوصول إلى عنوان URL لملف إضافة باستخدام chrome.runtime.getURL() واستخدام النتيجة بالطريقة نفسها التي يتم بها استخدام عناوين URL الأخرى.

// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;

بالإضافة إلى ذلك، يمكن لبرنامج نصي للمحتوى الوصول إلى واجهات برمجة التطبيقات التالية في Chrome مباشرةً:

لا يمكن للنصوص البرمجية للمحتوى الوصول إلى واجهات برمجة التطبيقات الأخرى مباشرةً.

العمل في عوالم معزولة

تعمل النصوص البرمجية للمحتوى في بيئة معزولة، ما يسمح لها بإجراء تغييرات على بيئة JavaScript بدون حدوث تعارض مع الصفحة أو النصوص البرمجية الإضافية للمحتوى.

قد يتم تشغيل إضافة في صفحة ويب باستخدام رمز مشابه للمثال أدناه.

<html>
  <button id="mybutton">click me</button>
  <script>
    var greeting = "hello, ";
    var button = document.getElementById("mybutton");
    button.person_name = "Bob";
    button.addEventListener("click", function() {
      alert(greeting + button.person_name + ".");
    }, false);
  </script>
</html>

يمكن أن تُدخل هذه الإضافة نصًا برمجيًا للمحتوى على النحو التالي.

var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener("click", function() {
  alert(greeting + button.person_name + ".");
}, false);

سيظهر كلا التنبيهَين في حال الضغط على الزر.

لا تسمح العوالم المعزولة للنصوص البرمجية للمحتوى والإضافة وصفحة الويب بالوصول إلى أي متغيرات أو دوال أنشأها الآخرون. يمنح ذلك أيضًا النصوص البرمجية للمحتوى القدرة على تفعيل وظائف لا يفترض أن تكون متاحة لصفحة الويب.

إدراج نصوص برمجية

يمكن إدخال "برامج النصوص الخاصة بالمحتوى" برمجيًا أو تصريحيًا.

إدخالها آليًا

استخدِم عملية الإدخال الآلي لبرامج النصوص الخاصة بالمحتوى التي يجب تنفيذها في مناسبات معيّنة.

لإدخال نص برمجي خاص بالمحتوى، يجب توفير إذن activeTab في ملف البيان. يمنح هذا الإذن وصولاً آمنًا إلى مضيف الموقع الإلكتروني النشط ووصولاً مؤقتًا إلى إذن علامات التبويب، ما يتيح تشغيل النص البرمجي للمحتوى على علامة التبويب النشطة الحالية بدون تحديد أذونات الوصول إلى مصادر متعددة.

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab"
  ],
  ...
}

يمكن إدخال نصوص برمجية للمحتوى كرمز.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "changeColor"){
      chrome.tabs.executeScript({
        code: 'document.body.style.backgroundColor="orange"'
      });
    }
  });

أو يمكن إدخال ملف كامل.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "runContentScript"){
      chrome.tabs.executeScript({
        file: 'contentScript.js'
      });
    }
  });

إضافة البيانات بشكل تعريفي

استخدِم طريقة العرض التوضيحي لإدخال النصوص البرمجية للمحتوى التي يجب تنفيذها تلقائيًا على صفحات محدّدة.

يتم تسجيل النصوص البرمجية التي يتم إدخالها بشكل تصريحي في البيان ضمن الحقل "content_scripts". ويمكن أن تتضمّن ملفات JavaScript أو ملفات CSS أو كليهما. يجب أن تحدّد جميع نصوص البرامج التي يتم تشغيلها تلقائيًا أنماط المطابقة.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
الاسم النوع الوصف
matches {: #matches } مصفوفة سلاسل مطلوبة تحدّد هذه السمة الصفحات التي سيتم إدراج نص برمجي المحتوى فيها. اطّلِع على أنماط المطابقة لمزيد من التفاصيل حول بنية هذه السلاسل وأنماط المطابقة والأنماط العامة للحصول على معلومات حول كيفية استبعاد عناوين URL.
css {: #css } مصفوفة سلاسل اختياري. قائمة بملفات CSS التي سيتم إدراجها في الصفحات المطابقة يتم إدخالها بالترتيب الذي تظهر به في هذه المصفوفة، قبل إنشاء أي DOM أو عرضه للصفحة.
js {: #js } مصفوفة سلاسل اختياري. قائمة ملفات JavaScript التي سيتم إدراجها في الصفحات المطابقة يتم إدخالها بالترتيب الذي تظهر به في هذه المصفوفة.
match_about_blank {: #match_about_blank } قيمة منطقية اختياري. تحديد ما إذا كان يجب إدخال النص البرمجي في إطار about:blank حيث يتطابق الإطار الرئيسي أو إطار الفتح مع أحد الأنماط المحدّدة في matches القيمة التلقائية هي false.

استبعاد المطابقات والأنماط العامة

يمكن تخصيص عملية مطابقة الصفحات المحدّدة من خلال تضمين الحقول التالية في بيان التسجيل.

الاسم النوع الوصف
exclude_matches {: #exclude_matches } مصفوفة سلاسل اختياري. يستبعد الصفحات التي كان سيتم إدراج نص برمجي للمحتوى فيها. اطّلِع على أنماط المطابقة لمزيد من التفاصيل حول بنية هذه السلاسل.
include_globs {: #include_globs } مصفوفة سلاسل اختياري. يتم تطبيقه بعد matches لتضمين عناوين URL التي تتطابق أيضًا مع هذا النمط العام. تهدف هذه السمة إلى محاكاة الكلمة الرئيسية @include في Greasemonkey.
exclude_globs {: #exclude_globs } مصفوفة من السلاسل اختياري. يتم تطبيقه بعد matches لاستبعاد عناوين URL التي تتطابق مع هذا النمط العام. تهدف هذه السمة إلى محاكاة @excludeالكلمة الرئيسية في Greasemonkey.

سيتم إدخال نص برمجي للمحتوى في صفحة إذا كان عنوان URL الخاص بها يطابق أي نمط matches وأي نمط include_globs، ما دام عنوان URL لا يطابق أيضًا نمط exclude_matches أو نمط exclude_globs.

بما أنّ السمة matches مطلوبة، لا يمكن استخدام exclude_matches وinclude_globs وexclude_globs إلا للحدّ من الصفحات التي ستتأثر.

ستُدخل الإضافة التالية نص المحتوى البرمجي في http://www.nytimes.com/ health ولكن ليس في http://www.nytimes.com/ business .

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

تتّبع خصائص Glob بنية مختلفة وأكثر مرونةً من أنماط المطابقة. سلاسل glob المقبولة هي عناوين URL قد تحتوي على علامات نجمية وعلامات استفهام "أحرف بدل". تتطابق علامة النجمة * مع أي سلسلة بأي طول، بما في ذلك السلسلة الفارغة، بينما تتطابق علامة الاستفهام ? تتطابق مع أي حرف مفرد.

على سبيل المثال، يتطابق النمط العام http:// ??? .example.com/foo/ * مع أي مما يلي:

  • http:// www .example.com/foo /bar
  • http:// the .example.com/foo /‎

ومع ذلك، لا يتطابق مع ما يلي:

  • http:// my .example.com/foo/bar
  • http:// example .com/foo/
  • http://www.example.com/foo

سيُدرج هذا الامتداد النص البرمجي للمحتوى في http:/www.nytimes.com/ arts /index.html وhttp://www.nytimes.com/ jobs /index.html، ولكن ليس في http://www.nytimes.com/ sports /index.html.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

ستُدرج هذه الإضافة النص البرمجي للمحتوى في http:// history .nytimes.com وhttp://.nytimes.com/ history، ولكن ليس في http:// science .nytimes.com أو http://www.nytimes.com/ science .

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

يمكن تضمين بعض هذه العناصر أو كلها أو أحدها لتحقيق النطاق الصحيح.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

وقت التنفيذ

يتم التحكّم في وقت إدخال ملفات JavaScript في صفحة الويب من خلال الحقل run_at. الحقل المفضّل والتلقائي هو "document_idle"، ولكن يمكن أيضًا تحديده على أنّه "document_start" أو "document_end" عند الحاجة.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}
الاسم النوع الوصف
document_idle {: #document_idle } سلسلة الخيار المفضّل: استخدِم "document_idle" متى أمكن ذلك.

يختار المتصفّح وقتًا لإدراج النصوص البرمجية بين "document_end" وبعد تنشيط الحدث windowonload مباشرةً. يعتمد وقت الإضافة الدقيق على مدى تعقيد المستند والوقت الذي يستغرقه تحميله، ويتم تحسينه لسرعة تحميل الصفحة.

لا تحتاج البرامج النصية للمحتوى التي يتم تشغيلها في "document_idle" إلى انتظار حدث window.onload، ويُضمن تشغيلها بعد اكتمال DOM. إذا كان النص البرمجي يحتاج بالتأكيد إلى التنفيذ بعد window.onload، يمكن للإضافة التحقّق مما إذا كان onload قد تم تنفيذه من قبل باستخدام السمة document.readyState.
document_start {: #document_start } سلسلة يتم إدخال النصوص البرمجية بعد أي ملفات من css، ولكن قبل إنشاء أي DOM آخر أو تشغيل أي نص برمجي آخر.
document_end {: #document_end } سلسلة يتم إدخال النصوص البرمجية مباشرةً بعد اكتمال DOM، ولكن قبل تحميل الموارد الفرعية، مثل الصور والإطارات.

تحديد اللقطات

يتيح الحقل "all_frames" للإضافة تحديد ما إذا كان يجب إدراج ملفات JavaScript وCSS في جميع الإطارات التي تتطابق مع متطلبات عنوان URL المحدّد أو في الإطار العلوي فقط في علامة تبويب.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
الاسم النوع الوصف
all_frames {: #all_frames } قيمة منطقية اختياري. القيمة التلقائية هي false، ما يعني أنّه يتم مطابقة الإطار العلوي فقط.

إذا تم تحديد القيمة true، سيتم إدخالها في جميع الإطارات، حتى إذا لم يكن الإطار هو الإطار العلوي في علامة التبويب. يتم التحقّق من كل إطار بشكل مستقل بحثًا عن متطلبات عنوان URL، ولن يتم إدراجه في الإطارات الفرعية إذا لم يتم استيفاء متطلبات عنوان URL.

التواصل مع الصفحة المضمّنة

على الرغم من أنّ بيئات التنفيذ الخاصة بنصوص المحتوى البرمجية والصفحات التي تستضيفها معزولة عن بعضها، إلا أنّها تشترك في إمكانية الوصول إلى نموذج المستند الخاص بالصفحة. إذا أرادت الصفحة التواصل مع النص البرمجي الخاص بالمحتوى أو مع الإضافة من خلال النص البرمجي الخاص بالمحتوى، عليها إجراء ذلك من خلال نموذج المستند المشترك.

يمكن تحقيق مثال باستخدام window.postMessage:

var port = chrome.runtime.connect();

window.addEventListener("message", function(event) {
  // We only accept messages from ourselves
  if (event.source != window)
    return;

  if (event.data.type && (event.data.type == "FROM_PAGE")) {
    console.log("Content script received: " + event.data.text);
    port.postMessage(event.data.text);
  }
}, false);
document.getElementById("theButton").addEventListener("click",
    function() {
  window.postMessage({ type: "FROM_PAGE", text: "Hello from the webpage!" }, "*");
}, false);

تنشر الصفحة غير التابعة للإضافة، example.html، الرسائل إلى نفسها. يتم اعتراض هذه الرسالة وفحصها من خلال النص البرمجي للمحتوى، ثم يتم نشرها في عملية الإضافة. بهذه الطريقة، تنشئ الصفحة قناة تواصل مع عملية الإضافة. ويمكن إجراء العكس بالطريقة نفسها.

الحفاظ على الأمان

على الرغم من أنّ البيئات المعزولة توفّر مستوى من الحماية، إلا أنّ استخدام النصوص البرمجية للمحتوى يمكن أن يؤدي إلى حدوث ثغرات أمنية في الإضافة وصفحة الويب. إذا تلقّى النص البرمجي للمحتوى محتوًى من موقع إلكتروني منفصل، مثل تقديم XMLHttpRequest، احرص على فلترة المحتوى من هجمات البرمجة النصية على مواقع إلكترونية متعددة قبل إدراجه. التواصل عبر HTTPS فقط لتجنُّب هجمات "man-in-the-middle"

احرص على فلترة صفحات الويب الضارة. على سبيل المثال، الأنماط التالية خطيرة:

var data = document.getElementById("json-data")
// WARNING! Might be evaluating an evil script!
var parsed = eval("(" + data + ")")
var elmt_id = ...
// WARNING! elmt_id might be "); ... evil script ... //"!
window.setTimeout("animate(" + elmt_id + ")", 200);

بدلاً من ذلك، ننصحك باستخدام واجهات برمجة تطبيقات أكثر أمانًا لا تشغّل نصوصًا برمجية:

var data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
var parsed = JSON.parse(data);
var elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(function() {
  animate(elmt_id);
}, 200);