aboutsummaryrefslogtreecommitdiff
path: root/files/es/mozilla/add-ons/webextensions/modify_a_web_page/index.html
blob: eb7493b62b35acc64278380adc269a8046e0081f (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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
---
title: Modify a web page
slug: Mozilla/Add-ons/WebExtensions/Modify_a_web_page
translation_of: Mozilla/Add-ons/WebExtensions/Modify_a_web_page
---
<div>{{AddonSidebar}}</div>

<div>Uno de los usos más comunes para las extensiones es modificar páginas web.  Por ejemplo, una extension puede querer cambiar el estilo de la página, esconder determinados nodos DOM o incluir otros nuevos.</div>

<div> </div>

<div>Existen dos maneras de hacer esto con extensiones Web y APIs:</div>

<div> </div>

<ul>
 <li><strong>Declarativamente</strong>: Define un patrón que encaja con un conjunto de URLs y carga un conjunto de scripts a las páginas cuyos URL encajen con ese patrón.</li>
 <li><strong>Programaticamente</strong>: Usando una Javascript API, carga una script en la página alojada en una lengüeta específica.</li>
</ul>

<p>De ambas formas, estos scripts se llaman scripts de contenido y son distintos del resto de scripts que constituyen una extensión. </p>

<ul>
 <li>Solamente tienen acceso a un grupo pequeño de extensiones web y APIs.</li>
 <li>Obtienen acceso directo a la página web en la que han sido cargadas.</li>
 <li>Se comunican con el resto de la extensión usando una API de mensajería.</li>
</ul>

<p>En este artículo hablaremos de los dos métodos para cargar una script..</p>

<h2 id="Modificando_páginas_que_encajen_con_un_patrón_URL">Modificando páginas que encajen con un patrón URL</h2>

<p>Para empezar, crea un nuevo directorio llamado "modify-page". En este directorio, crea un archivo llamado "manifest.json", con el siguiente contenido:</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>La llave <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts</a></code> es el método de carga de scripts a páginas cuya URL encaje con los patrones. En este caso, <code>content_scripts</code> le dice al navegador que cargue una script llamada "page-eater.js" en todas las páginas con <a href="https://developer.mozilla.org/">https://developer.mozilla.org/</a>.</p>

<div class="note">
<p>Debido a que el atributo <code>"js"</code> de <code>content_scripts</code> es una array, puedes usarla para inyectar más de una script a las páginas que encajen con el patrón. Si haces esto las páginas compartiran el mismo campo de aplicación, igual que múltiples scripts cargadas por una página, y son cargadas en el mismo orden en las que están dispuestas en la array.</p>
</div>

<div class="note">
<p>La llave <code>content_scripts</code> tambien tiene un atributo de <code>"css"</code> que puedes usar para inyectar código CSS. </p>
</div>

<p>Después, crea un archivo llamado "page-eater.js" dentro del directorio "modify-page" e introduce el contenido de a continuación:</p>

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

var header = document.createElement('h1');
header.textContent = "This page has been eaten";
document.body.appendChild(header);</pre>

<p> Ahora, <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox">instala la extensión</a> y visita <a href="https://developer.mozilla.org/">https://developer.mozilla.org/</a>:</p>

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

<div class="note">
<p>Ten en cuenta que aunque este video muestra el contenido de la script operando en <a href="https://addons.mozilla.org/en-US/firefox/">addons.mozilla.org</a>, las scripts de contenido están bloqueadas en esta página por el momento.</p>
</div>

<h2 id="Modificando_las_páginas_programaticamente">Modificando las páginas programaticamente</h2>

<p>Y si quieres comer páginas, pero solo cuando el usuario te lo pida?  Actualicemos este ejemplo para que podamos enyectar el contenido de la script cuando el usuario haga click en un item del menu de contexto.</p>

<p>Primero actualiza "manifest.json" para que incluya el contenido a continuación:</p>

<pre class="brush: json">{

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

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

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

}</pre>

<p>Aquí, hemos eliminado la llave <code>content_scripts</code>  y hemos añadido dos nuevas llaves:</p>

<ul>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions">permissions</a></code>: Para inyectar scripts a las páginas necesitamos los permisos para la página que estamos modificando. El permiso <a href="/en-US/Add-ons/WebExtensions/manifest.json/permissions#activeTab_permission"><code>activeTab</code> </a>es una manera de obtener el permiso temporalmente para la lengüeta que esté actualmente abierta. También necesitamos el permiso <code>contextMenus</code> para poder añadir items al menu de contexto.</li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/background">background</a></code>: Usamos esto para cargar un <a href="/en-US/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#Background_scripts">"background script"</a> persistente llamado "background.js", en el cual montamos el menu de contexto e inyectamos el script de contenido.</li>
</ul>

<p>Ahora generaremos este archivo. Crea un archivo llamado "background.js" en el directorio "modify-page" e introduce el siguiente contenido: </p>

<pre class="brush: js">browser.contextMenus.create({
  id: "eat-page",
  title: "Eat this page"
});

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

<p>En esta script estamos creando un <a href="/en-US/Add-ons/WebExtensions/API/ContextMenus/create">item del menu de contexto</a>  y dándole una ID y un título específico (el texto que se estará expuesto en el menu de contexto). Después configuramos un evento de escucha para que cuando el usuario haga click en uno de los items del menu podamos comprobar si se trata de nuestro item <code>eat-page</code> . En caso afirmativo, inyectaremos "page-eater.js" a la lengüeta actual usando la API <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript">tabs.executeScript()</a></code>. Alternativamente, esta API puede tomar como argumento una ID. En este caso la hemos omitido lo cual quiere decir que la script es inyectada en la lengüeta que está actualmente abierta.</p>

<p>Ahora mismo la extensión debería ser algo como esto:</p>

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

<p>Ahora <a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox#Reloading_a_temporary_add-on">recarga la extensión</a>, abre la página (cualquier página en esta ocasión), activa el menu de contexto y selecciona "Eat this page" (Comer esta página):</p>

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

<div class="note">
<p>Ten en cuenta que aunque este video muestra el contenido de la script operando en <a href="https://addons.mozilla.org/en-US/firefox/">addons.mozilla.org</a>, las scripts de contenido están bloqueadas en esta página por el momento.</p>
</div>

<h2 id="Mensajería">Mensajería</h2>

<p>Scripts de contenido y scripts de fondo no pueden acceder directamente al estado del otro. Sin embargo, pueden comunicarse mediante el uso de mensajes. Una terminal configura un escuchador de mensajes y la otra terminal puede mandarle un mensaje. La siguente tabla resume las APIs involucradas en cada parte:</p>

<table class=" fullwidth-table standard-table">
 <thead>
  <tr>
   <th scope="row"> </th>
   <th scope="col">En el script de contenido</th>
   <th scope="col">En el script de fondo</th>
  </tr>
  <tr>
   <th scope="row">Mandar un mensaje</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">Recibir un mensaje</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>Actualicemos nuestro ejemplo para ilustrar como mandar un mensaje desde una script de fondo.</p>

<p>Primero, hemos de editar "background.js" para que tenga el siguiente contenido:</p>

<pre class="brush: js">browser.contextMenus.create({
  id: "eat-page",
  title: "Eat this page"
});

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

function onExecuted(result) {
    var querying = browser.tabs.query({
        active: true,
        currentWindow: true
    });
    querying.then(messageTab);
}

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

<p>Ahora, después de inyectar "page-eater.js", hemos de usar <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/query">tabs.query()</a></code>  para obtener la lengüeta actualmente activa y entonces usar <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage">tabs.sendMessage()</a></code> para mandar un mensaje a las scripts de contenido cargadas en la lengüeta. El mensaje tiene el contenido <code>{replacement: "Message from the extension!"}</code>.</p>

<p>Después, actualiza "page-eater.js" de esta forma:</p>

<pre class="brush: js">function eatPageReceiver(request, sender, sendResponse) {
  document.body.textContent = "";
  var header = document.createElement('h1');
  header.textContent = request.replacement;
  document.body.appendChild(header);
}
browser.runtime.onMessage.addListener(eatPageReceiver);
</pre>

<p>Ahora, en vez de simplemente comer la página, el contenido espera a un mensaje usando <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage">runtime.onMessage</a></code>.  Cuando el mensaje llega, el script de contenido ejecuta el mismo código de antes, exceptuando que el  texto de reemplazo se obtenido de <code>request.replacement</code>.</p>

<p>Debido a que <code><a href="/en-US/Add-ons/WebExtensions/API/tabs/executeScript">tabs.executeScript()</a></code> es una función asincrónica y para asegurarnos de que mandamos el mensaje solo cuando el escuchador ha sido añadido en "page-eater.js", usamos <code>onExecuted</code> que sera llamado después de que "page-eater.js" se ejecute.</p>

<div class="note">
<p>Pulsa Ctrl+Shift+J (o Cmd+Shift+J en el Mac)  o <code>web-ext run --bc</code> para abrir la consola de navegación para ver <code>console.log</code> en la script de fondo. Alternativamente puedes usar el <a href="/en-US/Add-ons/Add-on_Debugger">Add-on Debugger</a>, el cual te permite poner un breakpoint.  De momento no hay forma de iniciar un <a href="https://github.com/mozilla/web-ext/issues/759">Add-on Debugger directamente de una extensión web</a>.</p>
</div>

<p>Si queremos enviar mensajes directamente desde el contenido script de vuelta a la página de fondo, podríamos usar<code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage">runtime.sendMessage()</a></code> en vez de  <code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage">tabs.sendMessage()</a></code>. Por ejemplo:</p>

<pre class="brush: js">browser.runtime.sendMessage({
    title: "from page-eater.js"
});</pre>

<div class="note">
<p>Todos estos ejemplos inyectan Javascript; también puedes inyectar CSS programaticamente usando la función<code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/insertCSS">tabs.insertCSS()</a></code>.</p>
</div>

<h2 id="Aprende_más">Aprende más</h2>

<ul>
 <li>La guía de <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts">scripts de contenido</a></li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_scripts">content_scripts</a></code> llave de manifiesto</li>
 <li><code><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions">permissions</a></code> llave de manifiesto</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>Ejemplos con<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>Ejemplos con<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>

<p> </p>