diff options
Diffstat (limited to 'files/ru/mozilla/add-ons/sdk/guides/скрипты_содержимого/index.html')
| -rw-r--r-- | files/ru/mozilla/add-ons/sdk/guides/скрипты_содержимого/index.html | 519 |
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 = "<h1>this page has been eaten</h1>";' + +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 = ' + + ' "<h1>Page matches ruleset</h1>";'; + +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 = "<h1>Page matches ruleset</h1>";</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("<h1>Page matches ruleset</h1>");'; + +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"><!DOCTYPE html"> +<html> + <head> + <script> + window.foo = "hello from page script" + </script> + </head> +</html></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"><html> + <head> + </head> + <body> + <script> + window.onclick = function() { + window.alert("it's my click now!"); + } + </script> + </body> +</html></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 > 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> |
