aboutsummaryrefslogtreecommitdiff
path: root/files/ru/mozilla/add-ons/sdk/guides/скрипты_содержимого/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/ru/mozilla/add-ons/sdk/guides/скрипты_содержимого/index.html')
-rw-r--r--files/ru/mozilla/add-ons/sdk/guides/скрипты_содержимого/index.html519
1 files changed, 519 insertions, 0 deletions
diff --git a/files/ru/mozilla/add-ons/sdk/guides/скрипты_содержимого/index.html b/files/ru/mozilla/add-ons/sdk/guides/скрипты_содержимого/index.html
new file mode 100644
index 0000000000..59832331e8
--- /dev/null
+++ b/files/ru/mozilla/add-ons/sdk/guides/скрипты_содержимого/index.html
@@ -0,0 +1,519 @@
+---
+title: Скрипты Content Scripts
+slug: Mozilla/Add-ons/SDK/Guides/Скрипты_содержимого
+tags:
+ - Content script
+ - Дополнение
+translation_of: Archive/Add-ons/Add-on_SDK/Guides/Content_Scripts
+---
+<article id="wikiArticle">
+<p>{{AddonSidebar}}</p>
+
+<div class="blockIndicator warning">
+<p>Support for extensions using XUL/XPCOM or the Add-on SDK was removed in Firefox 57, released November 2017. As there is no supported version of Firefox enabling these technologies, this page will be removed by December 2020.</p>
+</div>
+
+<p>{{LegacyAddonsNotice}}</p>
+
+<p>Многим дополнениям (add-on) необходим доступ к веб-страницам и возможность их изменения. Но основной код дополнения не имеет прямого доступа к веб-содержимому. Взамен, SDK-дополнений необходим способ в коде, который даст доступ к веб-содержимому в отдельных скриптах, которые называются <code>content scripts</code> (скрипты содержимого). Эта страница описывает как разрабатывать и реализовывать <code>content scripts</code>.</p>
+
+<p>Скрипты <code>content scripts</code>, вероятно, один из наиболее сбивающих с толку аспектов при работе с SDK, но вам они скорее всего будут нужны. Существуют пять основных принципов:</p>
+
+<ul>
+ <li>расширения основного кода, включая "main.js" и другие модули в "lib", могут использовать SDK <a href="/en-US/Add-ons/SDK/High-Level_APIs">верхнего-уровня</a> и <a href="/en-US/Add-ons/SDK/Low-Level_APIs">нижнего-уровня</a> API, но не имеют доступа к веб-содержимому напрямую;</li>
+ <li>скрипты <code>content scripts </code><a href="/en-US/Add-ons/SDK/Guides/Two_Types_of_Scripts#API_Access_for_Add-on_Code_and_Content_Scripts">не могут использовать API в SDK</a> (нет доступа к глобальным <code>exports</code>, <code>require</code>) но есть доступ к веб-содержимому;</li>
+ <li>API в SDK которые используют <code>content scripts</code>, например <a href="/en-US/Add-ons/SDK/High-Level_APIs/page-mod">page-mod</a> и <a href="/en-US/Add-ons/SDK/High-Level_APIs/tabs">tabs</a>, предоставляют функции, которые позволяют коду расширения загружать скрипты содержимого в веб-страницы;</li>
+ <li>скрипты <code>content scripts </code>могут быть загружены как строки, но чаще они хранятся как отдельные файлы в папке "data". jpm не создаёт каталог "data" по умолчанию, поэтому вы должны создать его и положить туда ваши скрипты;</li>
+ <li>API передачи сообщений позволяет основному коду и скриптам <code>content scripts </code>взаимодействовать друг с другом.</li>
+</ul>
+
+<p>Следующее дополнение (полностью завершённое) показывает эти принципы. "main.js" прикрепляет <code>content scripts</code> к текущей вкладке, используя модуль <a href="/en-US/Add-ons/SDK/High-Level_APIs/tabs">tabs</a>. В этом случае, <code>content scripts</code> передаётся, как строка. Скрипт <code>content scripts</code> просто заменяет содержимое страницы:</p>
+
+<pre class="brush: js">// main.js
+var tabs = require("sdk/tabs");
+var contentScriptString = 'document.body.innerHTML = "&lt;h1&gt;this page has been eaten&lt;/h1&gt;";'
+
+tabs.activeTab.attach({
+ contentScript: contentScriptString
+});</pre>
+
+<p>Следующие высокоуровневые SDK-модули, могут использовать скрипты <code>content scripts </code>для изменения веб-страниц:</p>
+
+<ul>
+ <li><a href="/en-US/Add-ons/SDK/High-Level_APIs/page-mod">page-mod</a>: позволяет вам прикреплять <code>content scripts</code> к веб-страницам, которые соответствуют заданному URL шаблону.</li>
+ <li><a href="/en-US/Add-ons/SDK/High-Level_APIs/tabs">tabs</a>: экспортирует объект <code>Tab</code> для работы с вкладкой браузера. <code>Tab-объект включает</code> функцию <a href="/en-US/Add-ons/SDK/High-Level_APIs/tabs#attach(options)"><code>attach()</code></a>, которая позволяет прикрепить <code>content scripts</code> ко вкладке.</li>
+ <li><a href="/en-US/Add-ons/SDK/High-Level_APIs/page-worker">page-worker</a>: позволяет вам получить страницу, без отображения её. Вы можете прикрепить <code>content scripts</code> к странице, чтобы иметь доступ и возможность изменять DOM страницы.</li>
+ <li><a href="/en-US/Add-ons/SDK/High-Level_APIs/context-menu">context-menu</a>: использует <code>content scripts</code> для взаимодействия со страницей, в которой вызывается меню.</li>
+</ul>
+
+<p>В дополнение к этому, некоторые SDK компоненты пользовательского интерфейса - <code>panel, sidebar, frame</code> - заданы в помощью HTML, и необходимо использовать отдельные скрипты для взаимодействия с их контентом. В большинстве случаев они похожи на скрипты <code>content scripts</code>, но в данной статье они не описываются. Для изучения способов взаимодействия с данными модулями пользовательского интерфейса обратитесь к документации: <a href="/en-US/Add-ons/SDK/High-Level_APIs/panel">panel</a>, <a href="/en-US/Add-ons/SDK/Low-Level_APIs/ui_sidebar">sidebar</a>, <a href="/en-US/Add-ons/SDK/Low-Level_APIs/ui_frame">frame</a>.</p>
+
+<p>Почти все примеры дополнений, представленных в этом руководстве, доступны в полнофункциональном, но минимально необходимом, виде. На GitHub: <a href="https://github.com/mdn/addon-sdk-content-scripts">addon-sdk-content-scripts repository</a>.</p>
+
+<h2 id="Загрузка_content_scripts">Загрузка content scripts</h2>
+
+<article id="wikiArticle">
+<p>Вы можете загрузить одиночный скрипт посредством задания строкового атрибута <code>contentScript</code> или <code>contentScriptFile.</code> Атрибут<code> contentScript</code> определяет строковое значение как сам скрипт:</p>
+
+<pre class="brush: js">// main.js
+
+var pageMod = require("sdk/page-mod");
+var contentScriptValue = 'document.body.innerHTML = ' +
+ ' "&lt;h1&gt;Page matches ruleset&lt;/h1&gt;";';
+
+pageMod.PageMod({
+ include: "*.mozilla.org",
+ contentScript: contentScriptValue
+});</pre>
+
+<p>Атрибут <code>contentScriptFile</code> определяет строковое значение как путь к ресурсу<code>://<em>URL-путь к скрипту, который находится в подкаталоге вашего дополнения</em>.</code> jpm не создаёт папку "data" по умолчанию, поэтому вы должны добавить её и положить внутрь файл <code>content scripts</code>.</p>
+
+<p>Следующее дополнение использует URL для ссылки на файл "content-script.js", находящийся в папке <code>data </code>в корне дополнения.</p>
+
+<pre class="brush: js">// main.js
+
+var data = require("sdk/self").data;
+var pageMod = require("sdk/page-mod");
+
+pageMod.PageMod({
+ include: "*.mozilla.org",
+ contentScriptFile: data.url("content-script.js")
+});</pre>
+
+<pre class="brush: js">// content-script.js
+
+document.body.innerHTML = "&lt;h1&gt;Page matches ruleset&lt;/h1&gt;";</pre>
+
+<div class="note">
+<p>Начиная с Firefox 34 и далее , вы можете использовать "./content-script.js" как синоним для self.data.url("content-script.js"). Поэтому можно переписать код main.js, указанный выше, следующим образом:</p>
+
+<pre class="brush: js">var pageMod = require("sdk/page-mod");
+
+pageMod.PageMod({
+ include: "*.mozilla.org",
+ contentScriptFile: "./content-script.js"
+});
+</pre>
+</div>
+
+<div class="warning">
+<p>Настоятельно рекоммендуется использовать  <code>contentScript </code>только для очень простых скриптов или статичных строк: если это не так, то могут возникнуть проблемы с принятием Вашего дополнения на AMO (<span class="st">addons.<em>mozilla</em>.org</span>).</p>
+
+<p>Содержите ваши скрипты в отдельном файле и загружайте их, используя <code>contentScriptFile</code>. Это сделает ваш код проще в поддержке, отладке, безопаснее, удобочитаемее.</p>
+</div>
+
+<p>Для любого из параметров<code> contentScript</code> или <code>contentScriptFile</code> вы можете загружать несколько скриптов, передавая массив строк:</p>
+
+<pre class="brush: js">// main.js
+
+var tabs = require("sdk/tabs");
+
+tabs.on('ready', function(tab) {
+ tab.attach({
+ contentScript: ['document.body.style.border = "5px solid red";', 'window.alert("hi");']
+ });
+});
+</pre>
+
+<pre class="brush: js">// main.js
+
+var data = require("sdk/self").data;
+var pageMod = require("sdk/page-mod");
+
+pageMod.PageMod({
+ include: "*.mozilla.org",
+ contentScriptFile: [data.url("jquery.min.js"), data.url("my-content-script.js")]
+});</pre>
+
+<p>Если так сделать, то скрипты смогут взаимодействовать друг с другом, как скрипты загружаемые на одной web-странице.</p>
+
+<p>Можно использовать параметры <code>contentScript</code> and <code>contentScriptFile </code>одновременно. В таком случае скрипты, загружаемые <code>contentScriptFile</code>  загрузятся до <code>contentScript. </code>Это похволяет загружать библиотеки JavaScript, такие как jQuery по URL, а затем использвать их в простом скрипте, загруженном через <code>contentScript</code>:</p>
+
+<pre class="brush: js">// main.js
+
+var data = require("sdk/self").data;
+var pageMod = require("sdk/page-mod");
+
+var contentScriptString = '$("body").html("&lt;h1&gt;Page matches ruleset&lt;/h1&gt;");';
+
+pageMod.PageMod({
+ include: "*.mozilla.org",
+ contentScript: contentScriptString,
+ contentScriptFile: data.url("jquery.js")
+});</pre>
+
+<div class="warning">
+<p>Настоятельно рекоммендуется использовать  <code>contentScript </code>только для очень простых скриптов или статичных строк: если это не так, то могут возникнуть проблемы с принятием Вашего дополнения на AMO (<span class="st">addons.<em>mozilla</em>.org</span>).</p>
+
+<p>Содержите ваши скрипты в отдельном файле и загружайте их, используя <code>contentScriptFile</code>. Это сделает ваш код проще в поддержке, отладке, безопаснее, удобочитаемее.</p>
+</div>
+
+<h3 id="Определение_момента_(времени)_подключения_скрипта">Определение момента (времени) подключения скрипта</h3>
+
+<p>Опция <code>contentScriptWhen </code>определяет момент, когда <code>content script</code> должен быть загружен. Возможные варианты:</p>
+
+<ul>
+ <li><code>"start"</code>: загрузить сразу после того, как элемент документа страницы вставляется в DOM. В таком случае DOM-контент ещё пока не загружен, поэтому скрипт не может работать с ним.</li>
+ <li><code>"ready"</code>: загрузить скрипт после того, как DOM страницы загружен: то есть в точке активации событий <a href="https://developer.mozilla.org/en/Gecko-Specific_DOM_Events">DOMContentLoaded</a>. В этот момент content scripts уже могут взаимодействовать с DOM-контентом, но загрузка внешних CSS и картинок ещё могла не завершиться.</li>
+ <li><code>"end"</code>: загрузить скрипт после завершения загрузки всего контента (DOM, JS, CSS, картинки), в то время, как активируется событие <a href="https://developer.mozilla.org/en/DOM/window.onload">window.onload event</a>.</li>
+</ul>
+
+<p>Значение по умолчанию <code>"<strong>end</strong>"</code>.</p>
+
+<p>Обратите внимание, что <a href="/en-US/Add-ons/SDK/High-Level_APIs/tabs#attach(options)"><code>tab.attach()</code></a> не имеет параметра <code>contentScriptWhen</code>, потому что он обычно вызывается после загрузки страницы.<a href="/en-US/Add-ons/SDK/High-Level_APIs/tabs#attach(options)"><code> </code></a></p>
+
+<h3 id="Передача_конфигурационных_опций">Передача конфигурационных опций</h3>
+
+<p><code>Атрибут contentScriptOptions</code> это JSON-объект, который используется скриптом как read-only значение доступное через свойство <code><a href="/en-US/Add-ons/SDK/Guides/Content_Scripts/self">self</a>.options</code>:</p>
+
+<pre class="brush: js">// main.js
+
+var tabs = require("sdk/tabs");
+
+tabs.on('ready', function(tab) {
+ tab.attach({
+ contentScript: 'window.alert(self.options.message);',
+ contentScriptOptions: {"message" : "hello world"}
+ });
+});</pre>
+
+<p>Могут быть использованы любые варианты JSON-объектов (object, array, string, etc.).</p>
+
+<h2 id="Доступ_к_DOM">Доступ к DOM</h2>
+
+<p>Скрипты <code>content scripts</code> могут иметь доступ к DOM страницы, конечно, только те скрипты, которые уже загрузились на странице. При этом скрипты content scripts изолированы от скриптов web-страницы:</p>
+
+<ul>
+ <li>content scripts не видят объектов JavaScript, добавленных скриптами web-страницы.</li>
+ <li>Если скриты web-страницы переопределят поведения каких-либо DOM-объектов, то скрипты <code>content script</code> обнаружат исходное поведение.</li>
+</ul>
+
+<p>То же происходит в обратную сторону: скрипты web-страницы не увидят объектов JavaScript, добавленных скриптами <code>content scripts</code>.</p>
+
+<p>Например, рассмотрим страницу, где скрипты web-страницы создают переменную <code>foo </code>в объекте <code>window</code>:</p>
+
+<pre class="brush: html">&lt;!DOCTYPE html"&gt;
+&lt;html&gt;
+ &lt;head&gt;
+ &lt;script&gt;
+ window.foo = "hello from page script"
+ &lt;/script&gt;
+ &lt;/head&gt;
+&lt;/html&gt;</pre>
+
+<p>Другой скрипт (но тоже page-script), загруженный на страницу после этого скрипта (указанного выше), будет иметь доступ к foo. Но скрипт <code>content script</code> нет:</p>
+
+<pre class="brush: js">// main.js
+
+var tabs = require("sdk/tabs");
+var mod = require("sdk/page-mod");
+var self = require("sdk/self");
+
+var pageUrl = self.data.url("page.html")
+
+var pageMod = mod.PageMod({
+ include: pageUrl,
+ contentScript: "console.log(window.foo);"
+})
+
+tabs.open(pageUrl);</pre>
+
+<pre>console.log: my-addon: null
+</pre>
+
+<p>Есть веские причины для изоляции. Во-первых, из <code>content script</code> не утекают объекты в web-страницу, что потенциально является дырой в безопасности. Во-вторых, <code>content scripts</code> могут не беспокоиться о пересечении объектов с объектами, созданных скриптами web-страницы.</p>
+
+<p>Такая изоляция необходима, например, в случае, если web-страница загружает библиотеку jQuery, но <code>content script</code> не увидит объектов, созданных этой библиотекой. В этом случае content script может добавить свою собственный jQuery-объект, который не пересечётся со страничным объектом.</p>
+
+<h3 id="Взаимодействие_со_скриптами_web-страницы">Взаимодействие со скриптами web-страницы</h3>
+
+<p>Обычно изоляция content scripts и page scripts (скрипты web-страницы) необходима. Но иногда вы захотите наладить такое взаимодействие: вы можете захотеть иметь общие объекты между <code>content scripts</code> и <code>page scripts</code> или передевать между ними сообщения. Если появится такая необходимость, то прочтите о <a href="/en-US/Add-ons/SDK/Guides/Content_Scripts/Interacting_with_page_scripts">взаимодействии со скриптами web-страницы</a> (<a href="/en-US/Add-ons/SDK/Guides/Content_Scripts/Interacting_with_page_scripts">interacting with page scripts</a>).</p>
+
+<h3 id="Прослушивание_событий">Прослушивание событий</h3>
+
+<p>Вы можете прослушивать события DOM в скриптах <code>content scripts</code> также, как в обычных скриптах web-страницы. Но есть два важных отличия:</p>
+
+<p>Первое. Если вы определите слушатель через передачу строки в функцию<a href="https://developer.mozilla.org/en/DOM/element.setAttribute"><code> setAttribute()</code></a>, то слушатель будет вызываться в контексте web-страницы, поэтому он не будет иметь доступа ни к каким переменным, определённым в <code>content script</code>.</p>
+
+<p>Например, при выполнении в данном <code>content script</code> появится ошибка "theMessage is not defined":</p>
+
+<pre class="brush: js">var theMessage = "Hello from content script!";
+anElement.setAttribute("onclick", "alert(theMessage);");</pre>
+
+<p>Второе. Если вы определите слушатель напрямую через <a href="/en-US/docs/Web/API/GlobalEventHandlers">GlobalEventHandlers</a>, например на <code>onclick</code>, то такое определение может быть переопределено на web-странице. Например, здесь представлен add-on, который пытается добавить обработчик click-события при помощи присвоения <code>window.onclick</code>:</p>
+
+<pre class="brush: js">var myScript = "window.onclick = function() {" +
+ " console.log('unsafewindow.onclick: ' + window.document.title);" +
+ "}";
+
+require("sdk/page-mod").PageMod({
+ include: "*",
+ contentScript: myScript,
+ contentScriptWhen: "start"
+});</pre>
+
+<p>Это всё будет прекрасно работать на многих страницах, но не сработает там, где также присваивается <code>onclick</code>:</p>
+
+<pre class="brush: html">&lt;html&gt;
+ &lt;head&gt;
+ &lt;/head&gt;
+ &lt;body&gt;
+ &lt;script&gt;
+ window.onclick = function() {
+ window.alert("it's my click now!");
+ }
+ &lt;/script&gt;
+ &lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>По этим причинам, лучший вариант для добавления слушалелей это использование <a href="https://developer.mozilla.org/en/DOM/element.addEventListener"><code>addEventListener()</code></a>, определяющем функцию:</p>
+
+<pre class="brush: js">var theMessage = "Hello from content script!";
+
+anElement.onclick = function() {
+ alert(theMessage);
+};
+
+anotherElement.addEventListener("click", function() {
+ alert(theMessage);
+});</pre>
+
+<h2 id="Взаимодействие_с_скриптом_дополнения_(add-on)">Взаимодействие с скриптом дополнения (add-on)</h2>
+
+<p>Для организации взаимодействия друг с другом скрипта дополнения (<code>add-on script</code>) и скрипта <code>content script</code> нужно обоим дать доступ к объекту <code>port</code>.</p>
+
+<ul>
+ <li>для отправки сообщений используется <code>port.emit()</code></li>
+ <li>для получения сообщений - <code>port.on()</code></li>
+</ul>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/7873/content-scripting-overview.png" style="display: block; margin-left: auto; margin-right: auto;">Сообщения асинхронны: то есть, отправитель не ждёт ответа от получателя, а только отправляет сообщение и продолжает работать дальше.</p>
+
+<p>Вот пример простого дополнения, которое отправляет сообщение скрипту <code>content script, используя port</code>:</p>
+
+<pre class="brush: js">// main.js
+
+var tabs = require("sdk/tabs");
+var self = require("sdk/self");
+
+tabs.on("ready", function(tab) {
+ var worker = tab.attach({
+ contentScriptFile: self.data.url("content-script.js")
+ });
+ worker.port.emit("alert", "Message from the add-on");
+});
+
+tabs.open("http://www.mozilla.org");</pre>
+
+<pre class="brush: js">// content-script.js
+
+self.port.on("alert", function(message) {
+ window.alert(message);
+});</pre>
+
+<div class="note">
+<p>Модуль <code>context-menu</code> не использует данную модель коммуникации. Для изучения варианта взаимодействия скриптов <code>content scripts</code>, загруженных с использованием <code>context-menu</code>, смотрите <a href="/en-US/Add-ons/SDK/High-Level_APIs/context-menu">context-menu documentation</a>. </p>
+</div>
+
+<h3 id="Доступ_к_порту_в_content_script">Доступ к порту в content script</h3>
+
+<p>В скрипте <code>content script</code> объект <code>port </code>доступен через свойство глобального объекта <a href="/en-US/Add-ons/SDK/Guides/Content_Scripts/self"><code>self</code></a>.  Чтобы послать сообщение из <code>content script</code>:</p>
+
+<pre class="brush: js">self.port.emit("myContentScriptMessage", myContentScriptMessagePayload);</pre>
+
+<p>Чтобы получить сообщение из кода дополнения:</p>
+
+<pre class="brush: js">self.port.on("myAddonMessage", function(myAddonMessagePayload) {
+ // Handle the message
+});</pre>
+
+<div class="note">
+<p><span>Учтите, что глобальный объект <a href="/en-US/Add-ons/SDK/Guides/Content_Scripts/self"><code>self</code></a> совершенно отличается от модуля <a href="https://developer.mozilla.org/en-US/Add-ons/SDK/High-Level_APIs/self"><code>self</code> module</a>, предоставляющим API дополнению для доступа к его файлам и ID.</span></p>
+</div>
+
+<h3 id="Доступ_к_порту_в_скрипте_дополнения_(add-on_script)">Доступ к порту в скрипте дополнения (add-on script)</h3>
+
+<p>В коде дополнения канал взаимодействия между дополнением и конкретным <code>content script</code> инкапсулируется посредством объекта <a href="https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/content_worker"><code>worker</code></a>. Поэтому объект <code>port </code>для для связи со скриптом content script это свойство связанного worker.</p>
+
+<p>Тем не менее, объект worker не расширен на код дополнения так же, как в других модулях.</p>
+
+<h4 id="Сообщения_из_page-worker">Сообщения из<code> page-worker</code></h4>
+
+<p>Объект <code>page-worker</code> интегрирует в себе <code>worker API</code>. Поэтому для получения сообщений от скрипта content script, ассоциированного с <code>page-worker нужно использовать </code><code>pageWorker.port.on()</code>:</p>
+
+<pre class="brush: js">// main.js
+
+var self = require("sdk/self");
+
+var pageWorker = require("sdk/page-worker").Page({
+  contentScriptFile: self.data.url("content-script.js"),
+  contentURL: "http://en.wikipedia.org/wiki/Internet"
+});
+
+pageWorker.port.on("first-para", function(firstPara) {
+  console.log(firstPara);
+});</pre>
+
+<p>Для отправки пользовательских сообщений их дополнения нужно вызвать <code>pageWorker.port.emit()</code>:</p>
+
+<pre class="brush: js">// main.js
+
+var self = require("sdk/self");
+
+var pageWorker = require("sdk/page-worker").Page({
+  contentScriptFile: self.data.url("content-script.js"),
+  contentURL: "http://en.wikipedia.org/wiki/Internet"
+});
+
+pageWorker.port.on("first-para", function(firstPara) {
+  console.log(firstPara);
+});
+
+pageWorker.port.emit("get-first-para");</pre>
+
+<pre class="brush: js">// content-script.js
+
+self.port.on("get-first-para", getFirstPara);
+
+function getFirstPara() {
+ var paras = document.getElementsByTagName("p");
+ if (paras.length &gt; 0) {
+ var firstPara = paras[0].textContent;
+ self.port.emit("first-para", firstPara);
+ }
+}</pre>
+
+<h4 id="Сообщения_из_page-mod">Сообщения из <code>page-mod</code></h4>
+
+<p>Один объект <code>page-mod</code> может привязать свои скрипты к нескольким страницам, каждая из них со своим контекстом, в котором запускаются <code>content scripts</code>. Поэтому для каждой страницы необходим отдельный канал (<code>worker</code>) связи.</p>
+
+<p><code>page-mod</code> не интегрирует в себе <code>worker API напрямую</code>. Вместо этого, когда скрипт <code>content script</code> привязывается к странице, <code>page-mod</code> бросает событие <code>attach</code> тому слушателю, который связан с worker. Создавая слушатель для события <code>attach</code>, вы можете получить доступ через объект <code>port </code>к тому скрипту <code>content scripts</code>, который связан с нужной страницей (через <code>page-mod)</code>:</p>
+
+<pre class="brush: js">// main.js
+
+var pageMods = require("sdk/page-mod");
+var self = require("sdk/self");
+
+var pageMod = pageMods.PageMod({
+  include: ['*'],
+  contentScriptFile: self.data.url("content-script.js"),
+  onAttach: startListening
+});
+
+function startListening(worker) {
+  worker.port.on('click', function(html) {
+    worker.port.emit('warning', 'Do not click this again');
+  });
+}</pre>
+
+<pre class="brush: js">// content-script.js
+
+window.addEventListener('click', function(event) {
+ self.port.emit('click', event.target.toString());
+ event.stopPropagation();
+ event.preventDefault();
+}, false);
+
+self.port.on('warning', function(message) {
+ window.alert(message);
+});
+</pre>
+
+<p>В дополнении, описанном выше, есть два сообщения:</p>
+
+<ul>
+ <li><code>click</code> отправляется из <code>page-mod</code> в дополнение, когда пользователь кликает на элемент на web-странице</li>
+ <li><code>warning</code> отправляет прикольную строчку обратно в объект <code>page-mod</code></li>
+</ul>
+
+<h4 id="Сообщения_из_Tab.attach()">Сообщения из <code>Tab.attach()</code></h4>
+
+<p>Функция <code>Tab.attach()</code> возвращает <code>worker</code>, который можно использовать для связи со скриптом content script(s).</p>
+
+<p>Следующее дополнение добавляет кнопку в Firefox: когда пользователь надимает её, то дополнение привязывает скрипт <code>content script</code> к активной вкладке, отправляет этому скрипту сообщение "my-addon-message" и ждёт ответ "my-script-response":</p>
+
+<pre class="brush: js">//main.js
+
+var tabs = require("sdk/tabs");
+var buttons = require("sdk/ui/button/action");
+var self = require("sdk/self");
+
+buttons.ActionButton({
+ id: "attach-script",
+ label: "Attach the script",
+ icon: "./icon-16.png",
+ onClick: attachScript
+});
+
+function attachScript() {
+ var worker = tabs.activeTab.attach({
+ contentScriptFile: self.data.url("content-script.js")
+ });
+ worker.port.on("my-script-response", function(response) {
+ console.log(response);
+ });
+ worker.port.emit("my-addon-message", "Message from the add-on");
+}
+</pre>
+
+<pre class="brush: js">// content-script.js
+
+self.port.on("my-addon-message", handleMessage);
+
+function handleMessage(message) {
+ alert(message);
+ self.port.emit("my-script-response", "Response from content script");
+}</pre>
+
+<h3 id="Описание_port_API">Описание port API</h3>
+
+<p>Смотрите <a href="/en-US/Add-ons/SDK/Guides/Content_Scripts/port">reference page for the <code>port</code> object</a>.</p>
+</article>
+
+<h3 id="Описание_postMessage_API">Описание postMessage API</h3>
+
+<p>До того, как был введён объект port, дополнения и <code>content scripts </code>общались следующим образом, используя различные API:</p>
+
+<ul>
+ <li>скрипт content script <code>вызывал self.postMessage()</code> для отправки и <code>self.on()</code> для получения</li>
+ <li>дополнение (add-on) вызывал <code>worker.postMessage()</code> для отправки и <code>worker.on()</code> для получения</li>
+</ul>
+
+<p>Данный API до сих пор доступно и <a href="/en-US/Add-ons/SDK/Guides/Content_Scripts/using_postMessage">документировано</a>, но желательно использовать <code>port API</code>, описанный здесь выше. Исключением является модуль <a href="/en-US/Add-ons/SDK/High-Level_APIs/context-menu">context-menu</a>, который ещё использует <code>postMessage</code>.</p>
+
+<h3 id="Взаимодействие_скриптов_content_script_со_скриптами_content_script">Взаимодействие скриптов content script со скриптами content script</h3>
+
+<p>Скрипты <code>content scripts</code> могут взаимодействовать друг с другом напрямую если они загружены в одном контексте. Например, если один вызов <code>Tab.attach()</code> привязывает два скрипта <code>content scripts</code>, то они видят друг друга напрямую, как если два скрипта загружены на одну страницу. Но если вызвать <code>Tab.attach()</code> дважды, привязывая <code>content scripts</code> каждый раз, то они уже не будут загружены в одном контексте, и дожны взаимодействовать способами как скрипты из разных контекстов. Один из вариантом это пересылать сообщения через основной код дополнения, используя port API с передачей сообщения другим скриптам <code>context script</code>. Этои вариант будет работать независимо от контекста, в котором загружен скрипт <code>content script</code>.</p>
+
+<p>В отдельном случае, когда два скрипта загружены на одной странице, существует возможность для обоих скриптов <code>content scripts</code> взаимодействовать друг с другом, используя<a href="https://developer.mozilla.org/en-US/Add-ons/SDK/Guides/Content_Scripts/Communicating_With_Other_Scripts#Using_the_DOM_postMessage_API"> DOM postMessage() API</a> или <a href="https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent">CustomEvent</a>. Следующее дополнение показывает как скрипт <code>content script</code>, добавленный через <code>page-mod</code>, получает событие CustomEvent, отправленное из <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/SDK/High-Level_APIs/context-menu">context-menu</a>, когда элемент меню был кликнут. Скрипт <code>page-mod</code> будет отображать алерт с URL той ссылки, по которой было отображено контекстное меню. URL передан в скрипт <code>page-mod</code> с использованием CustomEvent.</p>
+
+<pre><code>var pageMod = require("sdk/page-mod");
+pageMod.PageMod({
+ include: "*.mozilla.org",
+ contentScript: 'function contextMenuAlert(href) {'
+ + ' window.alert("The context menu was clicked on URL:\\n" + href);'
+ + '};'
+ + 'window.addEventListener("myAddonId-contextMenu-clicked",'
+ + ' function(event){contextMenuAlert(event.detail);});'
+});
+
+let cm = require("sdk/context-menu");
+cm.Item({
+ label: "Alert URL",
+ context: [
+ cm.URLContext(["*.mozilla.org"]),
+ cm.SelectorContext("a[href]")
+ ],
+ contentScript: 'self.on("click", function (node, data) {'
+ + ' var event = new CustomEvent("myAddonId-contextMenu-clicked",'
+ + ' {detail:node.href});'
+ + ' window.dispatchEvent(event);'
+ + '});'
+});</code></pre>
+
+<h2 id="Междоменные_скрипты_content_script">Междоменные скрипты <code>content script</code></h2>
+
+<p>По умолчанию скрипты <code>content script </code>не имеют никаких междоменных привилегий. В частности, они не имеют доступа к содержимому в <code>iframe</code>, если содержимое получено из другого домена, или выполняются междоменные XMLHttpRequests.</p>
+
+<p>Однако, вы можете разрешить эти функции для заданных доменов, путём добавления их в <a href="/en-US/Add-ons/SDK/Tools/package_json">package.json</a> дополнения в ключе <code>"cross-domain-content"</code>, который расположен в ключе <code>"permissions"</code>. Смотрите статью <a href="/en-US/Add-ons/SDK/Guides/Content_Scripts/Cross_Domain_Content_Scripts">междоменные скрипты содержимого</a>.</p>
+</article>