aboutsummaryrefslogtreecommitdiff
path: root/files/ru/mozilla/add-ons/webextensions/modify_a_web_page/index.html
blob: 169be48be831f4ca8c1c25ff7bca092c0a9ce2df (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
---
title: Модификация веб страницы
slug: Mozilla/Add-ons/WebExtensions/Modify_a_web_page
translation_of: Mozilla/Add-ons/WebExtensions/Modify_a_web_page
original_slug: Mozilla/Add-ons/WebExtensions/модификация_веб_страницы
---
<p> </p>

<div>{{AddonSidebar}}</div>

<p>Одним из наиболее распространённых вариантов использования расширений является внесение изменение в веб-страницу. К примеру, расширение может изменить стиль, применённый к странице, скрыть существующие или вставить на страницу дополнительные DOM-узлы.</p>

<p>Существует два способа сделать это используя WebExtensions API:</p>

<ul>
 <li><strong>Декларативно</strong>: объявить шаблон, которому соответствует набор URL-адресов, и загрузить набор скриптов на страницы, которые попадают в под этот шаблон.</li>
 <li><strong>Программно</strong>: используя JavaScript API, загрузить скрипт на страницу, из определённой вкладки.</li>
</ul>

<p>В любом случае, эти скрипты называются <em>контентными скриптами</em>, и отличаются от других скриптов, которые составляют расширение:</p>

<ul>
 <li>Они получают доступ к малому подмножеству WebExtension API.</li>
 <li>Они получают прямой доступ к странице, на которой были загружены.</li>
 <li>Они взаимодействуют с остальными скриптами расширения, используя API сообщений.</li>
</ul>

<p>В этой статье мы рассмотрим оба способа загрузки скрипта.</p>

<h2 id="Модификация_страниц_подпадающих_под_URL-шаблон">Модификация страниц, подпадающих под URL-шаблон</h2>

<p>Прежде всего создадим новую директорию, назовём её "modify-page". В этой директории, создадим файл "manifest.json", со следующим содержимым:</p>

<pre class="brush: json">{

  "manifest_version": 2,
  "name": "modify-page",
  "version": "1.0",

  "content_scripts": [
    {
      "matches": ["https://developer.mozilla.org/*"],
      "js": ["page-eater.js"]
    }
  ]

}</pre>

<p>Ключ <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts</a></code> - это как мы загружаем скрипты на страницы, соответствующие URL-шаблону. В нашем случае, <code>content_scripts</code> говорит браузеру загрузить скрипт "page-eater.js" на все страницы, начинающиеся с <a href="https://developer.mozilla.org/">https://developer.mozilla.org/</a>.</p>

<div class="note">
<p>Поскольку свойство <code>"js"</code> ключа <code>content_scripts</code> это массив, вы можете использовать его, для внедрения более одного скрипта. Если вы сделаете это, страницы получат набор, как если бы эти скрипты были загружены самой страницей, они будут загружены в той же очерёдности, в которой они расположены в массиве.</p>
</div>

<div class="note">
<p>Ключ <code>content_scripts</code> также имеет свойство  <code>"css"</code>, которое вы можете использовать для вставки CSS-таблиц.</p>
</div>

<p>Далее, создадим файл "page-eater.js", внутри директории "modify-page":</p>

<pre class="brush: js">document.body.textContent = "";

var header = document.createElement('h1');
header.textContent = "Эта страница была съедена";
document.body.appendChild(header);</pre>

<p>Теперь <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox">установим расширение</a>, и перейдём на страницу <a href="https://developer.mozilla.org/">https://developer.mozilla.org/</a>:</p>

<p>{{EmbedYouTube("lxf2Tkg6U1M")}}</p>

<div class="note">
<p>Обратите внимание, несмотря на то, что в указанном видео, на странице <a href="https://addons.mozilla.org/en-US/firefox/">addons.mozilla.org</a> всё работает нормально, на текущий момент, для этого сайта, контентные скрипты заблокированы.</p>
</div>

<h2 id="Программная_модификация_страницы">Программная модификация страницы</h2>

<p>Что, если вы всё ещё хотите "съедать" страницы, но лишь в тех случаях, когда пользователь попросил об этом? Давайте обновим этот пример таким образом, чтобы мы внедряли контентный скрипт, когда пользователь выбирает соответствующий пункт контентного меню.</p>

<p>Для начала обновим "manifest.json":</p>

<pre class="brush: json">{

  "manifest_version": 2,
  "name": "modify-page",
  "version": "1.0",

  "permissions": [
    "activeTab",
    "contextMenus"
  ],

  "background": {
    "scripts": ["background.js"]
  }

}</pre>

<p>Мы удалили ключ <code>content_scripts</code> и добавили два новых:</p>

<ul>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions">permissions (разрешения)</a></code>: для внедрения скрипта, нам нужны разрешения для страниц, которые мы модифицируем.  <a href="/en-US/Add-ons/WebExtensions/manifest.json/permissions#activeTab_permission">Разрешение <code>activeTab</code></a> это способ получить доступ к текущей вкладки. Нам также нужно разрешение <code>contextMenus</code>, чтобы добавлять в контекстное меню новые элементы.</li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/background">background (фоновый)</a></code>: мы используем этот ключ, для загрузки постоянного <a href="/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Background_scripts">"фонового скрипта"</a>, с именем "background.js", в котором мы настроим контекстное меню и внедрим контентный скрипт.</li>
</ul>

<p>Давайте создадим этот файл. Создадим новый файл "background.js" в директории "modify-page" и поместим в него следующий код:</p>

<pre class="brush: js">browser.contextMenus.create({
  id: "eat-page",
  title: "Съесть эту страницу"
});

browser.contextMenus.onClicked.addListener(function(info, tab) {
  if (info.menuItemId == "eat-page") {
    browser.tabs.executeScript({
      file: "page-eater.js"
    });
  }
});
</pre>

<p>В этом скрипте мы создаём <a href="/en-US/Add-ons/WebExtensions/API/ContextMenus/create">элемент контекстного меню</a>, передавая ему определённый идентификатор и заголовок (текст будет отображаться в элементе контекстного меню). Затем мы настраиваем обработчик событий таким образом, чтобы когда пользователь выбирает пункт контекстного меню, осуществлялась проверка, наш ли это элемент <code>eat-page</code>. Если это так - внедряем скрипт "page-eater.js" в текущую вкладку, используя <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript">tabs.executeScript()</a></code> API. Это API опционально принимает идентификатор вкладки, в качестве аргумента. Мы опустили его, это означает, что скрипт будет внедряться в текущую активную вкладку.</p>

<p>На данном этапе расширение должно иметь следующий вид:</p>

<pre class="line-numbers  language-html"><code class="language-html">modify-page/
    background.js
    manifest.json
    page-eater.js</code></pre>

<p>Теперь <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox#Reloading_a_temporary_add-on">перезагрузим расширение</a>, откроем страницу (на этот раз любую) активируем контекстное меню и выберем "Съесть эту страницу":</p>

<p>{{EmbedYouTube("zX4Bcv8VctA")}}</p>

<div class="note">
<p>Обратите внимание, несмотря на то, что в указанном видео, на странице <a href="https://addons.mozilla.org/en-US/firefox/">addons.mozilla.org</a> всё работает нормально, на текущий момент, для этого сайта, контентные скрипты заблокированы.</p>
</div>

<h2 id="Обмен_сообщениями">Обмен сообщениями</h2>

<p>Контентные и фоновые скрипты не могут на прямую взаимодействовать друг с другом. Не смотря на это они могут взаимодействовать с помощью обмена сообщениями. Для этого один конец создаёт обработчик сообщений, а другой - может посылать сообщения. В следующей таблице представлены API-интерфейсы, задействованные с каждой стороны:</p>

<table class=" fullwidth-table standard-table">
 <thead>
  <tr>
   <th scope="row"></th>
   <th scope="col">В контентном скрипте</th>
   <th scope="col">В фоновом скрипте</th>
  </tr>
  <tr>
   <th scope="row">Отправка сообщения</th>
   <td><code><a href="/en-US/Add-ons/WebExtensions/API/runtime#sendMessage()">browser.runtime.sendMessage()</a></code></td>
   <td><code><a href="/en-US/Add-ons/WebExtensions/API/Tabs/sendMessage">browser.tabs.sendMessage()</a></code></td>
  </tr>
  <tr>
   <th scope="row">Получение сообщения</th>
   <td><code><a href="/en-US/Add-ons/WebExtensions/API/runtime/onMessage">browser.runtime.onMessage</a></code></td>
   <td><code><a href="/en-US/Add-ons/WebExtensions/API/runtime#onMessage">browser.runtime.onMessage</a></code></td>
  </tr>
 </thead>
</table>

<p>Давайте обновим наш пример, чтобы посмотреть, как послать сообщение из фонового скрипта.</p>

<p>Изменим "background.js" :</p>

<pre class="brush: js">browser.contextMenus.create({
  id: "eat-page",
  title: "Съесть эту страницу"
});

function messageTab(tabs) {
  browser.tabs.sendMessage(tabs[0].id, {
    replacement: "Message from the extension!"
  });
}

browser.contextMenus.onClicked.addListener(function(info, tab) {
  if (info.menuItemId == "eat-page") {
    browser.tabs.executeScript({
      file: "page-eater.js"
    });

    var querying = browser.tabs.query({
      active: true,
      currentWindow: true
    });
    querying.then(messageTab);
  }
});
</pre>

<p>Теперь, после внедрения "page-eater.js", мы используем <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/query">tabs.query()</a></code>, чтобы получить текущую открытую вкладку и используем <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage">tabs.sendMessage()</a></code>, для отправки сообщения контентному скрипту, загруженному на этой вкладке. Сообщение несёт полезную нагрузку <code>{replacement: "Message from the extension!"}</code>.</p>

<p>Далее, обновим "page-eater.js":</p>

<pre class="brush: js">function eatPage(request, sender, sendResponse) {
  document.body.textContent = "";

  var header = document.createElement('h1');
  header.textContent = request.replacement;
  document.body.appendChild(header);
}

browser.runtime.onMessage.addListener(eatPage);
</pre>

<p>Теперь, вместо простого "поедания страницы", контентный скрипт ждёт сообщение, используя <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage">runtime.onMessage</a></code>. Когда сообщение получено, контентный скрипт выполняет в точности такой же код, как и а примере ранее, за исключением того, что заменяющий текст берётся из <code>request.replacement</code>.</p>

<p>Если мы хотим отправить сообщение наоборот, из контентного скрипта в фоновый, настройка будет обратной данному примеру, за исключением того, что мы будем использовать <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage">runtime.sendMessage()</a></code> в контентном скрипте.</p>

<div class="note">
<p>Все эти примеры внедряют JavaScript; вы можете программно внедрять стилевые таблицы CSS используя функцию <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/insertCSS">tabs.insertCSS()</a></code>.</p>
</div>

<h2 id="Узнать_больше">Узнать больше</h2>

<ul>
 <li>Руководство по <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts">Content scripts</a></li>
 <li>Ключ манифеста<code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts</a></code></li>
 <li>Ключ манифеста<code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions">permissions</a></code></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript">tabs.executeScript()</a></code></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/insertCSS">tabs.insertCSS()</a></code></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage">tabs.sendMessage()</a></code></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage">runtime.sendMessage()</a></code></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage">runtime.onMessage</a></code></li>
 <li>Примеры использования <code>content_scripts</code>:
  <ul>
   <li><a href="https://github.com/mdn/webextensions-examples/tree/master/borderify">borderify</a></li>
   <li><a href="https://github.com/mdn/webextensions-examples/tree/master/notify-link-clicks-i18n">notify-link-clicks-i18n</a></li>
   <li><a href="https://github.com/mdn/webextensions-examples/tree/master/page-to-extension-messaging">page-to-extension-messaging</a></li>
  </ul>
 </li>
 <li>Примеры использования <code>tabs.executeScript()</code>:
  <ul>
   <li><a class="external external-icon" href="https://github.com/mdn/webextensions-examples/tree/master/beastify">beastify</a></li>
   <li><a class="external external-icon" href="https://github.com/mdn/webextensions-examples/tree/master/context-menu-demo">context-menu-demo</a></li>
  </ul>
 </li>
</ul>