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
|
---
title: Usando módulos de código JavaScript
slug: JavaScript_code_modules/Using
tags:
- páginas_a_traducir
translation_of: Mozilla/JavaScript_code_modules/Using
---
<p>{{ Fx_minversion_header(3) }}</p>
<p>Los módulos de código JavaScript son un concepto introducido en Firefox 3 (Gecko 1.9) y pueden ser usados para compartir código entre alcances (scopes) con diferentes privilegios. Los módulos pueden también ser usados para crear instancias únicas (singletons) globales de JavaScript que previamente requerian usar objetos XPCOM de JavaScript. Un módulo de código JavaScript es simplemente una porción de código JavaScript situado en una ubicación registrada. El módulo es cargado dentro de un alcance (scope) de JavaScript específico, tal como un script de XUL o un script XPCOM de JavaScript, usando <a href="/es/Components.utils.import" title="es/Components.utils.import">Components.utils.import</a>.</p>
<h2 id="Creación_de_módulos_JavaScript">Creación de módulos JavaScript</h2>
<p>Los módulos JavaScript tienen dos secciones: 1. un array <code>EXPORTED_SYMBOLS</code> en el que se declaran como "símbolos" los objetos, propiedades y métodos que serán empleados por los scripts que los importen. Y, 2. El código, que trata las propiedades y métodos de los "símbolos" exportados. Un muy sencillo módulo de JavaScript luce como esto:</p>
<pre>var EXPORTED_SYMBOLS = ["foo", "bar"]
function foo() {
return "foo";
}
var bar = {
name : "bar",
size : "3"
};
var dummy = "dummy";
</pre>
<p>Nótese que el módulo usa JavaScript normal para crear funciones, objetos, constantes y cualquier otro tipo JavaScript. Sólo los elementos declarados en el Array especial <code>EXPORTED_SYMBOLS</code> serán accesibles desde el exterior del módulo; los demás quedan encapsulados y no son accesibles fuera del mismo. Cualquier elemento de JavaScript nombrado en <code>EXPORTED_SYMBOLS</code> será exportado desde el módulo e insertado dentro del alcance (scope) importador. Por ejemplo:</p>
<pre>Components.utils.import("resource://app/modules/my_module.jsm");
alert(foo()); // muestra "foo"
alert(bar.size + 3); // muestra "6"
alert(dummy); // muestra "dummy is not defined" porque 'dummy' no fue exportado desde el módulo.
</pre>
<h3 id="La_URL_de_un_módulo_JavaScript">La URL de un módulo JavaScript</h3>
<p>Como se puede apreciar en el ejemplo, arriba, hace falta un llamado empleando una dirección URL para poder importar los módulos JavaScript. Éstos, normalmente, se crean como archivos planos con extensión <strong>jsm</strong> y se almacenan el el directorio <code>/modules</code> del aplicativo (XUL) o extensión para el que son creados. Y, se cargan usando un protocolo <strong>"resource:"</strong> (en el ejemplo) al presentar la URL como parámetro del llamado.</p>
<p>Sólo se pueden emplear los protocolos <strong>"chrome:"</strong> ( <span style="background-color: #ffffe1; border: 1px solid #818151; font-size: x-small; padding: 0px 2px; white-space: nowrap;" title="(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)">Requiere Gecko 2</span>) <strong>"resource:"</strong> o <strong>"file:"</strong>para cargar módulos JavaScript.</p>
<ul>
<li>Si está escribiendo una extensión para Firefox 4.x y cuenta con un archivo de manifiesto "<a href="/es/Components.utils.import" title="es/Components.utils.import">chrome.manifest</a>" en el que se ha declarado la ubicación del directorio "content" (mediante una instrucción <code>content</code>, ver tutorial XUL) puede alojar allí sus módulos JavaScript y cargarlos mediante el protocolo "chrome:", así: <code>chrome://<yourextension>/content/<yourmodule>.jsm</code> .</li>
<li>Si su extensión o aplicación debe soportar Mozilla 1.9.x (Firefox 3.x) será necesario registrar su ubicación en el manifiesto chrome de la misma (<a href="/es/Components.utils.import" title="es/Components.utils.import">chrome.manifest</a>) más adelante se explica como hacerlo.</li>
</ul>
<h3 id="Compartiendo_objetos_mediante_módulos">Compartiendo objetos mediante módulos</h3>
<p>Un comportamiento extremadamente importante de <a href="/es/Components.utils.import" title="es/Components.utils.import">Components.utils.import</a> es que los módulos son cacheados cuando se cargan e importaciones posteriores no recargan una nueva versión del módulo, sino que usan la version cacheada anteriormente. Esto significa que un módulo dado será compartido cuando sea importado varias veces. Cualquier modificacion a datos, objetos o funciones estarán disponibles en cualquier alcance (scope) que haya importado el módulo. Por ejemplo, si el modulo de ejemplo fue importado en dos alcances (scopes) diferentes de JavaScript, los cambios en un alcance (Scope) serán visibles desde el otro alcance (scope).</p>
<p>Alcance (scope) 1:</p>
<pre>Components.utils.import("resource://app/modules/my_module.jsm");
alert(bar.size + 3); // muestra "6"
bar.size = 10;
</pre>
<p>Alcance (scope) 2:</p>
<pre>Components.utils.import("resource://app/modules/my_module.jsm");
alert(foo()); // muestra "foo"
alert(bar.size + 3); // muestra "13"
</pre>
<p>Este comportamiento de compartir puede ser usado para crear objetos singleton que compartan datos entre ventanas y entre scripts XUL y componentes XPCOM.</p>
<div class="note"><strong>Nota: </strong>Cada ámbito (alcance) al que sea importado un módulo recibe una copia por-valor de los símbolos exportados por el módulo. De modo que los cambios que allí se realicen para los mismos no se verán reflejados en otros lugares. (Ésto garantiza que los "nombres" de los símbolos exportados no cambien para otros sitios y se pueda hacer referencia los mismos de modo uniforme)</div>
<p>Alcance 1</p>
<pre><code class="plain"> Components.utils.import(</code><code class="string">"<a>resource://app/my_module.jsm</a>"</code><code class="plain">);</code>
<code class="plain">bar = </code><code class="string">"foo"</code><code class="plain">;</code>
<code class="plain">alert(bar); </code><code class="comments">// muestra "foo"</code>
</pre>
<p>Alcance 2</p>
<pre><code class="plain">Components.utils.import(</code><code class="string">"<a>resource://app/my_module.jsm</a>"</code><code class="plain">);</code>
<code class="plain">alert(bar); </code><code class="comments">// muestra "[object Object]"</code></pre>
<h4 id="resource:_Protocol" name="resource:_Protocol">resource: Protocol</h4>
<p>Cuando uses <a href="/es/Components.utils.import" title="es/Components.utils.import">Components.utils.import</a>, notarás que los módulos de código son cargados usando el protocolo "resource://". La sintaxis básica de un recurso URL es como sigue:</p>
<pre class="eval">resource://<alias>/<ruta-relativa>/<archivo.js|jsm>
</pre>
<p>El <code><alias></code> es un alias a una ubicación, usualmente una hubicación física relativa a la aplicación o al runtime de XUL. Existen algunos alias predefinidos por defecto por el runtime de XUL runtime:</p>
<ul>
<li><code>app</code> - Alias a la ubicación de la aplicación de XUL.</li>
<li><code>gre</code> - Alias a la ubicación del runtime de XUL.</li>
</ul>
<p>La <code><ruta-relativa></code> puede tener múltiples niveles de profundidad y siempre es relativa a la ubicación definida por el <code><alias></code>. La ruta relativa común es "modules" y es usada por XUL Runner and Firefox. Los módulos de código son simples archivos JavaScript con la extensión .js o .jsm.</p>
<p>La manera mas sencilla para extensiones y aplicaciones XUL de agregar alias propios es al registrar un alias en el <a href="/es/Chrome_Registration" title="es/Chrome_Registration">manifiesto chrome</a> usando algo como esto:</p>
<pre class="eval">resource <em>nombrealias</em> <em>uri/a/los/archivos/</em>
</pre>
<p>Por ejemplo, si el XPI de tu extension <em>foo</em> incluye un directorio de primer nivel de módulos conteniendo el módulo <em>bar.js</em>, podrías crear un alias a ese directorio mediante la instrucción:</p>
<pre class="eval">resource foo modules/
</pre>
<p>Podrias entonces importar el módulo en tu código JavaScript mediante la sentencia:</p>
<pre class="eval">Components.utils.import("<a class="external" rel="freelink">resource://foo/bar.js</a>");
</pre>
<p>Los alias propios pueden también ser agregados programáticamente al protocolo de recursos. Por ejemplo:</p>
<pre>var ioService = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var resProt = ioService.getProtocolHandler("resource")
.QueryInterface(Components.interfaces.nsIResProtocolHandler);
var aliasFile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
aliasFile.initWithPath("/some/absolute/path");
var aliasURI = ioService.newFileURI(aliasFile);
resProt.setSubstitution("myalias", aliasURI);
// asumiendo que el módulo de código está en el directorio de alias misma, no en un subdirectorio
Components.utils.import("resource://myalias/file.jsm");
// ...
</pre>
|