diff options
Diffstat (limited to 'files/es/mozilla/tech')
30 files changed, 0 insertions, 5063 deletions
diff --git a/files/es/mozilla/tech/index.html b/files/es/mozilla/tech/index.html deleted file mode 100644 index f9682e62e1..0000000000 --- a/files/es/mozilla/tech/index.html +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Mozilla technologies -slug: Mozilla/Tech -tags: - - Landing - - Mozilla - - NeedsTranslation - - Reference - - TopicStub - - XUL -translation_of: Mozilla/Tech ---- -<p>Mozilla has several technologies used as components of its projects. These are documented here. (flesh out this text).</p> -<p>{{LandingPageListSubpages}}</p> diff --git a/files/es/mozilla/tech/toolkit_api/smile/index.html b/files/es/mozilla/tech/toolkit_api/smile/index.html deleted file mode 100644 index 20b37a8659..0000000000 --- a/files/es/mozilla/tech/toolkit_api/smile/index.html +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: SMILE -slug: Mozilla/Tech/Toolkit_API/SMILE -tags: - - Interfaces - - NeedsTranslation - - SMILE - - SeaMonkey - - TopicStub - - XPCOM - - XPCOM API Reference -translation_of: Mozilla/Tech/Toolkit_API/SMILE ---- -<p> </p> - -<div class="overheadIndicator smMinVerHeader standardNote"> -<p>This article covers features introduced in <a class="new" href="https://developer.mozilla.org/en-US/docs/SeaMonkey_2_for_developers" rel="nofollow">SeaMonkey 2</a></p> -</div> - -<p> </p> - -<p>SMILE is a JavaScript library designed to help developers build extensions using terminology and interfaces that are familiar to them.</p> - -<p>SMILE is about making it easier for extension developers to be productive, by minimizing some of the XPCOM formality and adding some "modern" JavaScript ideas. We want to start with areas that will provide the most benefit.</p> - -<p>SMILE has a <code><span class="lang lang-en"><a class="external" href="http://mxr.mozilla.org/comm-central/source/suite/smile/public/smileIApplication.idl" rel="external nofollow" title="http://mxr.mozilla.org/comm-central/source/suite/smile/public/smileIApplication.idl">smileIApplication</a> </span></code> interface that implements all the functions of <code><span class="lang lang-en"><a class="external" href="http://mxr.mozilla.org/comm-central/source/mozilla/toolkit/components/exthelper/extIApplication.idl" rel="external nofollow" title="http://mxr.mozilla.org/comm-central/source/mozilla/toolkit/components/exthelper/extIApplication.idl">extIApplication</a></span></code>. The library has also been implemented in Firefox ("<a class="internal" href="/en/Toolkit_API/FUEL" title="en/FUEL">FUEL</a>") and in Thunderbird ("<a class="internal" href="/en/Toolkit_API/STEEL" title="en/Thunderbird/STEEL">STEEL</a>").</p> - -<h3 id="Objects" name="Objects">Objects</h3> - -<h4 id="extIApplication_Objects">extIApplication Objects</h4> - -<ul> - <li><a href="/en/Toolkit_API/extIConsole" title="en/FUEL/Console">extIConsole</a></li> - <li><a href="/en/Toolkit_API/extIEventItem" title="en/FUEL/EventItem">extIEventItem</a></li> - <li><a href="/en/Toolkit_API/extIEventListener" title="en/FUEL/EventListener">extIEventListener</a></li> - <li><a href="/en/Toolkit_API/extIEvents" title="en/FUEL/Events">extIEvents</a></li> - <li><a href="/en/Toolkit_API/extIExtension" title="en/FUEL/Extension">extIExtension</a></li> - <li><a href="/en/Toolkit_API/extIExtensions" title="en/FUEL/Extensions">extIExtensions</a></li> - <li><a href="/en/Toolkit_API/extIPreference" title="en/FUEL/Preference">extIPreference</a></li> - <li><a href="/en/Toolkit_API/extIPreferenceBranch" title="en/FUEL/PreferenceBranch">extIPreferenceBranch</a></li> - <li><a href="/en/Toolkit_API/extISessionStorage" title="en/FUEL/SessionStorage">extISessionStorage</a></li> -</ul> - -<h4 id="smileIApplication_Objects">smileIApplication Objects</h4> - -<ul> - <li><a class="internal" href="/en/Toolkit_API/SMILE/smileIBookmarkRoots" title="en/Toolkit API/SMILE/smileIBookmarkRoots">smileIBookmarkRoots</a></li> - <li><a class="internal" href="/en/Toolkit_API/SMILE/smileIWindow" title="en/Toolkit API/SMILE/smileIWindow">smileIWindow</a></li> - <li><a class="internal" href="/en/Toolkit_API/SMILE/smileIBrowserTab" title="en/Toolkit API/SMILE/smileIBrowserTab">smileIBrowserTab</a></li> - <li><a class="internal" href="/en/Toolkit_API/SMILE/smileIApplication" title="en/Toolkit API/SMILE/smileIApplication">smileIApplication</a></li> -</ul> - -<h3 id="XPCOM" name="XPCOM">XPCOM</h3> - -<p>Although the <a class="internal" href="/en/Toolkit_API/extIApplication" title="en/Toolkit API/extIApplication">extIApplication</a> object is preloaded into XUL scripts, it is not preloaded into JavaScript XPCOM code. The object needs to be accessed like any other XPCOM service:</p> - -<pre>var Application = Components.classes["@mozilla.org/smile/application;1"].getService(Components.interfaces.smileIApplication); -</pre> diff --git a/files/es/mozilla/tech/xpcom/guide/index.html b/files/es/mozilla/tech/xpcom/guide/index.html deleted file mode 100644 index 7afb1c9cd1..0000000000 --- a/files/es/mozilla/tech/xpcom/guide/index.html +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: XPCOM guide -slug: Mozilla/Tech/XPCOM/Guide -tags: - - Landing - - Mozilla - - NeedsTranslation - - TopicStub - - XPCOM -translation_of: Mozilla/Tech/XPCOM/Guide ---- -<p><span class="seoSummary">These articles provide tutorials and usage documentation for XPCOM, including how to use it in your own projects and how to build XPCOM components for your Firefox add-ons and the like.</span></p> -<p></p><div class="row topicpage-table"> - <div class="section"><dl><dl><dt class="landingPageList"><a href="/es/docs/C%C3%B3mo_crear_un_componente_XPCOM_en_JavaScript">Cómo crear un componente XPCOM en JavaScript</a></dt><dd class="landingPageList"></dd></dl></dl></div> - <div class="section"><dl><dt class="landingPageList"><a href="/es/docs/Creaci%C3%B3n_de_Componentes_XPCOM">Creación de Componentes XPCOM</a></dt><dd class="landingPageList"></dd></dl></div> - </div><p></p> diff --git a/files/es/mozilla/tech/xpcom/language_bindings/index.html b/files/es/mozilla/tech/xpcom/language_bindings/index.html deleted file mode 100644 index 727c397d50..0000000000 --- a/files/es/mozilla/tech/xpcom/language_bindings/index.html +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: Language bindings -slug: Mozilla/Tech/XPCOM/Language_Bindings -tags: - - Embedding - - Landing - - Mozilla - - NeedsTranslation - - TopicStub - - XPCOM - - 'XPCOM:Language Bindings' -translation_of: Mozilla/Tech/XPCOM/Language_Bindings ---- -<p>An <strong>XPCOM Language Binding</strong> is a bridge between a particular language and <a href="/en/XPCOM" title="en/XPCOM">XPCOM</a> to provide access to XPCOM objects from that language, and to let modules written in that language be used as XPCOM objects by all other languages for which there are XPCOM bindings.</p> -<p>More specifically, an XPCOM language binding:</p> -<ul> - <li>Enables <em>access to XPCOM objects from that language</em> (where access means reading/writing/creating XPCOM objects as well as calling methods on them).</li> - <li>Exposes <em>modules written in the bound language as XPCOM objects</em>, thereby enabling all other languages for which XPCOM bindings exist to access these modules.</li> -</ul> -<p>Since the XPCOM layer itself is written in C/C++, its API can be accessed out-of-the-box using C or C++. In order to allow any other language to use the XPCOM API, a bridging layer is required.</p> -<p>The following bridging layers are currently available:</p> -<p></p><div class="row topicpage-table"> - <div class="section"><dl><dl><dt></dt></dl></dl></div> - <div class="section"><dl><dt class="landingPageList"><a href="/es/docs/Components.utils.import">Components.utils.import</a></dt><dd class="landingPageList">Este método fue introducido en <a href="es/Firefox_3_para_desarrolladores">Firefox 3</a> y es usado para compartir código entre diferentes alcances(scopes) de forma sencilla. Por ejemplo, puedes importar <a href="es/XPCOMUtils.jsm">XPCOMUtils.jsm</a> para evitar copiar y pegar grandes porciones comunes de código de registración de componentes XPCOM en tus archivos de compomentes.</dd></dl></div> - </div><p></p> diff --git a/files/es/mozilla/tech/xpcom/reference/index.html b/files/es/mozilla/tech/xpcom/reference/index.html deleted file mode 100644 index 9fcb623f1b..0000000000 --- a/files/es/mozilla/tech/xpcom/reference/index.html +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: XPCOM reference -slug: Mozilla/Tech/XPCOM/Reference -tags: - - Add-ons - - Extensions - - Landing - - Mozilla - - NeedsTranslation - - Reference - - TopicStub - - XPCOM -translation_of: Mozilla/Tech/XPCOM/Reference ---- -<p>This reference describes the interfaces and functions provided by the <a href="/en-US/docs/Mozilla/Tech/XPCOM">XPCOM</a> library. In addition, it details the various helper classes and functions, as well as the components, provided by the <a href="/en-US/docs/Mozilla/Tech/XPCOM/Glue">XPCOM glue</a> library. The contents herein are oriented primarily toward extension developers and people embedding XPCOM in other projects.</p> - -<div class="warning"> -<p><strong>WebExtensions are becoming the new standard for creating add-ons. </strong>Eventually support for XPCOM add-ons will be deprecated, so you should begin to investigate porting your add-ons to use the <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions">WebExtensions</a> API, and <a href="https://mzl.la/webext-feature-needed">report any missing functionality</a> so we can be sure to address your concerns. Work is ongoing on WebExtension capabilities, so your input will help prioritize and plan the work. To learn more about the kinds of changes that will be needed, see <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Comparison_with_XUL_XPCOM_extensions">Comparison with XUL/XPCOM extensions</a>. In addition, any binaries you use will then need to be converted for use with the WebExtensions <a href="/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging">native messaging</a> API, or compiled using <a href="https://webassembly.github.io/">WebAssembly</a> or <a href="/en-US/docs/Mozilla/Projects/Emscripten">Emscripten</a>.</p> -</div> - -<div class="note"> -<p>If you're working on a module in the Mozilla codebase that's compiled with the <code>MOZILLA_INTERNAL_API</code> flag set, some of these APIs -- the string functions and classes in particular -- are not the ones you should be using. See the <a href="/en-US/docs/Mozilla/Tech/XPCOM/Guide/Internal_strings">XPCOM internal string guide</a> for documentation of the internal string API used within the Mozilla codebase.</p> -</div> - -<p></p><div class="row topicpage-table"> - <div class="section"><dl><dl><dt></dt></dl></dl></div> - <div class="section"><dl><dt class="landingPageList"><a href="/es/docs/XPCOM_Interface_Reference">XPCOM Interface Reference</a></dt><dd class="landingPageList">This is a reference to the XPCOM interfaces provided by the Mozilla platform.</dd></dl></div> - </div><p></p> - -<p>Many XPCOM pages return an <code><a href="/en-US/docs/Mozilla/Tech/XPCOM/Reference/Core_functions/nsresult">nsresult</a></code>. Prior to Gecko 19 (Firefox 19 / Thunderbird 19 / SeaMonkey 2.16), this was an integer that simply returned an error code. It is now a strongly typed <code>enum</code> when XPCOM is built using a C++11 compiler. This causes compile-time errors to occur when improper values are returned as nsresult values, thereby making it easier to catch many bugs.</p> diff --git a/files/es/mozilla/tech/xpidl/index.html b/files/es/mozilla/tech/xpidl/index.html deleted file mode 100644 index c091484d6f..0000000000 --- a/files/es/mozilla/tech/xpidl/index.html +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: XPIDL -slug: Mozilla/Tech/XPIDL -tags: - - Todas_las_Categorías - - XPCOM - - xpidl -translation_of: Mozilla/Tech/XPIDL ---- -<p> -</p><p><b>XPIDL</b> es un lenguaje de descripción de interface usado para especificar clases en la interface <a href="es/XPCOM">XPCOM</a>. -</p><p>Los lenguajes de descripción de interface (IDL, por Interface Description Languages) son usados para describir interfaces independientemente del lenguaje y de la máquina. Los IDLs permiten definir interfaces que pueden luego ser procesadas por herramientas para autogenerar especificaciones de interface dependientes del lenguaje. -</p><p>Una de estas herramientas es <a href="es/XPIDL/xpidl">xpidl</a>, que es usada para generar archivos de encabezado para C++ (.h), información 'typelib', y mucho más. -</p> -<h2 id="Escribiendo_archivos_de_interfaz_XPIDL">Escribiendo archivos de interfaz XPIDL</h2> -<p>XPIDL se asemeja bastante a <a class="external" href="http://www.omg.org/gettingstarted/omg_idl.htm">OMG IDL</a>, con sintaxis extendida para manejar IIDs y tipos adicionales. Hay algunos ejemplos en la <a class="external" href="http://lxr.mozilla.org/mozilla/source/xpcom/base">xpcom/base</a> y en los directorios <a class="external" href="http://lxr.mozilla.org/mozilla/source/xpcom/ds">xpcom/ds</a> del árbol Mozilla. -</p> -<ul><li> <a class="external" href="http://www.mozilla.org/scriptable/xpidl/syntax.html">XPIDL syntax</a> (Desactualizado) -</li><li> <a href="es/XPIDL/Sintaxis">XPIDL:Sintaxis</a> (XPIDL <a class="external" href="http://en.wikipedia.org/wiki/Extended_Backus-Naur_form">EBNF</a>) -</li><li> <a class="external" href="http://www.mozilla.org/scriptable/xpidl/idl-authors-guide/index.html">XPIDL Author's Guide</a> (Actualizado en su mayoría) -</li></ul> -<h2 id="Recursos">Recursos</h2> -<ul><li> <a class="external" href="http://www.mozilla.org/scriptable/xpidl/notes/">Algunas notas en desórden</a>, que incluyen una <a class="external" href="http://www.mozilla.org/scriptable/xpidl/notes/keywords.txt">lista de palabras clave (keywords)</a> -</li><li> <a href="es/XPIDL/xpidl">xpidl</a> es una herramienta para generar encabezados de C++, interfaces de Java, typelibs <a href="es/XPConnect">XPConnect</a>, y documentación HTML desde los archivos XPIDL -</li></ul> -{{ languages( { "fr": "fr/XPIDL", "ja": "ja/XPIDL", "en": "en/XPIDL" } ) }} diff --git a/files/es/mozilla/tech/xul/escuela_xul/agregar_barras_de_herramientas_y_botones_para_éstas/index.html b/files/es/mozilla/tech/xul/escuela_xul/agregar_barras_de_herramientas_y_botones_para_éstas/index.html deleted file mode 100644 index efb5adcff9..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/agregar_barras_de_herramientas_y_botones_para_éstas/index.html +++ /dev/null @@ -1,291 +0,0 @@ ---- -title: Agregar barras de herramientas y botones para éstas -slug: >- - Mozilla/Tech/XUL/Escuela_XUL/Agregar_barras_de_herramientas_y_botones_para_éstas -translation_of: >- - Archive/Add-ons/Overlay_Extensions/XUL_School/Adding_Toolbars_and_Toolbar_Buttons ---- -<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>{{ PreviousNext("Escuela_XUL/Agregar_menus_y_submenus", "Escuela_XUL/Agregar_eventos_y_comandos") }}</p> - -<h2 id="Adding_a_new_toolbar">Adding a new toolbar</h2> - -<p>Adding new toolbars to Firefox is easy, but adding them the wrong way is very easy as well.</p> - -<p>Toolbars in Firefox are very customizable. Some users don't like extra toolbars, or they want to rearrange toolbar buttons to their liking, possibly merging multiple toolbars in the process. Firefox allows all of this by default, and if you don't pay attention to the details we describe here, your toolbar may not be as easy to customize as the rest.</p> - -<p>The first thing you need to do is add your buttons to the toolbar palette. The <a href="/en/XUL/toolbarpalette" title="en/XUL/toolbarpalette">toolbarpalette</a> is a collection of all toolbar buttons and toolbar items in Firefox, including those added by extensions. To add your buttons, all you need to do is overlay the palette in your main browser overlay.</p> - -<pre><overlay id="xulschoolhello-browser-overlay" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - <toolbarpalette id="BrowserToolbarPalette"> - <toolbarbutton id="xulschoolhello-hello-world-button" - class="toolbarbutton-1 chromeclass-toolbar-additional" - label="&xulschoolhello.helloWorld.label;" - tooltiptext="&xulschoolhello.helloWorld.tooltip;" - oncommand="XULSchoolChrome.BrowserOverlay.doSomething(event);" /> - <!-- More buttons here. --> - </toolbarpalette> - <!-- More overlay stuff. --> -</overlay> -</pre> - -<p>One detail that is easy to overlook is the fact that the <em>toolbarpalette</em> element is outside of the <em>window</em> element. If you put the <em>toolbarpalette</em> element inside the <em>window</em> element in your overlay, some weird errors will begin to happen.</p> - -<div class="note"> -<p>Always set the <em>label</em> and <em>tooltiptext</em> attributes of a <a href="/en/XUL/toolbarbutton" title="en/XUL/toolbarbutton">toolbarbutton</a>. In the case of a <a href="/en/XUL/toolbaritem" title="en/XUL/toolbaritem">toolbaritem</a> element (discussed later), use the <em>title</em> attribute instead of <em>label</em>. Tooltips are very important for users that want to know what a button does before clicking it.</p> -</div> - -<p>Setting the image for a toolbar button is done with CSS:</p> - -<pre>#xulschoolhello-hello-world-button { - list-style-image: url("chrome://xulschoolhello/skin/hellow-world.png"); -} -</pre> - -<p>It's not really that simple to set the image for a toolbar button, because we need to consider the appearance of the button on different systems, and also consider the different button states, but we'll get into that further ahead.</p> - -<p>The CSS file with your toolbar styles needs to be included in the overlay file, as you would expect, but also in the chrome.manifest file. This is very important because the toolbar customization dialog won't work correctly without this. The way to include the file in the manifest is to add this line:</p> - -<pre>style chrome://global/content/customizeToolbar.xul chrome://xulschoolhello/skin/toolbar.css -</pre> - -<p>If you are using XBL bindings (explained way ahead) for your toolbar items, you'll have to include the CSS files for those as well, each in a new line like the one above.</p> - -<p>We now have code that adds one or more buttons to the toolbar palette. The user can now use the Customize Dialog to add the buttons to the current Firefox toolbars. In most cases this is not what you want as default behavior, because it would be very hard for the user to discover your buttons. Keep in mind most users don't know how to customize toolbars in Firefox.</p> - -<p>Let's add our own <a href="/en/XUL/toolbar" title="en/XUL/toolbar">toolbar</a>. This is done in the overlay as well.</p> - -<pre><window id="main-window"> - <toolbox id="navigator-toolbox"> - <toolbar id="xulschoolhello-toolbar" toolbarname="&xulschoolhello.toolbarName.label;" - accesskey="&xulschoolhello.toolbar.accesskey;" - customizable="true" mode="icons" context="toolbar-context-menu" - defaultset="xulschoolhello-hello-world-button" - insertbefore="PersonalToolbar" /> - </toolbox> -</window> -</pre> - -<p>Our toolbar is added as a child of the <a href="/en/XUL/toolbox" title="en/XUL/toolbox">toolbox</a> element in the main browser window. The toolbox is the collection of toolbars in Firefox, including the main menu bar. Let's look at the attributes we used:</p> - -<ul> - <li>The <em>toolbarname</em> is the name that will appear on the View > Toolbars menulist. This menu allows hiding and showing any toolbar.</li> - <li>The <em>customizable</em> attribute determines if the user can customize the toolbar. You should normally set this to <em>true</em>, unless you have strong reasons not to want users changing your toolbar.</li> - <li>The <em>mode</em> attribute is set to <em>icons</em>, which is the usual value. This can be changed in the Customize dialog by the user.</li> - <li>The <em>context</em> attribute should also be set if you want a customizable toolbar. It points to the id of a popup element that holds the customization options that are displayed when the user right-clicks on the toolbar. This popup is already part of the main window, so it doesn't need to be implemented again.</li> - <li>The <em>defaultset</em> attribute lists the ids of the icons youwant to include on your toolbar by default. It's a comma-separated list of ids, and it can also include other special values: <em>spacer</em>, <em>separator</em> and <em>spring</em>. <em>spacer</em> represents an empty button space, <em>separator</em> a vertical separation line and <em>spring</em> a flexible empty area that stretches.</li> - <li>Finally, the <em>insertbefore</em> attribute places our toolbar above the Bookmarks Toolbar. This is a matter of personal preference, but the Mac OS theme seems to be designed so that the Bookmarks Toolbar is always the last one (it has a lighter color than the rest). It also makes sense from a usability perspective, since bookmarks should be very easy to access for the user.</li> -</ul> - -<p>That's it for the basics. With this knowledge you should be able to create simple toolbars and toolbar buttons you can add to Firefox. Now we'll look deeper into the details of toolbars so that you can make <strong>great</strong> toolbars.</p> - -<h2 id="Toolbar_buttons">Toolbar buttons</h2> - -<p>There are several types of buttons and elements you can add to a toolbar depending on your needs. The <a href="/en/XUL/toolbarbutton" title="en/XUL/toolbarbutton">toolbarbutton</a> element has the <em>type</em> attribute that allows you to change the behavior of the button in many ways. The <em>menu</em> and <em>menu-button</em> types allow you to create buttons that open popup menus beneath them. See the Back/Forward buttons in the main Firefox toolbar for an example. Menu toolbar buttons are handy when you want to include many options in your toolbar and you don't want it to be too cluttered. The other types, <em>checkbox</em> and <em>radio</em> are useful when you have buttons that change state when the user clicks on them. Read more about this in the <a href="/en/XUL/Attribute/toolbarbutton.type" title="en/XUL/Attribute/toolbarbutton.type">type attribute</a> specification.</p> - -<div class="note"> -<p>Keep in mind some users have small screens with low resolution. If you shrink the Firefox window, you'll notice that the content resizes until it reaches its minimum size and begin to be cropped (cut), making UI elements disappear. You should test that your toolbar resizes gracefully and doesn't force Firefox to crop content before it's strictly necessary.</p> -</div> - -<p>When you need something more elaborate than a button in your toolbar, you can use the <a href="/en/XUL/toolbaritem" title="en/XUL/toolbaritem">toolbaritem</a> element instead. This element is nothing more than a wrapper, so you can have whatever XUL content you want in it. However, you should keep in mind that odd-looking toolbars are likely to confuse and annoy users. Use custom toolbar items sparingly.</p> - -<h3 id="Toolbar_button_icons">Toolbar button icons</h3> - -<p>Making the icons and CSS rules for toolbar buttons is one of the most difficult tasks when making extensions. It is not too hard to come up with some graphics for the buttons, but it can be hard to make them blend in with Firefox on all operating systems. These are the icon sets for Firefox 3.0 on Windows XP, Windows Vista, Mac OS X and Linux:</p> - -<p><strong>Windows XP</strong><strong> and older</strong></p> - -<p><img alt="Toolbar-win.png" class="default internal" src="/@api/deki/files/4132/=Toolbar-win.png"></p> - -<p><strong>Windows Vista and 7 (Aero)</strong></p> - -<p><img alt="Toolbar-aero.png" class="default internal" src="/@api/deki/files/4133/=Toolbar-aero.png"></p> - -<p><strong>Mac OS X</strong></p> - -<p><img alt="Toolbar-mac.png" class="default internal" src="/@api/deki/files/4134/=Toolbar-mac.png"></p> - -<p><strong>Linux (Gnome)</strong></p> - -<p><img alt="" class="internal" src="../../../../@api/deki/files/4135/=Toolbar-gnome.png" style="height: 48px; width: 120px;"></p> - -<div class="note"> -<p>Note: the images above are probably not distributable under the same CC license, unlike the rest of this material.</p> -</div> - -<p>There are lots of differences there, right? Let's look at the most important ones:</p> - -<ul> - <li>On Windows, all icons except for the back / forward buttons are 24x24 pixels. The icons are colorful and detailed. On Windows Vista and Windows 7, the icons look shinier, and the predominant color is blue, while on XP the predominant color is green. Most Windows icons have 4 different states, from top to bottom: default, hover, disabled and active. The hover state is set when the mouse pointer is on top of the button and the button is not disabled. The active state is set when the user is clicking on the button. It is usually seen for only an instant, but you can you click and hold on the button to see the active state more clearly. You can't really tell on the white background of this page, but the disabled graphics are semi-transparent. This allows them to blend with whatever color the toolbar background is.</li> - <li>On Mac OS X, all icons except for the back / forward buttons are 36x23 pixels. They're all a mixture of grey tones, with very simple graphics in the center. Most only have 3 states: default, disabled and active. Transparency is not used.</li> - <li>On Linux, all icons are 24x24 pixels. Since Firefox is a <a class="external" href="http://www.gtk.org/" title="http://www.gtk.org/">GTK</a> application, it uses <a class="external" href="http://library.gnome.org/devel/gtk/stable/gtk-Stock-Items.html" title="http://library.gnome.org/devel/gtk/stable/gtk-Stock-Items.html">GTK icons</a> whenever possible. The icons in the image are the ones that aren't provided by GTK. GTK icons are accessed using special URLs, like this one: <a class="external" rel="freelink">moz-icon://stock/gtk-go-back?size=menu</a>. You can enter this URL in Firefox on Linux, and the corresponding icon will be displayed. The icons have the default and disabled states, and just like on Windows the disabled state is defined using transparency.</li> -</ul> - -<p>Now let's look at the CSS work involved in a toolbar that works on the 4 aforementioned systems. If you want your toolbar to look right on all systems, you should consider having different icon sets for each. You should also consider using a graphic designer for this work, as it takes a lot of attention to detail to make good icons.</p> - -<p>You can have a different skin directory for each operating system using Manifest Flags in the chrome.manifest file:</p> - -<pre>skin xulschoolhello classic/1.0 jar:chrome/xulschoolhello.jar!/skin/unix/ -skin xulschoolhello classic/1.0 jar:chrome/xulschoolhello.jar!/skin/win/ os=WINNT -skin xulschoolhello classic/1.0 jar:chrome/xulschoolhello.jar!/skin/winaero/ os=WINNT osversion>=6 -skin xulschoolhello classic/1.0 jar:chrome/xulschoolhello.jar!/skin/mac/ os=Darwin -</pre> - -<p>There is a separate skin directory for each system, with the Unix theme as the default (as most other systems are Unix-based). This makes it easy to keep the themes separate and to make changes to one of them without having to worry about the rest. On the other hand, it is often the case that there are multiple images and CSS sheets that are the same for all systems. For example, your extension logo icon will probably be the same. Having 4 copies of these files can be wasteful, so you may want to have a "common" directory.</p> - -<div class="note"> -<p>Image files use the most space in an extension package, by far. Most extensions are a few hundred kilobytes in size or smaller. If your extension is getting too big, you should look into reducing image size.</p> -</div> - -<p>Given the way manifest files work, we have found that the best solution is to have a separate package name for OS-specific skin files.</p> - -<pre>skin xulschoolhello classic/1.0 jar:chrome/xulschoolhello.jar!/skin/all/ -skin xulschoolhello-os classic/1.0 jar:chrome/xulschoolhello.jar!/skin/unix/ -skin xulschoolhello-os classic/1.0 jar:chrome/xulschoolhello.jar!/skin/win/ os=WINNT -skin xulschoolhello-os classic/1.0 jar:chrome/xulschoolhello.jar!/skin/winaero/ os=WINNT osversion>=6 -skin xulschoolhello-os classic/1.0 jar:chrome/xulschoolhello.jar!/skin/mac/ os=Darwin -</pre> - -<p>All we did here is add a new entry for "common" styles that points to the <em>all</em> directory. The OS-specific entries now use a different package name: <em>xulschoolhello-os</em>. Now you just need to be careful about when to use <em><a class="external" rel="freelink">chrome://xulschoolhello/skin/</a></em> and when to use <em><a class="external" rel="freelink">chrome://xulschoolhello-os/skin/</a></em>. It's a bit hacky, but it works well.</p> - -<p>As for the image files themselves, you may be wondering why it is that all icons are included in a single file instead of having one file for every state of every icon. One reason is that it would be complicated to manage that many files, and it becomes more likely that changes made to some of the files lead to an inconsistent appearance that is not obvious by looking at the individual files. It is easier to be able to edit all icons in one go. There is also a performance gain from using a single file. To get the region that corresponds to a specific state of an icon, the <a href="/en/CSS/-moz-image-region" title="en/CSS/-moz-image-region">-moz-image-region</a> CSS property is used.</p> - -<p>Here are some examples of how the CSS for a <em>toolbarbutton</em> would look like on the 3 major platforms. This assumes that you've set the class<em> xs-hw-toolbarbutton</em> to all of your buttons.</p> - -<p>Windows:</p> - -<pre>/* The second and third selectors at the bottom are necessary to prevent - conflicts with installed themes. */ -toolbarbutton.xulschoolhello-toolbarbutton, -window:not([active="true"]) toolbarbutton.xulschoolhello-toolbarbutton, -toolbar[iconsize="small"] toolbarbutton.xulschoolhello-toolbarbutton { - list-style-image: url("chrome://xulschoolhello-os/skin/toolbar.png"); -} - -#xulschoolhello-hello-world-button { - -moz-image-region: rect(0px, 24px, 24px, 0px); -} - -#xulschoolhello-hello-world-button:not([disabled="true"]):hover { - -moz-image-region: rect(24px, 24px, 48px, 0px); -} - -#xulschoolhello-hello-world-button[disabled="true"] { - -moz-image-region: rect(48px, 24px, 72px, 0px); -} - -#xulschoolhello-hello-world-button:not([disabled="true"]):hover:active { - -moz-image-region: rect(72px, 24px, 96px, 0px); -} -</pre> - -<p>Mac OS X:</p> - -<pre>/* The second and third selectors at the bottom are necessary to prevent - conflicts with installed themes. */ -toolbarbutton.xulschoolhello-toolbarbutton, -window:not([active="true"]) toolbarbutton.xulschoolhello-toolbarbutton, -toolbar[iconsize="small"] toolbarbutton.xulschoolhello-toolbarbutton { - list-style-image: url("chrome://xulschoolhello-os/skin/toolbar.png"); -} - -#xulschoolhello-hello-world-button { - -moz-image-region: rect(0px, 36px, 23px, 0px); -} - -#xulschoolhello-hello-world-button[disabled="true"] { - -moz-image-region: rect(23px, 36px, 46px, 0px); -} - -#xulschoolhello-hello-world-button:not([disabled="true"]):hover:active { - -moz-image-region: rect(46px, 36px, 69px, 0px); -} -</pre> - -<p>Linux:</p> - -<pre>/* The second and third selectors at the bottom are necessary to prevent - conflicts with installed themes. */ -toolbarbutton.xulschoolhello-toolbarbutton, -window:not([active="true"]) toolbarbutton.xulschoolhello-toolbarbutton, -toolbar[iconsize="small"] toolbarbutton.xulschoolhello-toolbarbutton { - list-style-image: url("chrome://xulschoolhello-os/skin/toolbar.png"); -} - -#xulschoolhello-hello-world-button { - -moz-image-region: rect(0px, 24px, 24px, 0px); - /* Or: list-style-image: url("moz-icon://stock/gtk-some-icon?size=menu"); */ -} - -#xulschoolhello-hello-world-button[disabled="true"] { - -moz-image-region: rect(24px, 24px, 48px, 0px); -} -</pre> - -<p>The Windows and Linux themes have several CSS rules that apply by default to all toolbar buttons. These add the button-like look you want. If for some reason you want to override these styles (and we don't recommend doing it), you'll need the following rule:</p> - -<pre>-moz-appearance: none; -</pre> - -<p><a href="/en/CSS/-moz-appearance" title="en/CSS/-moz-appearance">-moz-appearance</a> can be used in many cases where you want to strip the native look out of an element. This will save you a lot of time trying to remove all the CSS rules that give the buttons a native look. You'll probably still need to override a couple other CSS rules to get a completely plain look.</p> - -<h2 id="The_Customize_Toolbars_Dialog">The Customize Toolbars Dialog</h2> - -<p>Firefox has the option to customize its toolbars. We've already mentioned this before, and if you follow our recommendations, then you shouldn't have many problems making your toolbar compatible with the Customize Toolbars dialog. The dialog can be opened from View > Toolbars > Customize..., or by right-clicking on the main toolbar (or any toolbar with the correct <em>context</em> attribute value) and clicking on the Customize option.</p> - -<p>Other than what we have stated before, you should take into account the controls at the bottom of the Customize Toolbars dialog. You should test your toolbar buttons and items under all combinations of Icons / Icons and text / Text, Use Small Icons, and hiving your icons in different toolbars. You should also test that the Reset to Defaults button works correctly. Adding elements to your toolbar that are not <em>toolbarbutton</em> or <em>toolbaritem</em> will cause it to fail. Make sure your icons look OK while the Customize Dialog is open, and after clicking on the OK button. If you use XBL bindings, make sure everything works normally after customizing toolbars. All of this is very important to test because, when the dialog is opened, Firefox changes the DOM of the toolbar, adding wrapper elements that allow the customization. This tends to break very specific CSS, and XBL bindings lose their internal state when moved around the DOM.</p> - -<h2 id="Adding_toolbar_buttons_to_existing_toolbars">Adding toolbar buttons to existing toolbars</h2> - -<p>Finally, there is the very common case where you just want to add one button to the main toolbar. In this case you still need to add the button to the palette using an overlay. In order to add your button to the main toolbar on first run, you'll have to use Javascript code. Keep in mind that you shouldn't assume anything about the location (or presence!) of any specific buttons; remember users could have moved them or removed them altogether. The <a href="/en/Code_snippets/Toolbar#Adding_button_by_default" title="en/Code snippets/Toolbar#Adding button by default">Toolbar Code Snippets</a> page has a code sample you can use to do this.</p> - -<p>Remember to validate if your button is already present, to prevent duplicates. It's also a good idea to set a preference that indicates that you added your button already, so that it can be removed permanently if the user chooses to. Another option is to use <a href="/en/Toolkit_API/extIExtension" title="en/FUEL:Extension">FUEL's firstRun</a> property, which also relies on a preference.</p> - -<p><strong>Firefox 3</strong></p> - -<pre class="brush: js">let extension = Application.extensions.get(YOUR_EXTENSION_ID); - -if (extension.firstRun) { - // add button here. -} -</pre> - -<p><strong>Firefox 4</strong></p> - -<pre class="brush: js">Application.getExtensions(function (extensions) { - let extension = extensions.get(YOUR_EXTENSION_ID); - - if (extension.firstRun) { - // add button here. - } -})</pre> - -<p><strong>Both</strong></p> - -<pre class="brush: js">function firstRun(extensions) { - let extension = extensions.get(YOUR_EXTENSION_ID); - - if (extension.firstRun) { - // add button here. - } -} - -if (Application.extensions) - firstRun(extensions); -else - Application.getExtensions(firstRun); -</pre> - -<p>The FUEL library currently only works on Firefox 3 and above.</p> - -<p>{{ PreviousNext("Escuela_XUL/Agregar_menus_y_submenus", "Escuela_XUL/Agregar_eventos_y_comandos") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/agregar_barras_laterales/index.html b/files/es/mozilla/tech/xul/escuela_xul/agregar_barras_laterales/index.html deleted file mode 100644 index 64b2aea74a..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/agregar_barras_laterales/index.html +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: Agregar barras laterales -slug: Mozilla/Tech/XUL/Escuela_XUL/Agregar_barras_laterales -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Adding_sidebars ---- -<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}}{{AddonSidebar}}{{ PreviousNext("Escuela_XUL/Agregar_ventanas_y_dialogos", "Escuela_XUL/Uso_de_objetos_en_JavaScript") }}</p> - -<p>The sidebar in Firefox is a relatively large and flexible space to add rich interfaces without requiring new windows or complicated overlays. Sidebars take as much space as the user wants them to, and provide a frame where you can add elaborate data and controls. You're probably familiar with the Bookmarks and History sidebars. If not, you can open either one from the View > Sidebar menu. They also have shortcuts to open or close them using the keyboard.</p> - -<p>The code required to add a sidebar is very simple, as explained in <a href="/en/Creating_a_Firefox_sidebar" title="en/Creating a Firefox sidebar">Creating a Firefox Sidebar</a>. It's even simpler than that. All you need is to overlay the View Sidebar menu.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><menupopup id=<span class="code-quote">"viewSidebarMenu"</span>> - <menuitem id=<span class="code-quote">"</span><span class="code-quote">xulschoolhello</span><span class="code-quote">-sidebar"</span> - label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.sidebar.title;"</span> - accesskey=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.sidebar.accesskey;"</span> - type=<span class="code-quote">"checkbox"</span> autoCheck=<span class="code-quote">"<span class="code-keyword">false</span>"</span> group=<span class="code-quote">"sidebar"</span> - sidebarurl=<span class="code-quote">"chrome:<span class="code-comment">//xulschoolhello/content/sidebar.xul"</span> -</span> sidebartitle=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.sidebar.title;"</span> - oncommand=<span class="code-quote">"toggleSidebar('</span><span class="code-quote">xulschoolhello</span><span class="code-quote">-sidebar');"</span> /> -</menupopup></pre> -</div> -</div> - -<p>The example in the MDC page includes a shortcut key combination to toggle the new sidebar. <a href="/en/XUL_Tutorial/Keyboard_Shortcuts" title="en/XUL Tutorial/Keyboard Shortcuts">Keyboard shortcuts</a> are an essential feature of Firefox, and you can add your own into your extensions, which is also great. The problem is that choosing the right keyboard shortcuts is very, very hard, as <a class="external" href="http://adblockplus.org/blog/shortcut-keys-are-hard">explained by the creator of AdBlock Plus</a>, and the <a class="external" href="http://www.mozilla.org/access/keyboard/">Mozilla Keyboard Reference</a>. To sum up both of these references: you can choose an obscure key combination that won't conflict with Firefox, such as Ctrl+Shift+(some letter), but there's no way of knowing if any other extension uses that same combination as well. Shortcut keys can be very valuable for advanced users, but don't rely on them.</p> - -<p>The XUL page for the sidebar can hold any content you want and it's no different from other XUL windows or overlays. One minor difference is that the XUL sidebar should be defined using the <a href="/en/XUL/page" title="en/XUL/page">page</a> root element instead of <em>window</em> or <em>dialog</em>. The load event is fired every time the sidebar is opened, and unload every time it's closed, so you can use those for initialization and clean up .</p> - -<p>Another, more important difference to take into account is that users can resize the sidebar to their liking, and in most cases, the sidebar is going to be fairly narrow. You should design the content of your sidebar carefully, so that it is usable and appealing regardless of width. There are ways to limit the size boundaries of your sidebar with CSS or even disable resizing altogether, but none of those are good practices. Forcing sidebars to have a fixed size can cause accessibility and usability problems.</p> - -<p>You can still have plenty of content available in your sidebar, you just need to organize it in a way that doesn't take too much space. For this purpose we'll also look at some handy XUL elements in this section. They allow you to stack content on top of other content and switch between different sections easily.</p> - -<h2 id="The_tabbox_Element">The tabbox Element</h2> - -<p>The <a href="/en/XUL/tabbox" title="en/XUL/tabbox">tabbox</a> element creates a tabbed view of one or more <a href="/en/XUL/tabpanels" title="en/XUL/tabpanels">tabpanel</a> elements. You can see an example of a <em>tabbox</em> element if you open the Firefox Preferences window and select the Advanced section. The tabs are styled to match the operating system you're using, so you should avoid changing the CSS in tab boxes. On the other hand, if you need UI that behaves like a <em>tabbox</em> but doesn't look like one, you should still favor using a <em>tabbox</em> and use CSS to change its look. Using custom-made elements are likely to cause accessibility and functional problems.</p> - -<p>Creating a tabbed view is simple:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><tabbox id=<span class="code-quote">"</span><span class="code-quote">xulschoolhello</span><span class="code-quote">-tabbox"</span>> - <tabs> - <tab label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.mainTab.label;"</span> /> - <tab label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.advancedTab.label;"</span> /> - </tabs> - <tabpanels> - <tabpanel> - <!-- Content <span class="code-keyword">for</span> the main panel. --> - </tabpanel> - <tabpanel> - <!-- Content <span class="code-keyword">for</span> the advanced panel. --> - </tabpanel> - </tabpanels> -</tabbox></pre> -</div> -</div> - -<p>The first tab is selected by default, but you can change the default selection by setting the <a href="/en/XUL/Attribute/selected" title="en/XUL/Attribute/selected">selected</a> attribute to true in the <a href="/en/XUL/tab" title="en/XUL/tab">tab</a> element.</p> - -<p>A <em>tabpanel</em> can hold any kind of content. You should take into account that the whole tab box is going to be as large as the tab strip on the top and the content of the largest panel. You should try to balance the content in the tab panels so that you don't end up with uneven an mostly empty panels.</p> - -<h2 id="Decks_and_stacks">Decks and stacks</h2> - -<p>Sometimes you'll need finer grained control than the one provided by a <em>tabbox</em>. In these cases the <a href="/en/XUL/deck" title="en/XUL/deck">deck</a> and <a href="/en/XUL/stack" title="en/XUL/stack">stack</a> elements are probably what you're looking for. They are extremely useful, and you'll find yourself using them in many situations besides sidebars.</p> - -<p>A <em>deck</em> is like a <em>tabbbox</em> without the tabs. It only displays one of its child nodes at a time, depending on its <a href="/en/XUL/Attribute/selectedIndex" title="en/XUL/Attribute/selectedIndex">selectedIndex</a> value. In the following example, the second child will be displayed, not the first which would be the default.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><deck selectedIndex=<span class="code-quote">"2"</span>> - <hbox> - <!-- Content <span class="code-keyword">for</span> the first child. --> - </hbox> - <hbox> - <!-- Content <span class="code-keyword">for</span> the second child. --> - </hbox> -</deck></pre> -</div> -</div> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">Note how this is one of the few cases where an attribute of an element is named using camel case instead of all small caps.</div> -</div> -</div> - -<p> The size of the deck depends on the size of the largest child node, just like in a <em>tabbox</em>.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">We recommend that you use <em>hbox</em> or <em>vbox</em> elements as children of a <em>deck</em> or <em>stack</em>. The code is easier to read and maintain this way.</div> -</div> -</div> - -<p>A <em>deck</em> can be very useful when you have a large piece of XUL code that only changes in a small way depending on different circumstances. For instance, you could have a window that is used for two different purposes, and the only difference between the two cases is a label that has a value in one case and something else in another. Using a <em>.properties</em> file and a string bundle is a viable option, but it involves a lot of code for something so simple, specially if that's the only case where you need dynamic text. The alternative is to use a deck with the two labels, and change the selected index depending on the purpose of the window. This way you can still use DTD, and the code remains simple.</p> - -<p>A <a href="/en/XUL/stack" title="en/XUL/stack">stack</a> is like a <em>deck</em>, except that all of its children are always on display, one of top of the other. It allows you to decompose complex UI into individual layers, broadening the layout possibilities. One common use for a stack is to have an image background that stretches horizontally and vertically depending on the size of the foreground object:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><stack> - <hbox flex=<span class="code-quote">"1"</span>> - <image src=<span class="code-quote">"chrome:<span class="code-comment">//xulschoolhello/skin/stack-bg.png"</span> flex=<span class="code-quote">"1"</span> /> -</span> </hbox> - <hbox> - <!-- Some content here. --> - </hbox> -</stack></pre> -</div> -</div> - -<p>This workaround is necessary because you can't have an background image stretch using CSS.</p> - -<p>A less common use for the <em>stack</em> element is to use the <em>left</em> and <em>top</em> attributes on its children in order to have absolute positioning for the content on the layers. This kind of positioning can be useful for various artistic effects, as well as some type of desktop-like or Dashboard-like interface, where items are located in positions determined by the user, and they can overlap with each other. This can become complicated very easily, though.</p> - -<div class="note">Remember that you can't have flexibility and absolute positioning at the same time.</div> - -<h2 id="Trees">Trees</h2> - -<p>The bookmarks and history sidebars in Firefox use the <a href="/en/XUL/tree" title="en/XUL/tree">tree</a> element to show their content. Trees are another strong option when you need to show a great amount of information in a compact presentation. With a tree you can show a rather small amount of root nodes, giving the user the possibility to expand whichever ones are needed. Trees are specially powerful when combined with data templates, a topic that will be covered later on. You can also read much more about trees in the <a href="/en/XUL_Tutorial/Trees" title="en/XUL Tutorial/Trees">XUL Tutorial</a> page.</p> - -<p>The <em>tree</em> element is possibly the most complex element in XUL. It is meant to be very versatile and malleable, but it can require a good amount of work before it fits your specific needs. It is in reality a hierarchical table view, so its content is defined in terms of rows and columns. Here's an example of a simple tree:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><tree flex=<span class="code-quote">"1"</span>> - <treecols> - <treecol label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.nameColumn.label;"</span> flex=<span class="code-quote">"1"</span> /> - <treecol label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.greetingColumn.label;"</span> flex=<span class="code-quote">"3"</span> /> - </treecols> - <treechildren> - <treeitem> - <treerow> - <treecell label=<span class="code-quote">"Peter"</span> /> - <treecell label=<span class="code-quote">"Hey, what's up?"</span> /> - </treerow> - </treeitem> - <treeitem> - <treerow> - <treecell label=<span class="code-quote">"John"</span>/> - <treecell label=<span class="code-quote">"Good evening, how are you doing?"</span> /> - </treerow> - </treeitem> - </treechildren> -</tree></pre> -</div> -</div> - -<p>The text in the rows of the tree is hardcoded because we wouldn't generally use text from locale files. We would use data from a datasource such as a database or a remote API. This tree is not much of a tree because it only has one level of depth. A more elaborate tree would look like this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><tree flex=<span class="code-quote">"1"</span>> - <treecols> - <treecol label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.nameColumn.label;"</span> flex=<span class="code-quote">"1"</span> /> - <treecol label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.greetingColumn.label;"</span> flex=<span class="code-quote">"3"</span> /> - </treecols> - <treechildren> - <treeitem> - <treerow> - <treecell label=<span class="code-quote">"Peter"</span> /> - <treecell label=<span class="code-quote">"Hey, what's up?"</span> /> - </treerow> - </treeitem> - <!-- Notice that you need to specify the container attribute. --> - <treeitem container=<span class="code-quote">"<span class="code-keyword">true</span>"</span> open=<span class="code-quote">"<span class="code-keyword">true</span>"</span>> - <treerow> - <treecell label=<span class="code-quote">"John"</span>/> - <treecell label=<span class="code-quote">"Good evening, how are you doing?"</span> /> - </treerow> - <treechildren> - <treeitem> - <treerow> - <treecell label=<span class="code-quote">"John Jr."</span>/> - <treecell label=<span class="code-quote">"Bah, bah!"</span> /> - </treerow> - </treeitem> - </treechildren> - </treeitem> - </treechildren> -</tree></pre> -</div> -</div> - -<p>In this case, the row for "John" has a child row for "John Jr.". The <a href="/en/XUL/treechildren" title="en/XUL/treechildren">treechildren</a> element is placed as a child for John's <a href="/en/XUL/treeitem" title="en/XUL/treeitem">treeitem</a> element, and the <a href="/en/XUL/Attribute/container" title="en/XUL/Attribute/container">container</a> attribute must be set.</p> - -<p>It should be evident at this point that hand-coding a tree would take quite some time and yields a great deal of XML code that is hard to follow. This is why most of the uses of the <em>tree</em> element are for displaying data from an external datasource. Even handling the construction of a tree using Javascript and DOM functions can become very convoluted, which is why trees are better used along with templates. This topic will be covered later when we look at different kinds of datasources and templates.</p> - -<p>Adding style to a tree can also be challenging, which is why there's a guide at MDC specifically covering how to <a href="/en/XUL_Tutorial/Styling_a_Tree" title="en/XUL Tutorial/Styling a Tree">Style a Tree</a>. Looking at the Bookmarks and History sidebars should make it clear that trees are quite customizable with CSS.</p> - -<p>{{ PreviousNext("Escuela_XUL/Agregar_ventanas_y_dialogos", "Escuela_XUL/Uso_de_objetos_en_JavaScript") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/agregar_eventos_y_comandos/index.html b/files/es/mozilla/tech/xul/escuela_xul/agregar_eventos_y_comandos/index.html deleted file mode 100644 index 8d1771e21a..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/agregar_eventos_y_comandos/index.html +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: Agregar eventos y comandos -slug: Mozilla/Tech/XUL/Escuela_XUL/Agregar_eventos_y_comandos -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Adding_Events_and_Commands ---- -<p>{{LegacyAddonsNotice}}{{AddonSidebar}}</p> - -<p>{{ PreviousNext("Escuela_XUL/Agregar_barras_de_herramientas_y_botones_para_éstas", "Escuela_XUL/El_modelo_de_caja") }}</p> - -<h2 id="Event_handlers">Event handlers</h2> - -<p>Just like with HTML, most JavaScript code execution is triggered by event handlers attached to DOM elements. The most commonly used event is the <a href="/en/DOM/window.onload" title="en/DOM/window.onload">onload event</a>, which is used in overlays and other windows to detect when the window has loaded and then run initialization code:</p> - -<pre class="brush: js">// rest of overlay code goes here. -window.addEventListener( - "load", function() { XulSchoolChrome.BrowserOverlay.init(); }, false); -</pre> - -<p>You can do something similar with the <a href="/en/DOM/window.onunload" title="en/DOM/window.onunload">onunload event</a>, to do any cleanup you may need.</p> - -<div class="note">Please read <a href="/en/XUL_School/Appendix_A:_Add-on_Performance" title="en/XUL School/Appendix A: Add-on Performance">Appendix A</a> for recommendations on how to use the load event to initialize your add-on without having a negative performance impact on Firefox.</div> - -<p>Another way to attach event handlers, just like HTML, is to place the handler in the XUL code:</p> - -<pre><overlay id="xulschoolhello-browser-overlay" - onload="XulSchoolChrome.BrowserOverlay.init();" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> -</pre> - -<p>We prefer the first method because it keeps a better separation of content and behavior. Also, note that the <a href="/en/DOM/element.addEventListener" title="en/DOM/element.addEventListener">addEventListener</a> method receives the event name without the "on" prefix, while element attributes do have the prefix. There's a long <a href="/en/XUL/Events" title="en/XUL/Events">list of events</a> you can listen to, and which you use depend on the situation. Elements only implement the events that are relevant to them, but there are several events that are implemented for most elements. These are some notable events you should keep in mind:</p> - -<ul> - <li><a href="/en/XUL/Attribute/oncommand" title="en/XUL/Attribute/oncommand">oncommand</a>. This is one of the most important and commonly used events in XUL. It's very useful because it represents the most common action for input controls such as menu items, buttons and checkboxes. For a button, it represents the action of the user clicking on it, or focusing it with the keyboard and then pressing the ENTER key. It's an abstraction of the main way to interact with a control element.</li> - <li><a href="/en/XUL/Attribute/onselect" title="en/XUL/Attribute/onselect">onselect</a>. Fired when the selection in a tree or listbox changes.</li> - <li><a href="/en/XUL/Attribute/onclick" title="en/XUL/Attribute/onclick">onclick</a>. Triggered when the user clicks on the element, including right clicks. You shouldn't normally use this event to trigger actions on input controls such as buttons. Use oncommand instead.</li> - <li><a href="/en/DOM/element.onfocus" title="en/DOM/element.onfocus">onfocus</a> and <a href="/en/DOM/element.onblur" title="en/DOM/element.onblur">onblur</a>. Used when an element receives or loses focus when the user is navigating with the keyboard. You can combine these with <a href="/en/CSS/-moz-user-focus" title="en/CSS/-moz-user-focus">-moz-user-focus</a> to add custom focus behavior to elements that normally wouldn't have it.</li> - <li><a href="/En/DragDrop/Drag_and_Drop" title="en/DragDrop/Drag and Drop">Drag and drop</a>. Drag and drop operations involve several events. Since drag and drop is a complicated thing to manage, there are some high level wrappers that facilitate working with it. Also keep in mind that there are 2 drag and drop APIs, the newest (and preferred) one introduced in Firefox 3.5.</li> -</ul> - -<p>Event handlers can take an <em>event</em> argument, which is an <a href="/en/DOM/event" title="en/DOM/event">Event</a> object that holds information on the event. You can get information on key modifiers (in case the user was holding a modifier key like Alt while performing the event), screen coordinates for mouse events, and most importantly, the target element for the event. For example:</p> - -<pre><button label="&xulschoolhello.defaultGreeting.label;" - oncommand="XulSchoolChrome.BrowserOverlay.changeGreeting(event);" /> -</pre> - -<p>Then on the Javascript code you would have something like this:</p> - -<pre class="brush: js">changeGreeting : function(aEvent) { - // more stuff - aEvent.target.setAttribute("label", someNewGreeting); -} -</pre> - -<p>The target in this example is the button element, so clicking on it will change its text. The advantage of using the <em>event</em> argument is that the method is not dependent of the specific button, so it can also be used for other elements.</p> - -<p>For more advanced event handling, you should read about <a href="/en/XUL_Event_Propagation" title="en/XUL Event Propagation">Event Propagation</a>. In a nutshell, events propagate from the root of the DOM tree all the way down to the target element and then all the way up back to the root, in the capture and bubble phases, respectively. You can capture and cancel events during any of these phases, provided that they aren't canceled before they reach the point where you intended to capture them. The <em>addEventListener</em> method allows you to control the phase where you want to handle an event, with the last argument of the function.</p> - -<div class="note">In general, you should avoid adding event handlers in the capturing phase, or canceling events. This can lead to unexpected behavior for the user since most events have a default behavior associated to them.</div> - -<h3 id="Custom_events">Custom events</h3> - -<p>This is a very powerful tool that you should know, even if it isn't that frequently used. The DOM <a href="/en/DOM/document.createEvent" title="en/DOM/document.createEvent">createEvent</a> function allows you to create custom events that you can dispatch and capture.</p> - -<p>Custom events serve as a good communication mechanism, specially when dealing with a somewhat common problem: communication between window XUL and web page content. It isn't hard for XUL code to control the content on pages being loaded or displayed, as we will see later on, but it can be hard for your extension XUL code to receive information from pages in a secure manner. This is because it would be very insecure to have a website JS controlling the behavior of Firefox and running JavaScript code with chrome privileges.</p> - -<p>Suppose your extension interacts with pages from a website, and you want some actions on this site to trigger actions in your extension. One way to solve this is to have the actions on the site to generate a custom event that can be easily recognized by your extension. You can capture the events in the XUL overlay, since they'll bubble all the way up:</p> - -<pre class="brush: js">// in the overlay code. -document.addEventListener( - "XSHelloGreetingEvent", function(aEvent) { /* do stuff*/ }, false); -</pre> - -<p>Be careful when doing this! You should at least validate the URL of the page that is generating the custom event, so that you know that it's coming from the right place. You should also avoid this kind of events to trigger actions that could be destructive to the user's data, because a malicious site could try to trigger these events and cause damage. There's a reason for the division between remote content and local chrome, so make sure you respect it.</p> - -<p>There's a section further ahead on Intercepting Page Loads which complements this section very well. This should give you a solid foundation to handle interaction between web content and XUL. Additional information on custom events and how they can be used to effect communication between web content and XUL can be found in the <a href="/en/Code_snippets/Interaction_between_privileged_and_non-privileged_pages" title="en/Code snippets/Interaction between -privileged and non-privileged pages">Interaction between privileged and non-privileged pages</a> code snippets, which describe and provide examples of this sort of communication.</p> - -<h2 id="Broadcasters">Broadcasters</h2> - -<p>Keeping a consistent UI is another important aspect of extension behavior. Maybe your extension needs to disable or enable a series of controls when the user logs in or out of a service, or when Firefox detects it's <a href="/en/Online_and_offline_events" title="en/Online and offline events">online or offline</a>. It's common that you need to change several elements at the same time, and this can be difficult to manage through JavaScript. The <a href="/en/XUL/broadcaster" title="en/XUL/broadcaster">broadcaster</a> element can help you out in these cases.</p> - -<p>First you need to add a <em>broadcaster</em> element to your XUL code, as a child of a <a href="/en/XUL/broadcasterset" title="en/XUL/broadcasterset">broadcasterset</a> element.</p> - -<pre><broadcasterset id="xulschoolhello-broadcasterset"> - <broadcaster id="xulschoolhello-online-broadcaster" /> -</broadcasterset> -</pre> - -<p>These elements are completely invisible, so you can put them anywhere. It is recommended that you have them at the top of the XUL code, along with script declarations and other invisible elements with as <em>popupset</em> and <em>commandset</em>.</p> - -<p>Then you need to identify which of your XUL elements will be linked to this broadcaster, using the <a href="/en/XUL/Attribute/observes" title="en/XUL/Attribute/observes">observes attribute</a>:</p> - -<pre><menuitem id="xulschoolhello-hello-menu-item" - label="&xulschoolhello.hello.label;" - accesskey="&xulschoolhello.helloItem.accesskey;" - <strong>observes="xulschoolhello</strong><strong>-online-broadcaster"</strong> - oncommand="XULSchoolChrome.BrowserOverlay.sayHello(event);" /> -</pre> - -<p>The attribute value is set to be the <em>id</em> of the <em>broadcaster</em> element, indicating that this element will observe all attribute changes that happen in the <em>broadcaster</em>. You can have as many elements as you want observing a <em>broadcaster</em>.</p> - -<p>With that set, all you need to do now is set or remove attributes in the <em>broadcaster</em> using JavaScript. All nodes observing it will automatically have those attribute values set or removed as well. You can override pre-existing values, such as the <em>label</em> attribute value in the example.</p> - -<pre class="brush: js">let onlineBroadcaster = document.getElementById("xulschoolhello-online-broadcaster"); - -onlineBroadcaster.setAttribute("label", "Something"); -</pre> - -<p>You can also have finer-grained control to this behavior by adding the <a href="/en/XUL/observes" title="en/XUL/observes">observes</a> element as a child to your observer node. This allows you to choose which attributes you want it to observe.</p> - -<p>Broadcasters allow you to easily maintain consistency among numerous elements without having to add much code. They also save you the trouble of having to know if a given element is present in the DOM or not. For example, if you have a customizable toolbar, you can't be sure if a given button is present or not, so it's easier to use a <em>broadcaster</em>. This way you only need to set values to the broadcaster instead of having to check if the button is there or not.</p> - -<h2 id="Commands">Commands</h2> - -<p>The <a href="/en/XUL/Attribute/command" title="en/XUL/Attribute/command">command</a> element is a specialized type of <em>broadcaster</em>, meant to be used with the <em>oncommand</em> event. This is the recommended way of centralizing common UI behavior in Firefox and extensions. Commands are heavily used in Firefox, as a quick look into the DOM Inspector should show.</p> - -<p>Their behavior is identical as <em>broadcaster</em> elements, but they should be used when <em>oncommand</em> is one of the shared attributes. Our menu example is in fact better suited for a command.</p> - -<pre><commandset id="xulschoolhello-commandset"> - <command id="xulschoolhello-hello-command" - oncommand="XULSchoolChrome.BrowserOverlay.sayHello(event);" /> - <!-- More commands. --> -</commandset> -<!-- More code here... --> -<menuitem id="xulschoolhello-hello-menu-item" - label="&xulschoolhello.hello.label;" - accesskey="&xulschoolhello.helloItem.accesskey;" - command="xulschoolhello-hello-command" /> -</pre> - -<p>Commands allow you to keep your JavaScript calls in a single place, avoiding code repetition and possible bugs. Your UI can easily scale this way. You can create an extension that adds toolbar buttons, statusbar buttons and menu items, all with equivalent behavior, and without having to repeat lots of XUL code in the process. Commands and broadcasters also facilitate working with complex form windows and dialogs. You should always keep them in mind when adding the event-driven code for your extension.</p> - -<p>{{ PreviousNext("Escuela_XUL/Agregar_barras_de_herramientas_y_botones_para_éstas", "Escuela_XUL/El_modelo_de_caja") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/agregar_menus_y_submenus/index.html b/files/es/mozilla/tech/xul/escuela_xul/agregar_menus_y_submenus/index.html deleted file mode 100644 index e39f36363a..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/agregar_menus_y_submenus/index.html +++ /dev/null @@ -1,139 +0,0 @@ ---- -title: Agregar menus y submenus -slug: Mozilla/Tech/XUL/Escuela_XUL/Agregar_menus_y_submenus -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Adding_menus_and_submenus ---- -<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}}{{AddonSidebar}}</p> - -<p>{{ PreviousNext("Escuela_XUL/Montando_un_ambiente_de_desarrollo", "Escuela_XUL/Agregar_barras_de_herramientas_y_botones_para_éstas") }}</p> - -<p>The Hello World example in the previous sections shows the two most common ways to add menus: adding them to the Tools menu (recommended) and adding them to the main menu bar (not recommended). In this section we'll look into more specialized menus and what you can do with them.</p> - -<h2 id="Adding_a_New_Menu">Adding a New Menu</h2> - -<p>We already saw how to add menus in overlays, and as you may have imagined, you can nest submenus as deep as you want. You should avoid having deep menus full of options, though, because too many options are confusing for most users.</p> - -<p>If your extension requires new XUL windows, you may also need to have menus on those windows. You can do this with a <a href="/en/XUL/menubar" title="en/XUL/menubar">menubar</a>. The <em>menubar</em> element should be a child of a <a href="/en/XUL/toolbox" title="en/XUL/toolbox">toolbox</a> element because it is treated like another toolbar on systems other than Mac OS X. On those systems you can move toolbar controls to the menu bar when you're customizing your toolbars.</p> - -<div class="note"> -<p>Mac OS X treats menus in a very different way than other systems. If your extension involves menus in any way, you should test it on Mac OS X to make sure everything works adequately.</p> -</div> - -<p>The toolbox should be positioned at the beginning of the XUL document, and the code should be similar to this:</p> - -<pre><code><toolbox> - <menubar id="</code><code>xulschoolhello</code><code>-menubar"> - <menu id="</code><code>xulschoolhello</code><code>-greeting-menu" label="&</code><code>xulschoolhello</code><code>.greeting.label;"> - <menupopup> - <menuitem label="&xulschoolhello.greet.short.label;" - oncommand="XULSchoolChrome.GreetingDialog.greetingShort(event);" /> - <menuitem label="&</code><code>xulschoolhello</code><code>.greet.medium.label;" - oncommand="XULSchoolChrome.GreetingDialog.greetingMedium(event);" /> - <menuitem label="&</code><code>xulschoolhello</code><code>.greet.long.label;" - oncommand="XULSchoolChrome.GreetingDialog.greetingLong(event);" /> - <menuseparator /> - <menuitem label="&</code><code>xulschoolhello</code><code>.greet.custom.label;" - oncommand="XULSchoolChrome.GreetingDialog.greetingCustom(event);" /> - </menupopup> - </menu> - </menubar> -</toolbox> </code></pre> - -<p>This code displays a simple <a href="/en/XUL/menu" title="en/XUL/menu">menu</a> with options for 3 different types of greetings, a <a href="/en/XUL/menuseparator" title="en/XUL/menuseparator">menuseparator</a>, and finally an option to show a custom greeting. The separator is usually displayed as a horizontal line that creates a logical division between different types of <a href="/en/XUL/menuitem" title="en/XUL/menuitem">menuitem</a> elements, keeping everything more organized.</p> - -<p>A <em>menubar</em> can hold one or more <em>menu</em> elements. Menus require a <a href="/en/XUL/menupopup" title="en/XUL/menupopup">menupopup</a> element as a container for its children, which are usually <em>menuitem</em> elements, but can also be <em>menuseparator,</em> or <em>menu</em> in order to have multiple nesting levels:</p> - -<pre><code><toolbox> - <menubar id="</code><code>xulschoolhello</code><code>-menubar"> - <menu id="</code><code>xulschoolhello</code><code>-greeting-menu" label="&</code><code>xulschoolhello</code><code>.greeting.label;"> - <menupopup> - <menu id="</code><code>xulschoolhello</code><code>-greeting-sizes-menu" label="&</code><code>xulschoolhello</code><code>.greetingSizes.label;"> - <menupopup> - <menuitem label="&</code><code>xulschoolhello</code><code>.greet.short.label;" - oncommand="</code><code>XULSchoolChrome</code><code>.GreetingDialog.greetingShort(event);" /> - <menuitem label="&</code><code>xulschoolhello</code><code>.greet.medium.label;" - oncommand="</code><code>XULSchoolChrome</code><code>.GreetingDialog.greetingMedium(event);" /> - <menuitem label="&</code><code>xulschoolhello</code><code>.greet.long.label;" - oncommand="</code><code>XULSchoolChrome</code><code>.GreetingDialog.greetingLong(event);" /> - </menupopup> - </menu> - <menuitem label="&</code><code>xulschoolhello</code><code>.greet.custom.label;" - oncommand="</code><code>XULSchoolChrome</code><code>.GreetingDialog.greetingCustom(event);" /> - </menupopup> - </menu> - </menubar> -</toolbox> </code></pre> - -<p>In this case we grouped the 3 greeting items into a submenu. It doesn't make much sense to do that in this case because we end up with only two menu items, one of them being a menu with 3 child items.</p> - -<p>You can also have menus that are filled dynamically. Instead of setting the menupopup directly in the XUL, you can use the <a href="/en/XUL/Attribute/onpopupshowing" title="en/XUL/Attribute/onpopupshowing">onpopupshowing</a> event to fill the children when the popup is about to be displayed.</p> - -<div class="note"> -<p>If you have nothing to show on a menu, you should follow the standard used in Firefox: show a single disabled item with an "(Empty)" label.</p> - -<p>If filling your menu takes a noticeable amount of time, you should not make Firefox (and your users) wait for it to fill up before displaying anything. It's best to show an item with a throbber image (see <a class="external" rel="freelink">chrome://global/skin/icons/loading_16.png</a>) so the user knows there's something going on, and asynchronously fill its contents. We'll look into some asynchronous techniques further ahead in the tutorial.</p> -</div> - -<h2 id="Adding_Elements_to_Existing_Menus">Adding Elements to Existing Menus</h2> - -<p>Just as explained in the previous sections, the best place to overlay your extension menu is inside the <em>Tools</em> menu. That is, unless there's a place inside the menu structure where your extension menus make more sense. If you're overlaying the Tools menu, your overlay code should have something like this:</p> - -<pre><code><menupopup id="menu_ToolsPopup"> - <menu id="</code><code>xulschoolhello</code><code>-hello-menu" label="&</code><code>xulschoolhello</code><code>.hello.label;" - accesskey="&</code><code>xulschoolhello</code><code>.helloMenu.accesskey;" - insertafter="javascriptConsole,devToolsSeparator"> - <menupopup> - <!-- Your menuitem goes here. --> - </menupopup> - </menu> -</menupopup> </code></pre> - -<p>Now let's look at some specialized types of menu items.</p> - -<h2 id="Menu_types">Menu types</h2> - -<h3 id="Checkbox_Menu_Items">Checkbox Menu Items</h3> - -<p>You can make a <em>menuitem</em> "checkable" to allow the user to enable/disable options using the menu. We use two attributes for this: <a href="/en/XUL/menuitem#a-menuitem.type" title="en/XUL/menuitem#a-menuitem.type">type</a> and <a href="/en/XUL/menuitem#a-checked" title="en/XUL/menuitem#a-checked">checked</a>. The <em>type</em> attribute must be set to "checkbox". You can set the <em>checked</em> attribute to "true" to check it by default.</p> - -<p>The item's checked state changes when the user clicks on it. An example of one such item is the View > Status Bar item in the main Firefox menu.</p> - -<h3 id="Radio_Menu_Items">Radio Menu Items</h3> - -<p>If you need to have a set of <em>menuitem</em> elements where only one of them has to be checked at any given moment, you should set the <em>type</em> to "radio". The <em>name</em> attribute is used to identify the items that belong to the radio group.</p> - -<pre><code><menupopup oncommand="XULSchoolChrome.HW.GreetingDialog.greeting(event);"> - <menuitem type="radio" name="</code><code>xulschoolhello</code><code>-greeting-radio" - label="&</code><code>xulschoolhello</code><code>.greet.short.label;" checked="true" /> - <menuitem type="radio" name="</code><code>xulschoolhello</code><code>-greeting-radio" - label="&</code><code>xulschoolhello</code><code>.greet.medium.label;" /> - <menuitem type="radio" name="</code><code>xulschoolhello</code><code>-greeting-radio" - label="&</code><code>xulschoolhello</code><code>.greet.long.label;" /> -</menupopup> </code></pre> - -<p>This is a modified version of the 3 greeting menus. It is now implemented as a radio menu where you pick one of the 3 available choices. The first one is checked by default. The <em>oncommand</em> attribute is set on the <em>menupopup</em> to avoid code duplication, since now the 3 items call the same function.</p> - -<p>Another example of a menu like this is the View > Sidebars menu. Only one sidebar is visible at any given moment, and you can pick from several.</p> - -<h3 id="Menus_with_Images">Menus with Images</h3> - -<p>To add an icon to a <em>menu</em> or <em>menuitem</em>, set its class to "menu-iconic" or "menuitem-iconic" respectively, and set the <a href="/en/XUL/Attribute/image" title="en/XUL/Attribute/image">image</a> attribute or the <a href="/en/CSS/list-style-image" title="en/CSS/list-style-image">list-style-image</a> CSS property. Menu icons are typically 16px by 16px.</p> - -<h2 id="Menus_on_Mac_OS_X">Menus on Mac OS X</h2> - -<p>As mentioned earlier, menus are very different on Mac OS X. This is because menus on Mac are unified in a single menu bar which is controlled by the operating system, as opposed to menus in other systems, which are entirely controlled by Firefox. Mac OS X also has menu standards, such as the positioning of certain items that are not used in other systems. Here's a list of the known issues we've run into when handling menus on Mac:</p> - -<ul> - <li>The About, Preferences and Quit menu items are located under the "Firefox" menu, not the usual places you would find them. You can access these items by id through the DOM, but their parent menu is not easily accessible.</li> - <li>We've run into bugs when adding, removing, enabling and disabling menu items dynamically, specially the root menu items (File, Edit, View, etc). You should carefully test this behavior to make sure it works properly in your extension.</li> - <li>Images in menu items may not appear, showing only a narrow segment of the image instead. This seems to happen when remote images are used.</li> - <li>Menu items are not dynamically updated while they are open. For example, you could have a <em>menuitem</em> that tells you the current time and is updated every second. On other systems you would be able to see the item update itself without having to close the menu and then reopen. This is not the case on Mac OS.</li> -</ul> - -<p>{{ PreviousNext("Escuela_XUL/Montando_un_ambiente_de_desarrollo", "Escuela_XUL/Agregar_barras_de_herramientas_y_botones_para_éstas") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/agregar_ventanas_y_dialogos/index.html b/files/es/mozilla/tech/xul/escuela_xul/agregar_ventanas_y_dialogos/index.html deleted file mode 100644 index 030ed3c918..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/agregar_ventanas_y_dialogos/index.html +++ /dev/null @@ -1,197 +0,0 @@ ---- -title: Agregar ventanas y dialogos -slug: Mozilla/Tech/XUL/Escuela_XUL/Agregar_ventanas_y_dialogos -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Adding_windows_and_dialogs ---- -<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>{{ PreviousNext("Escuela_XUL/El_modelo_de_caja", "Escuela_XUL/Agregar_barras_laterales") }}</p> - -<h2 id="Opening_windows_and_dialogs">Opening windows and dialogs</h2> - -<p>To open a new window, use the Javascript <a href="/en/DOM/window.open" title="en/DOM/window.open">window.open</a> function just like with HTML windows.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">window.open( - <span class="code-quote">"chrome:<span class="code-comment">//xulschoolhello/content/someWindow.xul"</span>, -</span> <span class="code-quote">"</span><span class="code-quote">xulschoolhello</span><span class="code-quote">-some-window"</span>, - <span class="code-quote">"chrome,centerscreen"</span>);</pre> -</div> -</div> - -<p>The first argument is the URL to open, the second is an id to identify the window, and the last is an optional comma-separated list of features, which describe the behavior and appearance of the window. If this value is null or empty, the default toolbars of the main window will be added to the new one, which is rarely what you want. The <a href="/en/DOM/window.open" title="en/DOM/window.open">window.open</a> page has a detailed description of the features you can use and their values. The following features are very important and you should always keep them in mind:</p> - -<ul> - <li>chrome. This can only be used from the chrome, not from regular HTML JavaScript. It indicates that a chrome document is being opened, not a web page. This means that the document defines the whole window, and not only the inner content area. You should always include it when opening a XUL window or dialog.</li> - <li>modal. Modal windows block their parent window until action is taken on them. An alert window is an example of this. Modal windows should be avoided when possible because they interrupt the user's browsing and can become annoying very quickly. This feature should only be used when there's no way to continue without having the user do something. <strong>Never open modal windows at startup.</strong></li> - <li>resizable. Indicates the user can resize the window or not. In general, windows should not be resizable unless they display dynamically generated content from a datasource, such as lists or trees that may need resizing to have a better view of the content.</li> -</ul> - -<p>To open a new dialog, use the function <a href="/en/DOM/window.openDialog" title="en/DOM/window.openDialog">window.openDialog</a>, an extension of the <em>open</em> function. It allows you to send a set of optional parameters that can be used to communicate with the dialog.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let someValue = 2; -let returnValue = { accepted : false , result : "" }; - -window.openDialog( - "<a class="external" rel="freelink">chrome://xulschoolhello/content/someDialog.xul</a>", - "xulschoolhello-some-dialog", "chrome,centerscreen", - someValue, returnValue); // you can send as many extra parameters as you need. - -// if (returnValue.accepted) { do stuff }</pre> -</div> -</div> - -<p>The optional parameters are available in the dialog code through the <em>window.arguments</em> property:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let someValue = window.arguments[0]; -let returnValue = window.arguments[1]; - -// returnValue.accepted = true; -// returnValue.result = "something"; -</pre> -</div> -</div> - -<p>The parameter named <em>returnValue</em> is an object that the dialog will modify to reflect what the user did in it. This is the simplest way to have the dialog return something to its opener. Note that the opener will wait until the dialog is closed. This means the <em>openDialog</em> function call will not return until the dialog has been closed by the user.</p> - -<h2 id="Common_Dialogs_and_the_Prompt_Service">Common Dialogs and the Prompt Service</h2> - -<p>There are several types of dialogs that are fairly common, so there are ways to create them easily without having to reinvent the wheel and write all their XUL and JS code all over again. Whenever you need a new dialog, you should ask yourself if it can be implemented using these common dialogs, and use them whenever it is possible. They have been thoroughly tested for OS integration, accessbility and localization, so you save yourself a lot of work and favor them.</p> - -<p>Using the <a href="/en/XPCOM_Interface_Reference/nsIPromptService" title="en/NsIPromptService">Prompt Service</a> is the recommended way to create common dialogs in an extension. Read the article and its examples carefully, because there are many useful functions to use in the Prompt Service. There are some equivalent, simpler functions that are available in the <em>window</em> object, but those are meant for unprivileged HTML JavaScript code.</p> - -<h3 id="Alert">Alert</h3> - -<p>The alert is the simplest form of dialog. All it does is display a text message that the user can read and then click the OK button to dismiss it. We have been using the <a href="/en/DOM/window.alert" title="en/DOM/window.alert">window.alert</a> function to open alert messages in our examples so far, but that's not the right way to do it. It's OK to use this function if you're just debugging some problem and want to see if the program reaches a specific line of code, or to inspect the value of a variable, but your final extension should not have <em>alert</em> calls anywhere.</p> - -<p>If you use <em>window.alert</em>, the alert window will have the title [JavaScript Application], indicating that the source of the message is not well defined. The Prompt Service allows better alerts to be displayed. Here's an example of displaying an alert using the Prompt Service:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let prompts = - Cc["@mozilla.org/embedcomp/prompt-service;1"]. - getService(Ci.nsIPromptService); - -prompts.alert(window, "Alert Title", "Hello!");</pre> -</div> -</div> - -<p>You should of course use localized strings instead of hard-coded ones.</p> - -<p>The Prompt Service allows you to set the title of the dialog however you want it, and also lets you specify the window you want to use as a parent for the alert. This normally should be set to the current window. You can pass a null value and the service will pick the currently active window.</p> - -<h3 id="Confirm">Confirm</h3> - -<p>Confirmation dialogs display a text with a Yes / No question, and prompts the user to choose an answer. In HTML you can use the <a href="/en/DOM/window.confirm" title="en/DOM/window.confirm">window.confirm</a> function for this. The Prompt Service has a <em>confirm</em> method with similar behavior:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let prompts = - Cc["@mozilla.org/embedcomp/prompt-service;1"]. - getService(Ci.nsIPromptService); - -if (prompts.confirm(window, "Confirm Title", "Would you like to continue?")) { - // do something. -} else { - // do something else -}</pre> -</div> -</div> - -<p>The method returns a boolean value indicating the user's response.</p> - -<h3 id="Others">Others</h3> - -<p>Unprivileged Javascript can also use the <a href="/en/DOM/window.prompt" title="en/DOM/window.prompt">window.prompt</a> function to receive text input from the user. The Prompt Service has a very rich set of functions that allow different kinds of inputs, such as text, passwords, usernames and passwords, and checkboxes that can be used for "Never ask this again"-type dialogs. The <a href="/en/XPCOM_Interface_Reference/nsIPromptService#confirmEx" title="en/nsIPromptService#confirmEx">confirmEx</a> and <a href="/en/XPCOM_Interface_Reference/nsIPromptService#prompt" title="en/nsIPromptService#prompt">prompt</a> methods are the most customizable, allowing a great deal of options that cover most common dialog cases.</p> - -<p>Using the Prompt Service will save you a lot of XUL coding, and you'll be at ease knowing that you're using Mozilla's tried and tested code.</p> - -<h2 id="The_Dialog_Element">The Dialog Element</h2> - -<p>When the Prompt Service is not enough, you'll have to create you own XUL dialogs. Luckily, you still get a great deal of help from the platform if you use the <a href="/en/XUL/dialog" title="en/XUL/dialog">dialog</a> element as the document root instead of the more generic <em>window</em> element.</p> - -<p>You may be asking yourself what's the big deal about defining a simple XUL window with an OK and maybe a Cancel button. The dialogs we have covered in this section are very simple and shouldn't be too hard to implement manually using XUL. Well, it's more complicated than that. Different operating systems order and position their buttons differently in their dialogs. There are also subtle aspects about window size, margins and paddings that are not the same for all systems, so you should avoid making dialogs from scratch or overriding the default dialog CSS styles.</p> - -<p>The <em>dialog</em> element handles all of this transparently. All you need to do is define which buttons you'll need and the actions associated with them.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><dialog id=<span class="code-quote">"</span><span class="code-quote">xulschoolhello</span><span class="code-quote">-hello-dialog"</span> - title=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.helloDialog.title;"</span> - buttons=<span class="code-quote">"accept,cancel"</span> - ondialogaccept=<span class="code-quote">"<span class="code-keyword">return</span> XULSchoolChrome.HelloDialog.accept();"</span> - ondialogcancel=<span class="code-quote">"<span class="code-keyword">return</span> XULSchoolChrome.HelloDialog.cancel();"</span> - xmlns=<span class="code-quote">"http:<span class="code-comment">//www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"</span>></span></pre> -</div> -</div> - -<p>Carefully read the specification of the <a href="/en/XUL/dialog" title="en/XUL/dialog">dialog</a> element. You'll see that you can choose from a wide variety of buttons, associate any action you need to them, override their labels, and even add completely customized extra buttons. All of this without having to worry about your dialog looking odd in some operating systems. The only constant rule is that clicking on OK and Cancel will close the dialog unless your associated function returns false. You should avoid returning false, though, specially with the Cancel button. Dialogs in general should be easy to dismiss.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<p>Your dialogs shouldn't have fixed dimensions because of potential localization problems. Dialogs are sized to their contents and will generally work fine. However, there are cases where the dialog contents are generated or expanded dynamically by your code, and you'll need to resize them appropriately. The <a href="/en/DOM/window.sizeToContent" title="en/DOM/window.sizeToContent">window.sizeToContent</a> function is what you need in this case.</p> -</div> -</div> - -<h2 id="Input_Controls">Input Controls</h2> - -<p>Most additional XUL windows and dialogs in extensions are some kind of input form. Let's look into the most commonly used form elements and how to use them in your XUL windows. There isn't much we need to add from what the XUL Tutorial explains, so go ahead and read the following sections:</p> - -<ul> - <li><a href="/en/XUL_Tutorial/Input_Controls" title="en/XUL Tutorial/Input Controls">Input controls</a></li> - <li><a href="/en/XUL_Tutorial/Numeric_Controls" title="en/XUL Tutorial/Numeric Controls">Numeric controls</a></li> - <li><a href="/en/XUL_Tutorial/List_Controls" title="en/XUL Tutorial/List Controls">List controls</a></li> -</ul> - -<p>There are some other aspects to take into account when handling input controls, which we cover in the following sections.</p> - -<h3 id="Groupboxes">Groupboxes</h3> - -<p>The <a href="/en/XUL/groupbox" title="en/XUL/groupbox">groupbox</a> element should be easy to understand: it groups a series of XUL controls together. It's a box container with styling that is usually a visible border around its contents, so that it's clear what is being grouped together. It is frequently used with the <a href="/en/XUL/caption" title="en/XUL/caption">caption</a> element to associate the grouped elements with a title.</p> - -<p>The <em>groupbox</em> shouldn't be seen as an aesthetic device, but a logical one. If all you need is a border, use CSS. The <em>groupbox</em> element should be used when enclosed elements share some function which is separate from other elements or groups in the same window. It's also a useful accessibility feature, because screen readers will read the caption right before reading any text in its contents. You can change its style using CSS in case you don't want the borders to appear. See the Firefox Preferences window for an example of this: sections are defined using <em>groupbox</em> elements, but their style is quite different from the default.</p> - -<h3 id="Attribute_Persistence">Attribute Persistence</h3> - -<p>User actions can change the state of your windows, such as selecting an option in a listbox, or entering text in a textbox. If the user closes and then reopens your window, all the controls are reset to their defaults, which may not be what you want. You need some way of remembering the user-manipulated attribute values so that the window reloads it last state when opened.</p> - -<p>Most XUL elements support the <a href="/en/XUL/Attribute/persist" title="en/XUL/Attribute/persist">persist</a> attribute, which has this exact function. You set the <em>persist</em> attribute with a space-separated list of attribute names, indicating which attribute values must be persisted across window "sessions".</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><checkbox id=<span class="code-quote">"</span><span class="code-quote">xulschoolhello</span><span class="code-quote">-some-checkbox"</span> - label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.someText.label;" - </span> checked=<span class="code-quote">"<span class="code-keyword">false</span>"</span> persist=<span class="code-quote">"checked"</span> /></pre> -</div> -</div> - -<p>Setting the <em>id</em> attribute of the element is mandatory if you want the <em>persist</em> attribute to work. You can also set persistence programatically using the <em>document.persist</em> function:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">document.persist("xulschoolhello-some-checkbox", "checked");</pre> -</div> -</div> - -<p>Persistent data is stored in the user profile, in the file <em>localstore.rdf</em>. You may need to modify or delete this file often when testing persistent data in your extension.</p> - -<h3 id="Focus_and_Tabbing">Focus and Tabbing</h3> - -<p>Moving through all input controls in a window using only the keyboard is an accessibility requirement. You can do this in most Firefox windows by pressing the Tab key. Each Tab key press moves you to the next control in the window, giving it focus.</p> - -<p>In general, there's nothing you need to do in order to have good keyboard focus management. Firefox will automatically focus the first input control in your window, and tab focus advances in the order the items are found in the XUL document. If you have a very complex layout, or need customized tabbing behavior, you can set the <a href="/en/XUL/Property/tabIndex" title="en/XUL/Property/tabIndex">tabindex</a> attribute in the controls. You can also use the <a href="/en/XUL/Method/focus" title="en/XUL/Method/focus">focus</a> function to focus an element depending on events such as window load. You should do this carefully, to avoid having inaccessible controls.</p> - -<p>You can also use the <a href="/en/CSS/-moz-user-focus" title="en/CSS/-moz-user-focus">-moz-user-focus</a> CSS property to enable focusing of elements that typically wouldn't receive focus. Again, this should be used sparingly.</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/almacenamiento_local/index.html b/files/es/mozilla/tech/xul/escuela_xul/almacenamiento_local/index.html deleted file mode 100644 index 888f350c16..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/almacenamiento_local/index.html +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: Almacenamiento local -slug: Mozilla/Tech/XUL/Escuela_XUL/Almacenamiento_local -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Local_Storage ---- -<p>{{LegacyAddonsNotice}}{{AddonSidebar}}</p> -<p>{{ PreviousNext("Escuela_XUL/Manejo_de_preferencias", "Escuela_XUL/Interceptando_cargas_de_página") }}</p> - -<p>It is very common for an extension to require some kind of local persistent storage. We recommend that you at least keep an error log, so that you can request error data from your users when you encounter problems that are hard to debug. We'll discuss logging in this section, but first let's look at the right (or at least, common and scalable) way of managing local files.</p> - -<p>It is strongly recommended that you keep your local files inside the Firefox profile directory. Otherwise you may run into problems if the same extension is installed in multiple profiles. The common practice is to create a directory with the name of your project at the root of the profile folder, and keep your files inside. The structure could be something like this:</p> - -<ul> - <li>s435L.default (your profile directory) - <ul> - <li>XULSchool - <ul> - <li>log.txt</li> - <li>somedbfile.sqlite</li> - </ul> - </li> - </ul> - </li> -</ul> - -<p>The <a href="/en/nsDirectoryService" title="en/nsDirectoryService">Directory Service</a> and the {{ interface("nsIFile") }} interface are used to create the local directory. Here's what we usually do: we have a function that returns a reference to our root directory and creates it if necessary.</p> - -<pre class="brush: js">getLocalDirectory : function() { - let directoryService = - Cc["@mozilla.org/file/directory_service;1"]. - getService(Ci.nsIProperties); - // this is a reference to the profile dir (ProfD) now. - let localDir = directoryService.get("ProfD", Ci.nsIFile); - - localDir.append("XULSchool"); - - if (!localDir.exists() || !localDir.isDirectory()) { - // read and write permissions to owner and group, read-only for others. - localDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0774); - } - - return localDir; -}, -</pre> - -<p><strong>ProfD</strong> is a special identifier for the profile directory that exists so that you don't need to figure out its location. In general this is the only directory flag you'll need, but sometimes you'll need access to other system directories, and you don't want to have to worry about which operating system or system language your extension is running on. A {{ source("xpcom/io/nsDirectoryServiceDefs.h","full list of these flags") }} can be found in the Firefox source.<br> - Having that function in place, we do something like the following:</p> - -<pre class="brush: js">let myFile = XULSchool.getLocalDirectory(); - -myFile.append("someFile.txt"); -// do stuff with the file.</pre> - -<p>Files are handled with the {{ interface("nsIFile") }} interface. An {{ interface("nsIFile") }} doesn't necessarily represent an existing file, as in the previous examples. You first specify the file using {{ interface("nsIFile") }} and then use {{ ifmethod("nsIFile","create") }} to actually write it out to disk. You can also check if an {{ interface("nsIFile") }} exists using {{ ifmethod("nsIFile","exists") }}.</p> - -<p>To read and write information in files, you need to use stream objects. You can read more about <a href="/en/Code_snippets/File_I//O" title="en/Code snippets/File I//O">reading and writing files here</a>. In general you won't need to do this directly, but it's always useful to know.</p> - -<p>Finally, there's the issue of deleting local files when the extension is going to be uninstalled. Whether this is necessary or not is a matter of preference. Some extension developers prefer to leave the data there, so that if the user chooses to install the extension again, all the previous data will be recovered. This is the default behavior when Firefox is uninstalled: the profile information remains intact and it will be there waiting for you if Firefox is installed again. Others feel concerned about privacy and storing private information locally without deleting it. A good argument can be done for both, so it is up to you to choose what to do in this case. The FUEL library has an <a href="/en/Toolkit_API/extIExtension" title="en/Toolkit API/extIExtension">uninstall event</a> you can use to perform these operations.</p> - -<h2 id="Logging">Logging</h2> - -<p>Good logging is essential in all kinds of software projects. Any extension that is more complex than a Hello World needs some way to log errors and trace execution without having to fire up a debugger.</p> - -<p>It used to be the case that custom logging solutions were necessary, but Mozilla Labs have come up with a JavaScript implementation of a logger similar to the <a class="external" href="http://logging.apache.org/log4j/1.2/index.html">Log4J logger</a> used in Java projects. The logger is called <a class="link-https" href="https://wiki.mozilla.org/Labs/JS_Modules#Logging" title="https://wiki.mozilla.org/Labs/JS_Modules#Logging">Log4Moz</a> and it is implemented as a JavaScript Code Module, so it only works on Firefox 3 and above.</p> - -<p>To use this logger, you need to copy the <strong>log4moz.js</strong> file to your modules directory. In the initialization method of your one of your "common" or startup objects, add the following code:</p> - -<pre class="brush: js">let formatter = new Log4Moz.BasicFormatter(); -let root = Log4Moz.repository.rootLogger; -let logFile = this.getLocalDirectory(); // remember this? -let appender; - -logFile.append("log.txt"); - -// Loggers are hierarchical, lowering this log level will affect all -// output. -root.level = Log4Moz.Level["All"]; - -// this appender will log to the file system. -appender = new Log4Moz.RotatingFileAppender(logFile, formatter); -appender.level = Log4Moz.Level["All"]; -root.addAppender(appender); -</pre> - -<p>After that, you can create a logger object for any object in your project like this:</p> - -<pre class="brush: js">this._logger = Log4Moz.repository.getLogger("XULSchool.SomeObject"); - -this._logger.level = Log4Moz.Level["All"]; -</pre> - -<p>{{ note("We recommend that you create a logger instance in the constructor of every object and store it in a private variable.") }}</p> - -<p>And then logging is done with any of the following methods, depending on the kind of message being logged:</p> - -<pre class="brush: js">this._logger.fatal("This is a fatal message."); -this._logger.error("This is an error message."); -this._logger.warn("This is a warning message."); -this._logger.info("This is an info message."); -this._logger.config("This is a config message."); -this._logger.debug("This is a debug message."); -this._logger.trace("This is a trace message."); -</pre> - -<p>You can filter the output of the global logger or any specific logger instance by setting the <strong>level</strong> property. During development you should use the "All" level, but for release versions it's usually better to move the level up to "Warn", so that the log is compact and execution is more efficient.</p> - -<div class="note"><strong>Note:</strong> We recommend that all exception <strong>catch</strong> blocks include some logging at the error or warn levels, and in general you should use logging freely in order to have as much information as possible to fix bugs and know what is going on. Don't log inside functions that are called too often, such as <strong>mouseover</strong> event handlers, or certain HTTP activity listeners. This impacts performance and fills the log with useless messages. We normally add a comment that indicates that logging is not done there for performance reasons.</div> - -<h2 id="SQLite">SQLite</h2> - -<p><a class="external" href="http://en.wikipedia.org/wiki/Sqlite">SQLite</a> storage was introduced in Firefox 2, and it's the preferred storage mechanism in Firefox. It is the storage system used for the <a href="/en/Places" title="en/Places">Places API</a> that manages bookmarks and history. It's also used for storing cookies, form inputs, and others.</p> - -<p>SQLite is a lightweight SQL based storage system. It is ideal for embedding in other programs, and is currently in use in several popular applications. It's also the storage system we recommend for local storage in extensions.</p> - -<p>The <a href="/en/Storage" title="en/Storage">Storage page</a> has a good explanation on how to use the SQLite API, so we won't go over that again. If you're unfamiliar with SQL or if you're interested in knowing the restrictions in the syntax used by SQLite, you can read more at the <a class="external" href="http://www.sqlite.org/lang.html">SQLite site</a>.</p> - -<p>You should carefully design your database structure, taking into account features you're planning on adding in the future. Adding or removing columns, or making other changes to your DB structure from one version of your extension to the next will probably cause breakage of user data in older versions. You'll need to carefully add migration code that moves the data from the old DB format to the new, and this becomes increasingly complex as you add new versions and new structure changes. So, be careful and plan for the future.</p> - -<p>There are two paths you can take when creating the local database you'll be using for your extension:</p> - -<ul> - <li>Generate the database file (through {{ ifmethod("mozIStorageService","openDatabase") }}, all tables (through {{ ifmethod("mozIStorageConnection","createTable") }}, and initial data when your extension starts up for the first time. If you need a complex database this can be heavy in terms of time and code, but this will only happen once and this can be done in a lazy or asynchronous way.</li> - <li>Have an initial database file in your <strong><code>defaults</code></strong> directory that you can copy to the user's profile. This way you just need to do a file copy. You can reach the <code>defaults</code> directory at <code><strong>ProfD/extensions/YOUR_EXTENSION_ID.xpi/defaults</strong></code> for packed extensions or <code><strong>ProfD/extensions/YOUR_EXTENSION_ID/defaults</strong></code> for unpacked extensions. Packed extensions have appear with Gecko 2.0 (Firefox 4.0). This approach has the downside of being less stable.</li> -</ul> - -<h2 id="RDF">RDF</h2> - -<p><a href="/en/RDF" title="en/RDF">RDF</a> used to be the preferred storage mechanism for Firefox. If was used for most of its datasources, and you can still see it in use here and there, like in the <strong>install.rdf</strong> file. It is being phased out, with SQLite taking its place in most cases. The RDF API may be removed at some point in the future because it requires a great deal of code even for the simplest tasks, and it currently sees little maintenance, so we don't recommend using it unless you really have to.</p> - -<p>You'll still need to understand at least a little about RDF when you read the documentation about templates.</p> - -<h2 id="Templates">Templates</h2> - -<p>Templates are a very powerful tool in Firefox. They allow you to automatically generate XUL content using information from a datasource, and automatically update the content once the datasource changes. They were designed with RDF datasources in mind, but since Firefox 3 they have been extended to support SQLite datasources as well.</p> - -<p>Handling templates can also be complicated, but it is worth the effort if you need to display long lists or trees with complex data. If you manage to get your display code to use templates, you will have saved a lot of coding. Since templates are not necessary for most extensions and they're a complicated subject, it's better that you read it from the experts. There's a very detailed <a href="/en/XUL/Template_Guide" title="en/XUL/Template Guide">XUL Template Guide here</a>. As mentioned before, it revolves around RDF, so you may need to take some time to understand how RDF works. There's a section about <a href="/en/XUL/Template_Guide/SQLite_Templates" title="en/XUL/Template Guide/SQLite Templates">SQLite Templates</a> in the guide, but there are some concepts in it that will require you to read at least some of the rest of it.</p> - -<p>{{ PreviousNext("Escuela_XUL/Manejo_de_preferencias", "Escuela_XUL/Interceptando_cargas_de_página") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/apéndice_a_colon__rendimiento_de_los_add-ons/index.html b/files/es/mozilla/tech/xul/escuela_xul/apéndice_a_colon__rendimiento_de_los_add-ons/index.html deleted file mode 100644 index 74a50cf7a2..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/apéndice_a_colon__rendimiento_de_los_add-ons/index.html +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: 'Apéndice A: Rendimiento de los Add-ons' -slug: 'Mozilla/Tech/XUL/Escuela_XUL/Apéndice_A:_Rendimiento_de_los_Add-ons' -translation_of: 'Archive/Add-ons/Overlay_Extensions/XUL_School/Appendix_A:_Add-on_Performance' ---- -<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}}{{AddonSidebar}}</p> - -<div class="note"><strong>Note:</strong> See the newer article <a href="/en/Extensions/Performance_best_practices_in_extensions" title="en/Extensions/Performance best practices in extensions">Performance best practices in extensions</a> for more up-to-date information about how to optimize the performance of your add-on.</div> - -<p>Add-ons can have a noticeable performance impact on Firefox. This is evident when opening a Firefox profile that has many add-ons installed; some profiles can take minutes to load, which is a serious inconvenience for users that gives them a negative view of Firefox. Add-on developers need to make sure that they minimize their add-ons' performance impact, and here are a few simple guidelines that should be followed to achieve that.</p> - -<h2 id="Startup">Startup</h2> - -<p>This is the area where add-ons have the most noticeable impact. Most add-ons use the load event handler in the main overlay to initialize their objects and sometimes read files or even fetch remote data. The problem with the <em>onload</em> event is that it runs before the main window becomes visible, so all handlers need to complete before the user can see the window. An add-on can normally add a few hundred milliseconds to startup time because of the load handler, and it's not hard to figure out what having several add-ons will do.</p> - -<p>Luckily, minimizing your startup time is easy, if you follow these guidelines:</p> - -<ol> - <li>Do not load or run code before it’s needed. Add-ons can have extra features that are only available depending on user preferences. Other add-ons have most of their features depend on a user being logged in to a service. Don’t load at startup something you won’t need at the time.</li> - <li><a href="/../../../../en/Using_JavaScript_code_modules" title="../../../../en/Using_JavaScript_code_modules">JavaScript Code Modules</a>. Use them. JSM provide the cleanest way to separate JS into modules that can be loaded on request, unlike chrome scripts which are generally loaded with the overlay at startup. Keep as much of your code in JSM, make it as modular as you can, and only load modules as you require them. If your add-on is too simple for JSM, don’t worry about it. There’s still one more thing you can do.</li> - <li>Do as little as possible in your load handler. Ask yourself: is there anything I can’t run 100 ms or even 500 ms later? If there is, just use an <a href="/../../../../En/nsITimer" title="../../../../En/nsITimer">nsITimer</a> or the <a href="/../../../../en/DOM/window.setTimeout" title="../../../../en/DOM/window.setTimeout">setTimeout</a> function to delay running this code . The Firefox window will be able to load sooner and your startup code will run almost instantaneously afterward, in parallel with the loading of the homepage or the saved tab session. The browser will now load faster, and your code will still load at startup for all practical purposes. The code is simple enough:</li> -</ol> - -<pre class="brush: js">// this is the function that is called in the load event handler. -init : function() { - let that = this; - // run this later and let the window load. - window.setTimeout(function() { that.postInit(); }, 500); -}, - -postInit: function() { - // actual init code goes here. -}, -</pre> - -<p>How can you tell it works? The <a class="link-https" href="https://wiki.mozilla.org/Firefox/Projects/StartupPerformance/MeasuringStartup" title="https://wiki.mozilla.org/Firefox/Projects/StartupPerformance/MeasuringStartup">Measuring Startup</a> wiki page includes a relatively simple test you can use to compare a clean Firefox profile vs that profile with your add-on installed.</p> - -<h2 id="Page_Loads">Page Loads</h2> - -<p>This is another critical route that many add-ons tap into. The <a href="/en/XUL_School/Intercepting_Page_Loads" title="en/XUL School/Intercepting Page Loads">Intercepting Page Loads</a> section details several techniques to do this, and you should read all of them carefully to figure out which one you need. Some of these events are fired multiple times during a single page load, and having inefficient code in the event handlers can cause a noticeable delay that users may have hard time figuring out.</p> - -<p>Look at the source samples in the article and notice how they mostly consist of nested <em>if</em> statements. This is what you should do <strong>first</strong> to make sure that you filter out all cases that don't interest you so that your add-on doesn't slow down other requests. A very common filter is the URL of the page, since most add-ons are limited to one or a few domains. Use regular expressions if you need to. Make sure your comparison code is as efficient as possible.</p> - -<p>Finally, make sure all of your page load code is as efficient as possible. This can be tricky for some add-ons, like ad or script blockers that need to check a whitelist or blacklist. Nevertheless, loading pages is pretty important in Firefox, and users expect it to be fast. Try your best to keep it that way.</p> - -<h2 id="Other_Recommendations">Other Recommendations</h2> - -<ul> - <li>Always clean up after yourself. Event listeners, observers and other handlers normally have both an add and a remove function. Don't forget to remove what you don't need anymore! Even if you need something during the whole existence of the window, you should clean everything up in the unload event handler.</li> - <li>Even the unload event should be handled efficiently. Even if it is not as important as other areas, Firefox shutdown can also be slowed down because of add-ons. If there's anything you can unload before shutdown, or if there's anything you can do to unload things more efficiently, then it's important that you do.</li> - <li><strong>Never</strong> use XMLHttpRequest in synchronous mode.</li> - <li>If your add-on needs to perform a heavy operation like sorting or a complex mathematical calculation, you should use <a href="/En/Using_web_workers" title="En/Using web workers">DOM Workers</a> to offload the work to other threads.</li> -</ul> diff --git a/files/es/mozilla/tech/xul/escuela_xul/apéndice_b_colon__instalar_y_desinstalar_scripts/index.html b/files/es/mozilla/tech/xul/escuela_xul/apéndice_b_colon__instalar_y_desinstalar_scripts/index.html deleted file mode 100644 index 4ee95d992b..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/apéndice_b_colon__instalar_y_desinstalar_scripts/index.html +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: 'Apéndice B: Instalar y desinstalar Scripts' -slug: 'Mozilla/Tech/XUL/Escuela_XUL/Apéndice_B:_Instalar_y_desinstalar_Scripts' -translation_of: >- - Archive/Add-ons/Overlay_Extensions/XUL_School/Appendix_B:_Install_and_Uninstall_Scripts ---- -<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}}{{AddonSidebar}}</p> - -<p>Add-ons normally run code at startup, and as it is covered in the main tutorial, all you need is a <em>load</em> event handler and a little code. It is also common for an add-on to require to run a script only when it is installed for the first time, or every time it is updated. It can be used to write or copy necessary files to the profile folder, like the initial DB the add-on will use for storage. A few others require cleanup code to be run after the add-on is uninstalled. This appendix covers these cases with simple code that should work for most add-ons.</p> - -<h2 id="Install_Scripts">Install Scripts</h2> - -<p>Just like with a regular initialization function, we want a <em>load</em> event handler:</p> - -<pre class="brush: js">// rest of overlay code goes here. -window.addEventListener( - "load", function() { XulSchoolChrome.BrowserOverlay.init(); }, false); -</pre> - -<p>Then all we need is some persistent flag that ensures that the first run code is only run once. The best approach in this case is to use a preference, as explained in the <a href="/en/XUL_School/Handling_Preferences" title="en/XUL School/Handling Preferences">Handling Preferences</a> section. So, if we were to use FUEL, we can do the following in the <em>init</em> function:</p> - -<pre class="brush: js">init : function() { - let firstRunPref = - Application.prefs.get("extensions.xulschoolhello.firstRunDone"); - - if (!firstRunPref.value) { - firstRunPref.value = true; - // all the rest of the first run code goes here. - } -} -</pre> - -<p>In this case you would need to declare the first run preference in your default preferences file, with a default value of <em>false</em>. You should also change the preference value before you run any other first run code. Keep in mind that the user could have set multiple Firefox windows to open at startup, so there's a race condition on which window will run the first run code.</p> - -<p>If you need to run code on every update, or some of them, the code would be very similar. Instead of a boolean preference, it would be best to use a string preference with the last-installed add-on version. And then do a version comparison to decide which code to run. The current version number can be hard-coded in the first run function, or you can use the Add-on Manager to dynamically get it. This can get tricky with the <a href="/en/Addons/Add-on_Manager/AddonManager" title="en/Addons/Add-on Manager/AddonManager">Firefox 4 AddonManager</a>, so it's probably best to keep it simple.</p> - -<h2 id="Uninstall_Scripts">Uninstall Scripts</h2> - -<p>There are two common cases for needing these: cleaning up local data and presenting an uninstall feedback form. Regarding local data, it is debatable if it is good practice to remove it or not. If an add-on is uninstalled and later installed again, it might be desirable for preferences and other settings to be kept. Another argument in favor of keeping that data is that Firefox doesn't delete its profile folders after it is uninstalled, so it would be consistent to keep it. On the other hand, local data that is no longer needed takes unnecessary disk space and can contain private information that users forget is there. It's up to the developer's discretion.</p> - -<p>Uninstalling an add-on happens in 2 stages: first the add-on is flagged to be uninstalled, and then the add-on is actually removed. In the case of <a href="/en/Extensions/Bootstrapped_extensions" title="en/Extensions/Bootstrapped extensions">Bootstrapped Extensions</a>, both steps happen at the same time. In the case of "traditional" extensions, like those explained in the tutorial, both steps happen at different times. In this case the user is told that Firefox needs to restart in order for the extension to be completely removed. Then the user has the option to restart right away, wait to restart whenever is convenient, or even cancel the uninstall operation. The add-on will not be completely removed until the browser is restarted.</p> - -<p>So, in order to detect the first stage, you'll need to add an event listener using the <a href="/en/Addons/Add-on_Manager/AddonManager#addAddonListener%28%29" title="en/Addons/Add-on Manager/AddonManager#addAddonListener()">addAddonListener</a> method. The data parameter explains the action being performed.</p> - -<p>If you detect your add-on is going to be uninstalled at this stage, it's a good time to show the uninstall feedback form. It is <strong>not</strong> a good time to clean up your files, at least not without prior user consent. Remember that the user can revert this decision. So, you should listen to other events, like canceling the operation, to make sure that you know what is going on. Set a boolean flag that indicates if your add-on is set to be uninstalled or not, and reset it when necessary.</p> - -<p>The second stage is knowing when the application is actually going to be closed. Then you'll have reasonable certainty that the add-on will be removed and you can perform any cleanup operations safely. For this, you need to add an observer for the <a href="/en/Observer_Notifications#Application_shutdown" title="en/Observer Notifications#Application shutdown">quit-application</a> topic. This is when you'll know the application will close. Then you can check the flag you set up on the first stage and perform any necessary deletions. You shouldn't perform very time-consuming operations here, at least not without telling users what is going on.</p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/apéndice_c_colon__evitar_usar_eval_en_los_add-ons/index.html b/files/es/mozilla/tech/xul/escuela_xul/apéndice_c_colon__evitar_usar_eval_en_los_add-ons/index.html deleted file mode 100644 index 1fb0b53d94..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/apéndice_c_colon__evitar_usar_eval_en_los_add-ons/index.html +++ /dev/null @@ -1,210 +0,0 @@ ---- -title: 'Apéndice C: Evitar usar eval en los Add-ons' -slug: 'Mozilla/Tech/XUL/Escuela_XUL/Apéndice_C:_Evitar_usar_eval_en_los_Add-ons' -translation_of: >- - Archive/Add-ons/Overlay_Extensions/XUL_School/Appendix_C:_Avoid_using_eval_in_Add-ons ---- -<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}}{{AddonSidebar}}</p> - -<p>Using <code>eval</code> in extensions is almost always unnecessary, and many times even a security vulnerability. Moreover, code using <code>eval</code> is harder to parse for a human mind, is often pretty complex, and relies on assumptions that are not necessarily true in the future or even now.</p> - -<p>This article is aimed at presenting alternatives to common <code>eval</code> uses in add-ons and other Javascript code.</p> - -<p>Add-on authors are strongly encouraged to update their code to eliminate all use of <code>eval</code>, no matter if the add-on is to be hosted in the <a class="link-https" href="https://addons.mozilla.org/" title="https://addons.mozilla.org/">Mozilla Add-ons Gallery </a>or not. In order to host your add-on with Mozilla it is crucial to minimize or completely eliminate <code>eval</code> use in order to receive a positive review and have your add-on made public.</p> - -<h2 id="Parsing_JSON">Parsing JSON</h2> - -<p>Mozilla provides native JSON support since Firefox 3. There is simply no need to parse JSON using <code>eval</code>. Additionally, parsing JSON retrieved from a remote location becomes a security vulnerability when parsed with the <code>eval</code> function. Basically, you are executing remote code with full chrome access; that is, introducing a remote code execution vulnerability. Even if you trust the remote server; for example, because it is one you rent and administer yourself, there is a huge security risk, because of, but not limited to:</p> - -<ul> - <li>You might discontinue your project or sell it, so that it is possible another person with malicious intentions takes over your domain.</li> - <li>The server and/or domain name might be compromised.</li> - <li>If using an unencrypted, insecure connection, a Man-in-the-middle attacker might replace the JSON with attack code before it arrives at the user.</li> -</ul> - -<h3 id="Use_Native_JSON">Use Native JSON</h3> - -<p>Since Firefox 3.5 you should <a href="/En/Using_native_JSON" title="en/Using native JSON">use native JSON</a>. In Firefox 3.0, you may take a look at {{ Interface("nsIJSON") }} instead. Using native JSON has the added benefit that it is better when validating the input and also a lot faster.</p> - -<div class="note"><strong>Note:</strong> Do not use JSON parsers implemented in Javascript. These implementations are less efficient and often also contain serious security vulnerabilities. Such implementations are meant to be used within a very different security context, namely a website, where the origin of the data is usually known in all instances and where vulnerabilities would have a much smaller impact.</div> - -<h2 id="Passing_around_functionscode_as_strings">Passing around functions/code as strings</h2> - -<p>Often you'll want to pass functions or code to other functions, most notoriously <a href="/en/DOM/window.setTimeout" title="en/DOM/window.setTimeout">setTimeout</a> and <a href="/en/DOM/element.addEventListener" title="en/DOM/element.addEventListener">addEventListener</a>. Often this is achieved by a hack "function/code as string" technique.</p> - -<pre class="brush: js">// DO NOT USE -setTimeout("doSomething();", 100); -addEventListener("load", "myAddon.init(); myAddon.onLoad();", true); -setInterval(am_I_a_string_or_function_reference_qmark, 100); -</pre> - -<p>That in itself is certainly not elegant, but it may also become a security issue if you construct the passed code with externally provided data:</p> - -<pre class="brush: js">// DO NOT USE -setTimeout("alert('" + xhr.responseText + "');", 100); -// Attacker manipulated responseText to contain "attack!'); format_computer(); alert('done" -setTimeout("alert('attack!'); format_computer(); alert('done');", 100); -</pre> - -<p>As a general rule of thumb, just don't pass code around as strings and execute it by calling <code>eval</code>, <code>setTimeout</code> and friends.</p> - -<h3 id="Alternative_Use_(anonymous)_functions">Alternative: Use (anonymous) functions</h3> - -<p>You can always create a small anonymous function to pass around instead. Closures will ensure the code is still valid, even if your outer function already returned from execution.</p> - -<pre class="brush: js">addEventListener("load", function() { myAddon.init(); myAddon.onLoad(); }, true); -function doXHR() { - //... - var response = xhr.responseText; - setTimeout(function() { alert(response); }, 100); -} -</pre> - -<h3 id="Alternative_Use_Function.bind">Alternative: Use Function.bind</h3> - -<p>Function.bind is a new utility function that you may use to (partially) bind parameters to functions.</p> - -<pre class="brush: js">addEventListener("load", myAddon.init.bind(myAddon), true); -setTimeout(alert.bind(null, xhr.responseText), 100); -</pre> - -<h2 id="OverridingExtending_existing_functions">Overriding/Extending existing functions</h2> - -<p>A common thing add-ons do during their initialization is overriding/extending existing browser functions by using <code>Function.toString</code>/<code>Function.toSource</code> and <code>eval</code> to "string-patch" the function body.</p> - -<pre class="brush: js">// DO NOT USE -var functionBody = gBrowser.addTab.toSource(); -var afterBracket = functionBody.indexOf("{"} + 1; -functionBody = functionBody.substring(0, afterBracket) + "myAddon.onAddTab(aURI);" + functionBody.substring(afterBracket); -eval("gBrowser.addTab = " + functionBody); -</pre> - -<p>Of course, this not only looks messy, but can be quite error prone.</p> - -<ul> - <li>Other extensions might do something similar, but a little different, ending up with completely broken code.</li> - <li>The code is hard to read and by that hard to maintain and review. (The example is a quite simple one. In real life such code is often far more complex)</li> - <li>The code might break in the future, as certain assumptions might not longer be true, for example the function signature may change (aURI from above becomes aURL) or the function is replaced by a shorthand not containing bracket: - <pre class="brush: js">function addTab(aURI) tabBrowser.addTab(aURI); - </pre> - </li> -</ul> - -<p>Like with "Passing functions/code as strings" above, patching function to include some external data will create security vulnerabilities.</p> - -<h3 id="Alternative_Replace_Function.apply">Alternative: Replace + Function.apply</h3> - -<p>You may replace the original function with a new function, keeping a reference to the original function which you then call from the new one.</p> - -<pre class="brush: js">(function() { - var _original = gBrowser.addTab; // Reference to the original function - gBrowser.addTab = function() { - // Execute before - try { - myAddon.onAddTab(arguments[0]); - } catch (ex) { /* might handle this */ } - // Execute original function - var rv = _original.apply(gBrowser, arguments); - // execute afterwards - try { - myAddon.doneAddTab(rv); - } catch (ex) { /* might handle this */ } - - // return the original result - return rv; - }; -})(); -</pre> - -<p>This is admittedly more verbose, but at the same time it should be easier to understand.</p> - -<ul> - <li>You don't have to parse in your mind what the resulting function will look like.</li> - <li>There won't be any problems if various Add-ons employ this method with the same function.</li> - <li>You don't have to care about parameter naming or short-hand functions.</li> -</ul> - -<div class="note"><strong>Note:</strong> It is not safe to remove such an override again, as this method constitutes in a single-linked function chain. If you want to disable your overrides again, then use a flag indicating that, or similar. At the same time, it is also not safe to "un-string-patch" a function, for the exact same reason.</div> - -<div class="note"><strong>Note:</strong> There are still some scenarios where incompatibilities may arise, such as trying to cancel the function call under a certain set of conditions when other Add-ons have overridden the same function. Again, this is a problem with the "string-patch" method, too. How to handle this is inter-Add-on specific and not addressed in this article.</div> - -<h2 id="Triggering_event_handlers">Triggering event handlers</h2> - -<p>Sometimes scripts might want to manually trigger an event handler that is defined directly in the XUL document. Consider the following XUL fragment throughout the rest of this section.</p> - -<pre class="brush: xml"><menuitem id="mymenu" oncommand="executeSomething; executeSomethingElse();"/> -<label id="mylabel" onclick="executeSomething; executeSomethingElse();"/> -</pre> - -<p>Add-on authors commonly use <code>eval</code> to trigger the handlers.</p> - -<pre class="brush: js">// DO NOT USE -eval(document.getElementById("mymenu").getAttribute("oncommand")); -eval(document.getElementById("mylabel").getAttribute("onclick")); -</pre> - -<h3 id="Alternative_Dispatch_real_events">Alternative: Dispatch real events</h3> - -<p>Dispatching real events has the added bonus that all other event listeners for that Element (and the corresponding bubbling/capturing chain) will fire as well, so this method will have the closed resemblance to a real user event.</p> - -<pre class="brush: js">// Fake a command event -var event = document.createEvent("Events"); -event.initEvent("command", true, true); -document.getElementById("mymenu").dispatchEvent(event); - -// Fake a mouse click -var mouseEvent = document.createEvent("MouseEvents"); -event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); -document.getElementById("mylabel").dispatchEvent(mouseEvent); -</pre> - -<p>Please see the corresponding documentation on how to use and initialize particular event types.</p> - -<h3 id="Alternative_Element.doCommand()">Alternative: Element.doCommand()</h3> - -<p>Elements that have a command (<code>oncommand</code>) assigned will also have a working <code>doCommand</code> method.</p> - -<pre class="brush: js">document.getElementById("mymenu").doCommand(); -</pre> - -<h2 id="Accessing_properties_via_computed_names">Accessing properties via computed names</h2> - -<p>Not that common anymore, but still existing, are Add-Ons or other Javascript programs that access object properties using <code>eval</code> when the property name is not a literal, but computed on the fly.</p> - -<pre class="brush: js">//DO NOT USE -eval("myAddon.phrases.word" + word + " = '" + phrase + "';");</pre> - -<p>Again, this is not only unnecessarily hard to parse for a human, but may also contain security vulnerabilities if you compute the names using external data.</p> - -<h3 id="Alternative_Using_bracket-access_to_object_properties">Alternative: Using bracket-access to object properties</h3> - -<p>Object properties can always accessed using the bracket syntax:</p> - -<pre class="brush: js">obj["property"] === obj.property -</pre> - -<p>Hence the following will just work without having to resort to <code>eval</code>.</p> - -<pre class="brush: js">myAddon.phrases["word" + word] = "phrase"; -</pre> - -<h2 id="Special_thanks">Special thanks</h2> - -<p>Special thanks goes to Wladimir Palant of Adblock Plus, who wrote <a class="link-https" href="https://adblockplus.org/blog/five-wrong-reasons-to-use-eval-in-an-extension" title="https://adblockplus.org/blog/five-wrong-reasons-to-use-eval-in-an-extension">an article</a> years back which heavily inspired this one.</p> - -<h2 id="See_also">See also</h2> - -<ul> - <li><a href="/En/Using_native_JSON" title="en/Using native JSON">Native JSON</a></li> - <li>{{ Interface("nsIJSON") }}</li> - <li><a href="/en/JSON" title="en/JSON">JSON</a></li> - <li><a href="/en/JavaScript/Reference/Global_Objects/Function/bind" title="en/JavaScript/Reference/Global Objects/Function/bind">Function.bind</a></li> - <li><a href="/en/JavaScript/Reference/Global_Objects/Function/apply" title="en/JavaScript/Reference/Global Objects/Function/apply">Function.apply</a></li> - <li><a href="/en/XUL/Method/doCommand" title="en/XUL/Method/doCommand">Element.doCommand</a></li> - <li><a href="/en/DOM/document.createElement" title="en/DOM/document.createElement">document.createEvent</a></li> - <li><a href="/en/DOM/event.initEvent" title="en/DOM/event.initEvent">event.initEvent</a></li> -</ul> diff --git a/files/es/mozilla/tech/xul/escuela_xul/apéndice_d_colon__cargar_scripts/index.html b/files/es/mozilla/tech/xul/escuela_xul/apéndice_d_colon__cargar_scripts/index.html deleted file mode 100644 index e282486a46..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/apéndice_d_colon__cargar_scripts/index.html +++ /dev/null @@ -1,304 +0,0 @@ ---- -title: 'Apéndice D: Cargar Scripts' -slug: 'Mozilla/Tech/XUL/Escuela_XUL/Apéndice_D:_Cargar_Scripts' -translation_of: 'Archive/Add-ons/Overlay_Extensions/XUL_School/Appendix_D:_Loading_Scripts' ---- -<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}}{{AddonSidebar}}</p> - -<p>Most add-ons and XUL Runner applications provide their primary functionality by loading and executing JavaScript code. Because there are such a diverse array of add-ons, and because the needs of developers have grown organically over time, the Gecko runtime provides a number of means to dynamically load and execute JavaScript files. Each of these means has its own advantages and disadvantages, as well as its own quirks which may trap the unwary. Below is an overview of the more common means of loading scripts, along with some of their primary advantages, disadvantages, quirks, and use cases.</p> - -<p>The examples below which make use of the <code>Services</code> global assume that you're previously imported the <a href="/en/JavaScript_code_modules/Services.jsm" title="en/JavaScript_code_modules/Services.jsm">Services.jsm</a> module. As this module only exists on Firefox 4 and other Gecko 2-based platforms, the services in question will have to be manually loaded on other platforms.</p> - -<p> </p> - -<h2 id="<script>_tags"><script> tags</h2> - -<p> </p> - -<p>XUL <a href="/en/XUL/script" title="en/XUL/script">script tags</a> are traditionally the primary means of loading scripts for extension developers. These tags are generally inserted into XUL overlay files or other XUL documents, after which they are automatically loaded into the context of the XUL window in question and executed immediately and synchronously.</p> - -<h3 id="Advantages">Advantages</h3> - -<ul> - <li><strong>Familiarity:</strong> These tags are very similar to the HTML script tags familiar to most web developers.</li> - <li><strong>Simplicity:</strong> The simple, declarative nature of these tags make them easy to find and understand at a glance.</li> - <li><strong>Speed:</strong> Script tags may or may not be loaded from pre-compiled bytecode in the fastload cache (Gecko 1.x) or startup cache (Gecko 2), which means they don't necessarily need to read as source and compiled with each restart.</li> - <li><strong>Flexibility:</strong> Script tags provide a means to specify the character set and JavaScript version of the scripts to be loaded, which many other methods do not.</li> - <li><strong>Debuggable</strong>: development tools support debugging JavaScript loaded by script tags</li> -</ul> - -<h3 id="Disadvantages">Disadvantages</h3> - -<ul> - <li><strong>Scoping:</strong> Scripts loaded via script tags share the global scope with all other scripts loaded into the same window. These tags provide no means to load scripts into a private or otherwise specific scope.</li> - <li><strong>Speed:</strong> Even if these scripts are loaded from a cache, only read and compile time are reduced. The scripts still need to execute all of their initialization code and allocate and initialize all of their data structures each time the script is loaded.</li> - <li><strong>Loading:</strong> Script loaded via script tags run in partially loaded documents. Problems can ensue if the script immediately attempts to access DOM nodes. This is easily resolved by deferring the work to a dynamically added onload hander. (A standalone XUL window can use an onload attribute.)</li> -</ul> - -<h3 id="Example">Example</h3> - -<p>The following overlay will load the script “overlay.js” from the same directory as the overlay file into the window which it overlays. The script will be read with the UTF-8 encoding, based on the encoding of the overlay, and will execute as JavaScript <a href="/en/JavaScript/New_in_JavaScript/1.8" title="en/JavaScript/New_in_JavaScript/1.8">version 1.8</a>, based on the version specified in the script tag.</p> - -<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?> - -<!DOCTYPE overlay> - -<overlay id="script-overlay" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - - <script type="application/javascript;version=1.8" src="overlay.js"/> - -</overlay></pre> - -<h2 id="evalInSandbox">evalInSandbox</h2> - -<p>The <a href="/en/Components.utils.evalInSandbox" title="en/Components.utils.evalInSandbox"><code>Components.utils.evalInSandbox</code></a> method may be used to load arbitrary code into <a href="/en/Components.utils.Sandbox" title="en/Components.utils.Sandbox"><code>Components.utils.Sandbox</code></a> objects. JavaScript files or URLs may be loaded in this manner by first retrieving their contents into memory using an <a href="/en/nsIXMLHttpRequest" title="en/XMLHttpRequest"><code>XMLHttpRequest</code></a>. This is the method used by Jetpack's securable module system to load nearly all executable code.</p> - -<h3 id="Advantages_2">Advantages</h3> - -<ul> - <li><strong>Namespacing</strong>: Since scripts executed via <code>evalInSandbox</code> run in a defined namespace, global namespace contamination and the resultant extension compatibility issues are not usually a problem.</li> - <li><strong>Flexibility:</strong> The <code>evalInSandbox</code> method accepts several parameters, including the URL, line number, and JavaScript version of the file from which the code being evaluated was extracted. This information is invaluable for debugging, and the flexibility with which it can be specified makes this method useful for extracting JavaScript from a number of file formats other than raw JavaScript scripts. Additionally, as Sandbox objects can be created with an arbitrary prototype object, the evaluated code can be given access to the global properties of any existing scope.</li> - <li><strong>Security:</strong> <code>Sandbox</code> objects are initialized with a security principal object, or otherwise a window or URL from which to derive one. This means that <code>evalInSandbox</code> can be used to execute code with a specified privilege level rather than full chrome privileges. Beyond this, the scope of the Sandbox can be augmented or rarified to add or remove privileges as necessary. Under ordinary circumstances, native objects passed out of Sandboxes are wrapped in <a href="/en/XPConnect_security_membranes#section_2" title="en/XPConnect_security_membranes#section_2"><code>XrayWrapper</code></a> objects, which means that only native properties of these objects are directly exposed to privileged code. This behavior can be reversed by setting the <code>wantsXrays</code> parameter to false when constructing the <code>Sandbox</code>.</li> -</ul> - -<h3 id="Disadvantages_2">Disadvantages</h3> - -<ul> - <li><strong>Performance:</strong> There are several significant performance disadvantages inherent in this method: - - <ul> - <li>There is currently no way to load code into sandboxes from a cache. This means that code must be compiled and executed anew each time it is loaded, which has a significant overhead for large code bases.</li> - <li>In addition to compile time, reading files synchronously from disk has its own overhead, and <code>XMLHttpRequests</code> have significantly more overhead than native loading methods.</li> - <li>Although wary authors can choose to cache instances of their modules so that modules are loaded only once globally, this method can be easily misused to re-load scripts for each new window where they would be better loaded only once globally per session.</li> - <li>Because Sandbox objects are evaluated in their own <a href="/en/XPConnect_security_membranes" title="en/XPConnect_security_membranes">javascript compartment</a>, they are separated by a membrane from other JavaScript code. This means that any and all JavaScript objects passed in our out of them are wrapped in inter-compartment Proxy objects, which consume additional memory and add an extra layer of complexity to all property accesses and method calls.</li> - </ul> - </li> - <li><strong>JavaScript compartments</strong>: As noted above, each Sandbox executes in its own <a href="/en/XPConnect_security_membranes" title="en/XPConnect_security_membranes">javascript compartment</a>. In addition to the possible performance concerns, passing data between these compartments is not entirely transparent. Some known issues include: - <ul> - <li>E4X XML objects cannot be wrapped for passage between compartments: {{ Bug(613142) }}</li> - <li>There are a number of type detection issues, including: - <ul> - <li>String.replace does not recognize RegExp objects from foreign compartments: {{ Bug(633830) }}</li> - </ul> - </li> - </ul> - </li> - <li><strong>Debugging:</strong> Support for Sandbox evaluation in development tools is uneven. Chromebug supports Firebug based Sandboxes.</li> -</ul> - -<h3 id="Examples">Examples</h3> - -<p>The following code will execute a simple script in a Sandbox with the privilege level of the current content page. The globals of the current content window will be available in the scripts global scope. In stack traces, the script will appear to have been loaded from the file "<code><span class="nowiki">zz-9://plural/zed/alpha</span></code>", line <code>42</code>.</p> - -<pre class="brush: js">// Use the current content window as the execution context. -// To make properties defined by scripts executing on the page -// available to your sandbox script, use content.wrappedJSObject -// instead. -let context = content; - -// Create the Sandbox -let sandbox = Components.utils.Sandbox(context, { - // Make properties of the context object available via the - // script's global scope - sandboxPrototype: context, - // Wrap objects retrieved from the sandbox in XPCNativeWrappers. - // This is the default action. - wantXrays: true -}); - -// The script that will be executed: -let script = String(); - -// Evaluate the script: -Components.utils.evalInSandbox(script, sandbox, - // The JavaScript version - "1.8", - // The apparent script filename: - "zz-9://plural/zed/alpha", - // The apparent script starting line number: - 42); -</pre> - -<p>The following code will execute a simple script loaded from a local file in the same directory as the current script. The script will execute in the same security context as the current script and will have access to the same globals, but any new globals it creates will be accessible only to the script itself. Objects passed out of the sandbox will not be wrapped in <a href="/en/XPCNativeWrapper" title="en/XPCNativeWrapper"><code>XPCNativeWrapper</code></a>s but will still be wrapped in inter-compartment proxies.</p> - -<pre class="brush: js">const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1", - "nsIXMLHttpRequest", - "open"); - -function loadScript(name, context) { - // Create the Sandbox - let sandbox = Components.utils.Sandbox(context, { - sandboxPrototype: context, - wantXrays: false - }); - - // Get the caller's filename - let file = Components.caller.stack.filename; - // Strip off any prefixes added by the sub-script loader - // and the trailing filename - let directory = file.replace(/.* -> |[^\/]+$/g, ""); - let scriptName = directory + name; - - // Read the script - let xmlhttp = XMLHttpRequest("GET", scriptName, false); - xmlhttp.overrideMimeType("text/plain"); - xmlhttp.send(); - let script = xmlhttp.textContent; - - // Evaluate the script: - Components.utils.evalInSandbox(script, sandbox, - "1.8", scriptName, 0); -} - - -// Use the current global object. -// The following may be used instead at the top-level: -// -// let context = this -if (Components.utils.getGlobalForObject) - // Gecko 2.x - var context = Components.utils.getGlobalForObject({}); -else - // Gecko 1.x - context = {}.__parent__; - -loadScript("script.js", context); -</pre> - -<h2 id="The_Sub-Script_Loader">The Sub-Script Loader</h2> - -<p>The {{ interface("mozIJSSubScriptLoader") }} can be used to load local scripts from the <code>chrome:</code>, <code>resource:</code>, and <code>file:</code> protocols into any JavaScript object. Any new globals created by this script are defined as properties of this object. Additionally, any properties of the target object are available as variables in the script's global namespace, along with as any properties of the global associated with the target object. These scripts execute with the same privileges and restrictions of the global associated with the target object, and this method can therefore also be used when with <a href="/en/Components.utils.Sandbox" title="en/Components.utils.Sandbox"><code>Sandbox</code></a> objects with the same effect as <a href="/en/Components.utils.evalInSandbox" title="en/Components.utils.evalInSandbox"><code>evalInSandbox</code></a> and into content windows with the same effect as injecting script tags into their documents.</p> - -<h3 id="Advantages_3">Advantages</h3> - -<ul> - <li><strong>Namespacing</strong>: Global namespace contamination and the resultant extension compatibility issues can often be avoided by loading sub-scripts into private namespaces.</li> - <li><strong>Flexibility</strong>: The sub-script loader can load scripts into a variety of different namespaces for a wide variety of uses, and as of Gecko 2 allows the character set of the script to be specified.</li> - <li><strong>Performance</strong>: As of Gecko 8.0, scripts loaded via {{ ifmethod("mozIJSSubScriptLoader", "loadSubScript") }} are loaded from a cache. Unlike modules, however, scripts are still executed each time they are loaded and therefore still suffer performance and memory disadvantages over that method.</li> - <li>When loading into a Sandbox object, the same advantages apply as above.</li> -</ul> - -<h3 id="Disadvantages_3">Disadvantages</h3> - -<ul> - <li><strong>Performance</strong>: Prior to Gecko 8.0, scripts loaded via {{ ifmethod("mozIJSSubScriptLoader", "loadSubScript") }} are not loaded from a cache, and therefore must be read and compiled each time they are loaded which has a significant overhead for large code bases. Although wary authors can choose to cache instances of their modules so that modules are loaded only once globally, this method can be easily misused to re-load scripts for each new window where they would be better loaded only once globally per session.</li> - <li>Non-chrome files loaded in this manner will have the current filename prefixed to the filename in their debugging information. For instance, the file “<code><span class="nowiki">resource://foo/bar.js</span></code>” loaded from “<code><span class="nowiki">resource://foo/baz.js</span></code>” will appear as “<code><span class="nowiki">resource://foo/baz.js -> resource://foo/bar.js</span></code>” in stack traces.</li> - <li>When loading into a Sandbox object, the same disadvantages apply as above.</li> -</ul> - -<h3 id="Examples_2">Examples</h3> - -<p>The following code will load a script into its own context. The script will execute with the security principal of and have access to the global properties of the current global.</p> - -<pre class="brush: js">let context = {}; -Services.scriptloader.loadSubScript("chrome://my-package/content/foo-script.js", - context, "UTF-8" /* The script's encoding */); -</pre> - -<p>The following code will execute a simple script loaded from a local file in the same directory as the current script. The script will execute in the same security context as the current script and will have access to the same globals, but any new globals it creates will be accessible only to the script itself. Objects passed out of the sandbox will not be wrapped in <code>XPCNativeWrapper</code>s but will still be wrapped in inter-compartment proxies.</p> - -<pre class="brush: js">function loadScript(name, context) { - // Create the Sandbox - let sandbox = Components.utils.Sandbox(context, { - sandboxPrototype: context, - wantXrays: false - }); - - // Get the caller's filename - let file = Components.caller.stack.filename; - // Strip off any prefixes added by the sub-script loader - // and the trailing filename - let directory = file.replace(/.* -> |[^\/]+$/g, ""); - - Services.scriptloader.loadSubScript(directory + name, - sandbox, "UTF-8"); -} - -loadScript("foo.js", this); -</pre> - -<h2 id="JavaScript_modules">JavaScript modules</h2> - -<p><a href="/en/JavaScript_code_modules/Using" title="en/JavaScript_code_modules/Using">JavaScript modules</a> are used to efficiently load scripts into their own global namespaces. Because these scripts are loaded from a bytecode cache, and the same scripts are loaded only once per session no matter how many times they are imported, this is one of the most performant methods of script loading.</p> - -<h3 id="Advantages_4">Advantages</h3> - -<ul> - <li><strong>Performance</strong>: JavaScript modules are stored in a pre-compiled format in a cache, and therefore load with significantly less overhead than other types of scripts. Additionally, scripts are loaded only once globally per session, and therefore have virtually no overhead for multiple imports.</li> - <li><strong>Namespacing</strong>: JavaScript modules, like JavaScript components, are loaded into their own private scope. Namespace contamination and the resulting compatibility issues are only an issue when they are imported into shared global namespaces.</li> - <li><strong>Data sharing</strong>: As modules are loaded only once globally, every import has access to the same data and global variables no matter what context or window it was imported from. JavaScript modules can therefor be used for communication and data sharing between otherwise isolated contexts.</li> - <li><strong>Debugging</strong>: Chromebug (at least) can list Component.utils modules and single step through them.</li> -</ul> - -<h3 id="Disadvantages_4">Disadvantages</h3> - -<ul> - <li><strong>Namespacing:</strong> As modules always execute with their own namespace, they have no direct access to the DOM or window properties of windows or documents, and therefore must often pass around references to these objects and any document-specific state data that they require.</li> -</ul> - -<h3 id="Examples_3">Examples</h3> - -<p>The following code will import a module into the current global scope. All variables named in the target script's EXPORTED_SYMBOLS global array will be copied into the current execution context.</p> - -<pre class="brush: js">Components.utils.import("resource://my-package/my-module.jsm"); -</pre> - -<p>The following function will import an arbitrary module into a singleton object, which it returns. If the argument is not an absolute path, the module is imported relative to the caller's filename.</p> - -<pre class="brush: js">function module(uri) { - if (!/^[a-z-]+:/.exec(uri)) - uri = /([^ ]+\/)[^\/]+$/.exec(Components.stack.caller.filename)[1] + uri + ".jsm"; - - let obj = {}; - Components.utils.import(uri, obj); - return obj; -} -</pre> - -<p>Given the above code, the following code will import the module "my-module.jsm" from the current directory and define the symbols <code>foo</code> and <code>bar</code> from that module in the current scope. It will also import the symbol <code>Services</code> from the standard <code>Services.jsm</code> module.</p> - -<pre class="brush: js">const { Services } = module("resource://gre/modules/Services.jsm"); -const { bar, foo } = module("my-module"); -</pre> - -<h2 id="DOM_Workers_Worker_and_ChromeWorker">DOM Workers: Worker and ChromeWorker</h2> - -<p><a href="/En/Using_workers_in_extensions" title="En/Using_workers_in_extensions">DOM Workers</a> can be used to load scripts into their own global contexts which run in their own threads. In order to ensure thread safety, these contexts are extremely limited, can't be passed JavaScript objects, and have no access to the DOM. All communication between these contexts and outer contexts is marshalled through <a href="/en/JSON" title="en/JSON">JSON</a> encoding and decoding. <a href="/en/DOM/ChromeWorker" title="en/DOM/ChromeWorker"><code>ChromeWorker</code></a>s also have access to <code>ctypes</code> and a limited number of thread safe XPCOM classes, but are otherwise limited to simple computation based on data passed via messages and <code>XMLHttpRequests</code>.</p> - -<h3 id="Advantages_5">Advantages</h3> - -<ul> - <li><strong>Asynchronous</strong>: Workers execute asynchronously in their own threads, which means that they have limited risk of interfering with the main thread. They may safely perform synchronous <code>XMLHttpRequests</code> or other intensive computation which would normally need to be broken up into multiple callbacks.</li> - <li><strong>Safety</strong>: As workers have no access to objects which might cause a crash or deadlock when executed re-entrantly or by spinning the event loop, there are significant safety advantages over other methods of asynchronous execution.</li> -</ul> - -<h3 id="Disadvantages_5">Disadvantages</h3> - -<ul> - <li><strong>Limited scoping:</strong> As data from the main thread may only be accessed via JSON message passing, there are significant difficulties in performing many operations in Worker scopes.</li> - <li><strong>DOM Access</strong>: As there is no DOM access in Worker scopes, <code>XMLHttpRequests</code> may not easily be used with XML or HTML sources, and should instead only be used with JSON or other text-based sources.</li> - <li><strong>Debugging</strong>: JSD knows nothing about Workers and no JavaScript debuggers work on them.</li> -</ul> - -<h2 id="Jetpack_Processes">Jetpack Processes</h2> - -<p><a href="/en/Jetpack_Processes" title="en/Jetpack_Processes"><code>nsIJetpack</code> classes</a> are very similar to DOM workers, except that modules execute in entirely separate processes rather than separate threads. Additionally, rather than directly loading files, scripts are executed by evaluating strings.</p> - -<h3 id="Advantages_6">Advantages</h3> - -<ul> - <li><strong>Stability:</strong> As code running in Jetpack processes is isolated from the main process, crashes in these processes are unlikely to bring down the main process as well, though they may put a halt to functionality provided by the script or any functionality reliant on it.</li> - <li>The advantages of DOM Workers listed above also apply to Jetpack processes</li> -</ul> - -<h3 id="Disadvantages_6">Disadvantages</h3> - -<ul> - <li><strong>Performance:</strong> As scripts must be evaluated from strings, they are impossible to cache, which has significant performance implications for large code bases.</li> - <li>The disadvantages of DOM Workers listed above also apply to Jetpack processes</li> -</ul> diff --git a/files/es/mozilla/tech/xul/escuela_xul/apéndice_e_colon__dom_e_inserción_html/index.html b/files/es/mozilla/tech/xul/escuela_xul/apéndice_e_colon__dom_e_inserción_html/index.html deleted file mode 100644 index 66073bcc6b..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/apéndice_e_colon__dom_e_inserción_html/index.html +++ /dev/null @@ -1,244 +0,0 @@ ---- -title: 'Apéndice E: DOM e inserción HTML' -slug: 'Mozilla/Tech/XUL/Escuela_XUL/Apéndice_E:_DOM_e_inserción_HTML' -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/DOM_Building_and_HTML_Insertion ---- -<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}}{{AddonSidebar}}</p> - -<p>Many add-ons need to dynamically generate DOM content, either XUL or HTML, from their scripts. For security reasons, and to prevent errors, care needs to be taken to avoid evaluating arbitrary text as HTML. Failure to do so can lead to execution or remote scripts, and in the worst cases to privilege escalation which can leave a user's PC open to remote attack.</p> - -<h2 id="Building_DOM_Trees">Building DOM Trees</h2> - -<p>In most cases, DOM trees should be built exclusively with DOM creation methods. The following methods will all safely create a DOM tree without risk of remote execution.</p> - -<h3 id="E4X_Templating">E4X Templating</h3> - -<p>The following function can be used to generate DOM nodes from <a href="/en/E4X" title="en/E4X">E4X</a> XML objects. It has the advantage of appearing identical to ordinary HTML, but the disadvantage of being nearly exclusive to Firefox.</p> - -<pre class="brush: js">var HTML = Namespace("html", "http://www.w3.org/1999/xhtml"); -var XUL = Namespace("xul", "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); - -default xml namespace = HTML; -function xmlToDOM(xml, doc, nodes) { - if (xml.length() != 1) { - let domnode = doc.createDocumentFragment(); - for each (let child in xml) - domnode.appendChild(xmlToDOM(child, doc, nodes)); - return domnode; - } - switch (xml.nodeKind()) { - case "text": - return doc.createTextNode(String(xml)); - case "element": - let domnode = doc.createElementNS(xml.namespace(), xml.localName()); - for each (let attr in xml.@*::*) - domnode.setAttributeNS(attr.namespace(), attr.localName(), String(attr)); - - for each (let child in xml.*::*) - domnode.appendChild(xmlToDOM(child, doc, nodes)); - if (nodes && "@key" in xml) - nodes[xml.@key] = domnode; - return domnode; - default: - return null; - } -}</pre> - -<p>When passed an XML literal and a document, it returns the DOM tree corresponding to the XML for that document. If passed a third argument, the DOM node created for any element with a "key" attribute, is stored in a property of the given object named for the "key" attribute's value.</p> - -<pre class="brush: js">default xml namespace = XUL; - -var href = "http://www.google.com/"; -var text = "Google"; -var nodes = {}; -document.documentElement.appendChild( - xmlToDOM(<hbox xmlns:html={HTML}> - <html:div> - <a href={href} target="_top" key="link">{text}</a> - </html:div> - </hhox>, - document, nodes); - - nodes.link.addEventListener("click", function (event) { alert(event.target.href); }, false);</pre> - -<h3 id="JSON_Templating">JSON Templating</h3> - -<p>For code which needs to be cross-browser compatible, a similar templating system can be used, based on JSON objects rather than E4X. It also has the advantage of being slightly more concise than the E4X variant, though no easier to read.</p> - -<pre class="brush: js">var namespaces = { - html: "http://www.w3.org/1999/xhtml", - xul: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" -}; - -jsonToDOM.defaultNamespace = namespaces.html; -function jsonToDOM(xml, doc, nodes) { - function namespace(name) { - var m = /^(?:(.*):)?(.*)$/.exec(name); - return [namespaces[m[1]], m[2]]; - } - - function tag(name, attr) { - if (isArray(name)) { - var frag = doc.createDocumentFragment(); - Array.forEach(arguments, function (arg) { - if (!isArray(arg[0])) - frag.appendChild(tag.apply(null, arg)); - else - arg.forEach(function (arg) { - frag.appendChild(tag.apply(null, name[i])); - }); - }); - return frag; - } - - var args = Array.slice(arguments, 2); - var vals = namespace(name); - var elem = doc.createElementNS(vals[0] || jsonToDOM.defaultNamespace, - vals[1]); - - for (var key in attr) { - var val = attr[key]; - if (nodes && key == "key") - nodes[val] = elem; - - vals = namespace(key); - if (typeof val == "function") - elem.addEventListener(key.replace(/^on/, ""), val, false); - else - elem.setAttributeNS(vals[0] || "", vals[1], val); - } - args.forEach(function(e) { - elem.appendChild(typeof e == "object" ? tag.apply(null, e) : - e instanceof Node ? e : doc.createTextNode(e)); - }); - return elem; - } - return tag.apply(null, xml); -}</pre> - -<p>In the above, the <code>namespaces</code> object defines the namespace prefixes which can be used in the given DOM tree. Event listeners can be defined on the given nodes by passing functions rather than strings to on* attributes.</p> - -<pre class="brush: js">var href = "http://www.google.com/"; -var text = "Google"; -var nodes = {}; -document.documentElement.appendChild( - jsonToDOM(["xul:hbox", {}, - ["div", {}, - ["a", { href: href, key: "link", - onclick: function (event) { alert(event.target.href); } }, - text], - ["span", { class: "stuff" }, - "stuff"]]], - document, nodes)); - -alert(nodes.link);</pre> - -<h3 id="jQuery_Templating">jQuery Templating</h3> - -<p>For extensions which already use jQuery, it is possible to use its builtin DOM building functions for templating, though care must be taken when passing non-static strings to methods such as <code>.append()</code> and <code>.html()</code>. In most cases, <code>.text()</code> should be used instead of the latter. When using the <code>jQuery</code> constructor, only empty tags should be specified in order to avoid invoking the DOM parser.</p> - -<pre class="brush: js">var href = "http://www.google.com/"; -var text = "Google"; - $("body").append( - $("<div>", { class: "foo" }) - .append($("<a>", { href: href, text: text }) - .click(function (event) { alert(event.target.href) })) - .append($("<span>").text("Foo")));</pre> - -<h3 id="innerHTML_with_HTML_Escaping">innerHTML with HTML Escaping</h3> - -<p>This method is a last resort which should be used only as a temporary measure in established code bases. It is safe, though inefficient, to assign dynamic values to <code>innerHTML</code> if any dynamic content in the value is escaped with the following function:</p> - -<pre class="brush: js">function escapeHTML(str) str.replace(/[&"<>]/g, function (m) "&" + ({ "&": "amp", '"': "quot", "<": "lt", ">": "gt" })[m] + ";");</pre> - -<p>Note that quotation marks must be escaped in order to prevent fragments escaping attribute values, and that single quotes may not be used to quote attribute values in the fragment.</p> - -<pre class="brush: js">var href = "http://www.google.com/"; -var text = "Google"; - -document.getElementById("target-div").innerHTML = '<div>\ - <a href="' + escapeHTML(href) '" target="_top">' + escapeHTML(text) + '</a>\ - </div>'</pre> - -<p>It needs to be stressed that this method <strong>should not be used in new code</strong> and is only a temporary measure to shore up legacy code bases.</p> - -<h2 id="Safely_Generating_Event_Listeners_and_Scripts">Safely Generating Event Listeners and Scripts</h2> - -<p>It is occasionally necessary to generate event listeners and script fragments from dynamic content. Great care must be taken in these situations. Under no circumstances should code resembling <code>'callback("' + str + '")'</code> appear anywhere in your add-on.</p> - -<h3 id="Closures">Closures</h3> - -<p>By far the best way to create dynamic event listeners is to use closures. The following two code fragments are roughly equivalent:</p> - -<pre class="brush: js">function clickify(elem, address) { - elem.addEventListener("click", function (event) { openWindow(address) }, false); -} - -function clickify(elem, address) { - elem.onclick = function (event) { openWindow(address) }; -}</pre> - -<h3 id="Multiple_Attributes">Multiple Attributes</h3> - -<p>Sometimes there is a need for event listeners to appear as attributes in the DOM. In these cases, multiple attributes should be used, one for each variable:</p> - -<pre class="brush: js">function clickify(elem, address) { - elem.setAttribute("href", address); - elem.setAttribute("onclick", "openWindow(this.getAttribute('href'))"); -}</pre> - -<h3 id="Escaping_Functions">Escaping Functions</h3> - -<p>When the code fragment in question is not an event handler attribute and there is no feasible way to pass the data through other means, they must be escaped with functions such as <code>uneval</code>, <a href="/en/JavaScript/Reference/Global_Objects/String/quote" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/quote"><code>String.quote</code></a>, <a href="/en/JavaScript/Reference/Global_Objects/JSON/stringify" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/stringify"><code>JSON.stringify</code></a>, or <a href="/en/JavaScript/Reference/Global_Objects/Number" title="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Number">Number</a>. Generating scripts in this matter is deprecated and <strong>should be avoided wherever possible</strong>, but is relatively safe and sometimes acceptable.</p> - -<pre class="brush: js">function createScript(href, otherStuff) { - var script = function (href, otherStuff) { - doStuffWith(href); - doOtherStuff(); - for (var someStuff in otherStuff) - doSomeMoreStuffWith(someStuff); - } - - return script.toSource() + "(" + [String.quote(href), uneval(otherStuff)] + ")"; -}</pre> - -<h2 id="Safely_Using_Remote_HTML">Safely Using Remote HTML</h2> - -<p>In the above cases, we're working with text content that needs to appear in generated DOM. There are cases, however, where we need to safely display formatted HTML sent by a remote server. Fortunately, there is a safe and simple way to do this. The {{ ifmethod("nsIScriptableUnescapeHTML","parseFragment") }} method will convert a string to a document fragment while removing any scripts or other unsafe content in the process.</p> - -<pre class="brush: js">function ParseHTML(doc, html) { - return Components.classes["@mozilla.org/feed-unescapehtml;1"] - .getService(Components.interfaces.nsIScriptableUnescapeHTML) - .parseFragment(html, false, null, doc.documentElement); -}</pre> - -<p>The returned fragment may be appended to any element in the given document.</p> - -<pre class="brush: js">document.body.appendChild(ParseHTML(document, xhr.responseText, xhr.channel.name);</pre> - -<h2 id="See_Also">See Also</h2> - -<ul> - <li><a href="/En/Displaying_web_content_in_an_extension_without_security_issues" title="En/Displaying_web_content_in_an_extension_without_security_issues">Displaying web content in an extension without security issues</a></li> - <li><a href="/en/How_to_create_a_DOM_tree" title="https://developer.mozilla.org/en/How_to_create_a_DOM_tree">How to create a DOM tree</a></li> - <li>{{ domxref("Node.textContent") }}</li> - <li>{{ domxref("Node.appendChild()") }}</li> - <li>{{ domxref("element.setAttribute()") }}</li> - <li><a href="/en/DOM/document.createElement" title="en/DOM/document.createElement">document.createElement()</a></li> - <li><a href="/en/DOM/document.createTextNode" title="en/DOM/document.createTextNode">document.createTextNode()</a></li> -</ul> - -<div class="originaldocinfo"> -<h2 id="Original_Document_Information" name="Original_Document_Information">Original Document Information</h2> - -<ul> - <li>Author(s): Kris Maglione</li> - <li>Last Updated Date: 2011-08-08</li> -</ul> -</div> - -<p> </p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/documentación_de_mozilla/index.html b/files/es/mozilla/tech/xul/escuela_xul/documentación_de_mozilla/index.html deleted file mode 100644 index 0928dec065..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/documentación_de_mozilla/index.html +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: Documentación de Mozilla -slug: Mozilla/Tech/XUL/Escuela_XUL/Documentación_de_Mozilla -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Mozilla_Documentation_Roadmap ---- -<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}}{{AddonSidebar}}</p> - -<p>{{ PreviousNext("Notificaciones_de_usuario_y_alertas", "Escuela_XUL/Sitios_útiles_de_la_comunidad_Mozilla") }}</p> - -<h2 id="Mozilla_Documentation">Mozilla Documentation</h2> - -<p>Firefox extension development is still an immature discipline, with a developer base consisting mostly of hobbyists and just a few organized development groups. There's a great deal of free online documentation available on XUL and extension development, but finding it and turning it into useful information can be a daunting task. Knowing where to look is critical and non trivial. This tutorial was aimed at compiling all the right resources for extension development and putting them in the right context, but there's much more to learn, and knowing how to find it is part of what we felt was necessary to teach.</p> - -<p>Let's look into the resources that have helped us the most.</p> - -<h2 id="The_Mozilla_Developer_Center">The Mozilla Developer Center</h2> - -<p>This is the official and most extensive guide to everything related to Mozilla. MDC is where this tutorial is hosted, and where most of its links point to. It encompasses Firefox, other Mozilla products, Javascript, CSS, XUL, web and extension development guidelines, accessibility, usability, best practices... The list goes on. It's incredibly comprehensive, and its underlying Wiki technology makes it easy to expand and evolve with the help of the community.</p> - -<p>Having said that, there are a few problems with it. First of all, the in-site search is not reliable, so we recommend using a search engine like Google, with queries such as "MDC Javascript Code Modules" or "Javascript code modules site:developer.mozilla.org". Secondly, there are several important articles that are very lacking in information, like the <a href="/en/Preferences/Preferences_system" title="en/Preferences System">Preferences System</a> page. And finally, what we mentioned in our XPCOM section: almost no documentation on XPCOM components. The documentation on interfaces is very complete, but it isn't nearly as useful as the documentation that existed at <a class="external" href="http://xulplanet.com/">XULPlanet</a> and was later taken down. XULPlanet allowed you to navigate between interfaces and their related components, which makes locating components very easy. Hopefully this will be corrected in the future. In the meantime, you can still navigate XULPlanet using the <a class="external" href="http://www.archive.org/web/web.php" title="http://www.archive.org/web/web.php">Wayback Machine</a>.</p> - -<p>MDC should be your first stop when looking for documentation. If you find it lacking or missing some piece of information, please consider adding it once you've found it. Everyone looking for it later will thank you for it.</p> - -<h2 id="The_AMO_Developer_Hub">The AMO Developer Hub</h2> - -<p>The <a class="link-https" href="https://addons.mozilla.org/developers/" title="https://addons.mozilla.org/developers/">AMO Developer Hub</a> is a great guide for add-on developers. It includes links to tutorials and documentation, development tools, and most notably, the <a class="link-https" href="https://forums.addons.mozilla.org/" title="https://forums.addons.mozilla.org/">Mozilla Add-ons Forum</a>. This is a great place to ask questions and have them answered by experienced developers. It also includes discussions on add-on monetization, job postings and a long list of add-on ideas waiting to be developed.</p> - -<h2 id="The_Mozilla_Source">The Mozilla Source</h2> - -<p>Sometimes you need more than just a tutorial. There are various tricks that you can't learn anywhere, but you know that Firefox implements them in some way. In these cases you should dive into Mozilla's source code and try to locate the code you need. One way to do this is to look into your Firefox installation directory, maybe unpack a few JARs and see what's inside. But this is very awkward and limited. It would be much better to be able to search and navigate through the huge code base with some ease.</p> - -<p>Luckily, Mozilla provides exactly that in the <a class="external" href="http://mxr.mozilla.org/" title="http://mxr.mozilla.org/">Mozilla Cross-Reference</a>. The main index in this page gives you options to look into the different product branches in development at Mozilla. Make sure you pick the one that matches your target versions.</p> - -<p>All of these provide advanced search capabilities, including regular expression search and file path search. You'll be able to navigate the full source tree, inspect the change history for all files, and link to specific code lines. It takes a little getting used to, specially learning how to choose the best search queries, but it's an invaluable resource of information.</p> - -<h2 id="Mozilla_Blogs">Mozilla Blogs</h2> - -<p>Several Mozilla community members maintain blogs that are updated frequently, often including information on API changes, bug fixes, useful tools and future release plans. Many of the tips and tricks included in this tutorial were discovered by reading these blogs.</p> - -<p>There are several useful feeds that you can follow using a feed reader, such as Thunderbird. Here are some important feeds you should consider following:</p> - -<ul> - <li><a class="external" href="http://planet.mozilla.org/">Planet Mozilla</a>. This is the ultimate source for everything related to Mozilla. It brings together the feeds of most Mozilla employees, as well as several other members of the Mozilla community. Feeds are added frequently, so the information available through it will only grow with time. It can be hard to follow due of the sheer mass of information coming out of it (dozens of posts per day), but you'll certainly be up to date with pretty much everything if you take the time to read at least part of it.</li> - <li>The <a class="external" href="/devnews/index.php/categories/about-mozilla" title="devnews/index.php/categories/about-mozilla">about:mozilla newsletter</a> is a weekly publication that includes the highlights of what is posted at Planet Mozilla. It is a good alternative if you feel Planet Mozilla is too much. You can also subscribe to receive it by email if you prefer that. Posts on about:mozilla also make it to Planet Mozilla.</li> - <li>The <a class="external" href="http://blog.mozilla.com/addons/" title="http://blog.mozilla.com/addons/">Mozilla Add-ons Blog</a>. This blog is maintained by the Add-ons Team at Mozilla, and it's a great way to stay up to date with AMO development and add-on review policies. This blog is also part of Planet Mozilla.</li> -</ul> - -<h2 id="IRC_and_newsgroups">IRC and newsgroups</h2> - -<p>Mozilla developers use their <a class="external" href="http://irc.mozilla.org/">IRC channels</a> heavily. There are several help and development channels where you can discuss problems and other topics in real time with the people that have the answers. You'll need an IRC client in order to do this, and the <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/16?id=16">Chatzilla</a> extension works well for this purpose. Problems using IRC include: finding help when you have a big timezone difference with the United States, and no records of previously asked questions and their answers.</p> - -<p>Another somewhat obscure communication channel is the <a class="external" href="http://www.mozilla.org/community/developer-forums.html">Mozilla Newsgroups</a>. They are also very diverse and active, and there's a good chance you'll get your queries answered. Thunderbird also comes in handy for reading and posting to the newsgroups. Another advantage is that discussions are archived and searchable through Google Groups.</p> - -<h2 id="Other">Other</h2> - -<p>And finally, a couple resources you should also keep in mind:</p> - -<ul> - <li>Other extensions. There are thousands of extensions out there, and you may strike luck and find one that does exactly what you need. Be sure to look at the license the extension's code is released with before thinking about copying large sections of it. Also, remember to give credit when it's due.</li> - <li><a class="external" href="http://bugzilla.mozilla.org/">Mozilla's Bugzilla repository</a>. Pretty much every code change done in Firefox and Mozilla projects is documented in this huge tracking database. But this also means that finding exactly what you need can be time-consuming, and often fruitless. The advanced search is very useful in filtering results, but it is our experience that it's often better to be too general than too specific. Better to scan a list of hundreds of bugs than getting no results at all, right?</li> - <li>Anywhere else. Use your favorite search engine and patiently look for answers. It's better to take a long time finding an answer than taking even longer doing something that has already been done.</li> -</ul> - -<p>Good luck!</p> - -<p>{{ PreviousNext("Notificaciones_de_usuario_y_alertas", "Escuela_XUL/Sitios_útiles_de_la_comunidad_Mozilla") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/elementos_esenciales_de_una_extensión/index.html b/files/es/mozilla/tech/xul/escuela_xul/elementos_esenciales_de_una_extensión/index.html deleted file mode 100644 index 9fdbda1f36..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/elementos_esenciales_de_una_extensión/index.html +++ /dev/null @@ -1,417 +0,0 @@ ---- -title: Elementos esenciales de una extensión -slug: Mozilla/Tech/XUL/Escuela_XUL/Elementos_esenciales_de_una_extensión -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/The_Essentials_of_an_Extension ---- -<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}}{{AddonSidebar}}</p> - -<p>{{ PreviousNext("Escuela_XUL/Introducción_a_las_extensiones_de_Firefox", "Escuela_XUL/Montando_un_ambiente_de_desarrollo") }}</p> - -<h2 id="El_archivo_install.rdf">El archivo install.rdf</h2> - -<p>En la última sección miramos a los contenidos de la extensión Hola Mundo. Ahora, miraremos sus archivos y su código, comenzando con el archivo <em>install.rdf</em>. Puedes abrirlo con cualquier editor de texto.</p> - -<p>El archivo tiene un formato distinto del XML tradicional, llamado <a class="external" href="http://en.wikipedia.org/wiki/Resource_Description_Framework">RDF</a>. RDF solía ser el mecanismo central de almacenamiento para Firefox, pero está siendo reemplazado por un sistema de bases de datos más sencillo. Hablaremos de ambos más adelante en este tutorial.</p> - -<p>Ahora, miremos a las partes importantes del archivo.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><em:id>holamundo@xulschool.com</em:id></pre> -</div> -</div> - -<p>Este es el identificador único para la extensión. Firefox necesita esto para distinguir tu extensión de otras extensiones, así que se requiere que tengas una ID única.</p> - -<p>Hay dos estándares aceptados para las ids de las extensiones. Una es el formato email presente en el ejemplo de Hola Mundo, que sería algo como <em><nombreproyecto-name>@<tudominio></em>. El otro estándar es usar una cadena de texto <a class="external" href="http://en.wikipedia.org/wiki/Uuid">UUID</a>, la cuál es extremadamente única, y es muy improbable que sea duplicada. Los sistemas basados en Unix tienen una herramienta desde la línea de comandos llamada <em>uuidgen</em> que genera UUIDs. Estas también se pueden crear utilizando herramientas específicas para todos los sistemas. Los paréntesis que cierran son simplemente notación, y son una práctica común. Siempre y cuando tu id sea única, está bien usar cualquiera de las formas.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><em:name>XUL School Hello Worldem:name> -<em:description>Welcome to XUL School!</em:description> -<em:version>0.1</em:version> -<em:creator>Appcoast</em:creator> -<span class="code-comment"><em:homepageURL>https://developer.mozilla.org/en/XUL_School</em:homepageURL></span></pre> -</div> -</div> - -<p>Esta será la información que será mostrada antes y después de la que la extensión sea instalada, la que puedes ver en la ventana de Extensiones. La URL de la página principal puede ser visitada haciendo clic derecho en la extensión y eligiendo Visitar página principal. Hay muchas otras etiquetas que pueden ser añadidas, para contribuidores y traductores. La <a href="/en/Install_Manifests" title="en/Install Manifests">especificación completa</a> del archivo install.rdf tiene todos los detalles.</p> - -<p>Ya que las extensiones pueden ser traducidas en múltiples idiomas, suele ser necesario traducir la descripción de la extensión, o incluso su nombre. A partir de Firefox 3 y superior, una descripción y nombres con localización específica se puede añadir de la siguiente manera:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><em:localized> - <Description> - <em:locale>es-ES</em:locale> - <em:name>XUL School Hola Mundo</em:name> - <em:description>¡Bienvenido a XUL School!</em:description> - </Description> -</em:localized></pre> -</div> -</div> - -<p>La cadena de texto <em>es-ES</em> indica que esta es la localización para española (es) para España (ES). Puedes añadir tantos <em><em:localized></em> como necesites Para Firefox 2, localizar este archivo es un <a href="/en/Localizing_extension_descriptions#Localizing_before_Gecko_1.9" title="en/Localizing extension descriptions#Localizing before Gecko 1.9">poco más complicado</a>. Hablaremos de la localizacion más adelante en esta sección.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><em:type>2</em:type></pre> -</div> -</div> - -<p>Esto especifica que la extensión se instala como una extensión (y no como un tema, por ejemplo). Puedes leer los distintos tipos disponibles en la <a href="/en/Install_Manifests#type" title="en/Install Manifests#type">especificación de install.rdf</a>.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><em:targetApplication> - <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> - <em:minVersion>3.0</em:minVersion> - <em:maxVersion>6.0a1</em:maxVersion> - </Description> -</em:targetApplication></pre> -</div> -</div> - -<p>Este nodo especifica a qué versiones apunta la extensión, especialmente Firefox, desde la versión 3.0 hasta las versiones experimentales de Firefox 6. La UUID es la ID única de Firefox. Otras aplicaciones y aplicaciones basadas en Mozilla como Thunderbird o Seamonkey tienen las suyas propias. Puedes tener una extensión que funcione en múltiples aplicaciones y versiones. Por ejemplo, si creas una extensión para Firefox, normalmente se debería hacer el pequeño esfuerzo para portarla a Flock o SeaMonkey, los cuáles tienen funciones y UI similares.</p> - -<p>La versión mínima y máxima especifica el rango en el cuál la extensión puede ser instalada. Aquí hay más sobre el <a href="/en/Toolkit_version_format" title="en/Toolkit version format">formato de la versión</a>. Si la aplicación o el rango de versiones no coinciden, no podrás instalar la aplicación, o la aplicación se instalará desactivada. Los usuarios pueden desactivar la comprobación de versiones a través de las preferencias o a través de extensiones como <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/15003" title="https://addons.mozilla.org/en-US/firefox/addon/15003">Add-on Compatibility Reporter</a>.</p> - -<p>Esta es toda la información que Firefox y otras aplicaciones de Mozilla necesitan para instalar una extensión. Cualquier error o información omitida causará un error en el proceso de instalación, o la extensión se instalará como desactivada.</p> - -<h2 id="El_archivo_chrome.manifest">El archivo chrome.manifest</h2> - -<blockquote> -<p>Chrome es el conjunto de elementos gráficos para el usuario de la ventana de la aplicación que están fuera del contenido de la ventana. Barras de herramientas, de menús, de progreso y de título son ejemplos de elementos que son parte de chrome.</p> -</blockquote> - -<p>Extraído de <a href="/en/Chrome_Registration" title="en/Chrome Registration">Chrome Registration</a>.</p> - -<p>En otras palabras, el chrome es todo lo que ves en Firefox. Todas las ventanas de Firefox pueden verse en dos partes: (1) la chrome y (2) la posible área de contenido, como aquella que muestra las páginas web en una pestaña de Firefox. Las ventanas como el administrador de extensiones o la ventana de descargas son puro chrome. La mayoría del código reside en la carpeta chrome, como en el ejemplo de Hola Mundo.</p> - -<p>Los archivos chrome están empacados en un archivo JAR, normalmente nombrados tras la extensión. No es necesario empacar los archivos chrome, pero es una práctica común y recomendada por razones de rendimiento.</p> - -<p> </p> - -<p>Como hemos visto en la estructura de directorios de la extensión desempacada, la chrome está compuesta de 3 secciones: content, locale y skin. Estas 3 son necesarias para la mayoría de las extensiones. Si abrimos el archivo <em>chrome.manifest</em> (de nuevo, cualquier editor de texto servirá), veremos que las 3 secciones se mencionan:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">content xulschoolhello jar:chrome/xulschoolhello.jar!/content/ -skin xulschoolhello classic/1.0 jar:chrome/xulschoolhello.jar!/skin/ -locale xulschoolhello en-US jar:chrome/xulschoolhello.jar!/locale/en-US/</pre> -</div> -</div> - -<p>El archivo <em>chrome.manifest</em> le dice a Firefox donde mirar para los archivos chrome. El texto contiene varios espacios para que parezca una tabla, pero no es necesario. El parseador ignorará los espacios repetidos.</p> - -<p>La pimera línea le dice a Firefox que está siendo declarado (content, skin, locale, u otros que veremos más adelante). La segunda es el nombre del paquete, el cuál explicaremos en breve. Los paquetes skin y locale tienen un tercer valor para especificar que localización o tema están extendiendo. Puede haber múltiples temas y entradas de localización en relación a distintos temas y localizaciones. El caso más común es tener una entrada skin para el skin global, <em>classic/1.0</em>, y múltiples entradas locale, una para cada traducción. Finalmente, la localización es especificada.<br> - Nótese del esquema <em>jar</em><em>;</em> le dice a Firefox que mire dentro del archivo JAR y lea los archivos del camino correcto. Si quieres tener una extensión con un directorio chrome desempacado, sólo necesitas cambiar los lugares a algo como <em>chrome/content</em>/.</p> - -<p> </p> - -<p>Hay algunas opciones adicionales que pueden ser incluidas en las entradas del archivo <em>chrome.manifest</em>. Están documentadas en la página de <a href="/en/Chrome_Registration" title="en/Chrome Registration">Chrome Registration</a>. Notablemente, podemos tener distintas entradas que sean específicas para cada SO. Esto es importante, especialmente en Firefox 3 y versiones superiores, donde la apariencia del navegador es muy diferente para cada sistema operativo. Si nuestra extensión necesitase parecer diferente en los sistemas mayoritarios, podríamos cambiar el archivo de manifiesto para que incluyese esto:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">content xulschoolhello jar:chrome/xulschoolhello.jar!/content/ -skin xulschoolhello classic/1.0 jar:chrome/xulschoolhello.jar!/skin/unix/ -skin xulschoolhello classic/1.0 jar:chrome/xulschoolhello.jar!/skin/mac/ os=Darwin -skin xulschoolhello classic/1.0 jar:chrome/xulschoolhello.jar!/skin/win/ os=WinNT -locale xulschoolhello en-US jar:chrome/xulschoolhello.jar!/locale/en-US/</pre> -</div> -</div> - -<p>De esta manera podemos tener temas distintos para Windows, Mac OS X, y Linux (además de otros sistemas similares a unix), cada uno definido en un directorio separado. Ya que la mayoría de los sistemas están basados en Unix, el tema "unix" es el utilizado por defecto, sin banderas.</p> - -<h2 id="El_Chrome">El Chrome</h2> - -<p>Como se ha mencionado antes, el chrome se compone de 3 secciones: contenido, localizaciones y temas. El contenido es la sección mas importante, ya que tiene la interfaz de usuario (XUL) y archivos de scripts (JS). La sección de temas contiene los archivos que definen la mayoría del aspecto y la sensación de la UI (incluyendo CSS e imágenes, como las páginas web). Finalmente, la sección de localización incluye todos los textos utilizados en la extensión, en DTD y archivos de propiedades. Esta división permite a otros desarrolladores crear temas que reemplacen pieles, y traductores para crear localizaciones en distintos idiomas, todo esto sin tener que cambiar tu extensión o tu código. Esto le da a las extensiones de Firefox gran flexibilidad.</p> - -<p>Se accede a los archivos chrome a través del protocolo chrome. Las URIs chrome se definen así:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">chrome:<span class="code-comment">//packagename/section/path/to/file</span></pre> -</div> -</div> - -<p>Así que, por ejemplo, si quiero acceder al archivo <em>b</em><em>rowserOverlay.xul</em> en la extensión, la URI chrome sería <em><a class="external" rel="freelink">chrome://xulschoolhello/content/browserOverlay.xul</a></em>. Si tienes demasiados archivos en el contenido y quieres organizarlos en subdirectorios, no necesitas cambiar nada en <em>chrome.manifest</em>, todo lo que necesitas es añadir el camino correcto tras <em>content</em> en la URI. Los temas y localizaciones funcionan de la misma manera, y no necesitas especificar sus nombre. Así que, para acceder al archivo DTD en la extensión Hola Mundo, el camino chrome es <em><a class="external" rel="freelink">chrome://xulschoolhello/locale/browserOverlay.dtd</a></em>. Firefox sabe qué localización buscar.</p> - -<p>Aquí tenemos un experimento interesante. Abre una pestaña nueva en Firefox, teclea<em> <a class="external" rel="freelink">chrome://mozapps/content/downloads/downloads.xul</a></em> en la barra de notificaciones y pulsa ENTRAR. ¿Sorprendido? ¡Acabas de abrir la ventana de Descargas en tu pestaña de Firefox! Puedes acceder a cualquier archivo chrome simplemente tecleando su URI en la barra de direcciones. Esto puede ser útil si quieres inspeccionar archivos de script que son parte de Firefox, u otras extensiones, por ti sólo. La mayoría de estos archivos se abren como archivos de texto, a excepción de los archivos XUL, que se ejecutan y muestran como normalmente los verías en una ventana.</p> - -<h3 id="Contenido">Contenido</h3> - -<p>Hay dos archivos de contenido en el directorio de contenido. Miremos el primer archivo XUL.</p> - -<p>Los archivos <a href="/en/XUL" title="en/XUL">XUL</a> son archivos XML que definen la interfaz gráfica de usuario de los elementos en Firefox y las extensiones de Firefox. XUL fue inspirado por HTML, así que verás bastantes similitudes entre ambos. De todos modos, XUL es también una mejora sobre HTML, habiendo aprendido de los errores cometidos durante la evolución de HTML. XUL te permite crear interfaces más ricas e interactivas que las que puedas crear con HTML, o al menos XUL lo hace más fácil.</p> - -<p>Los archivos XUL normalmente definen una de dos cosas: ventanas o superposiciones. El archivo que has abierto antes, <em>downloads.xul</em>, tiene el código que define la ventana de Descargas. El archivo XUL incluido en la extensión Hola Mundo tiene una superposición. Una superposición extiende una ventana ya existente, añadiendo nuevos elementos a esta o reemplazando algunos de los elementos que tiene. La línea que nos hemos saltado en el archivo <em>chrome.manifest</em> declara que este archivo XUL es una superposición para la ventana principal del navegador.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">overlay chrome:<span class="code-comment">//browser/content/browser.xul chrome://xulschoolhello/content/browserOverlay.xul</span></pre> -</div> -</div> - -<p>Con esta línea, Firefox sabe que necesita tomar el contenido de <em>browserOverlay.xul</em> y superponerlo sobre la ventana principal del navegador, <em>browser.xul</em>. Puedes declarar overlays para cualquier ventana o diálogo en Firefox, pero superponer la ventana principal del navegador es el caso más común.</p> - -<p>Ahora echemos un vistazo a los contenidos de nuestro archivo XUL. Nos saltaremos las primeras líneas porque se refieren al tema y la localización, las cuales cubriremos más tarde.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><overlay id="xulschoolhello-browser-overlay" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"></pre> -</div> -</div> - -<p>El elemento raíz en el archivo es un <em>overlay</em>. Otros documentos XUL usan la etiqueta <em>window</em> o <em>dialog</em>. El elemento tiene una id única, la cuál deberías usar en la mayoría de los elementos en tu XUL. El segundo atributo es el espaciado de nombres, lo cuál es algo que siempre deberías definir en tu elemento raíz. Esto dice que este nodo y todos sus nodos hijos son XUL. Sólo necesitas cambiar las declaraciones del espaciado de nombres cuando combines distintos tipos de contenidos, como XUL con HTML o SVG.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">Es probable que te hayas dado cuenta del nombre que hemos usado en distintos lugares, así como la id <em>xulschoolhello-browser-overlay. Este es el espaciado de nombres estándar que utilizamos para evitar conflictos con Firefox y otras extensiones, así como hacer algunas tareas de desarrollo más sencillas. Usamos el mismo espaciado de nombres en todas las ids y clases de estilo de los elementos de superposición porque serán mezclados con otros elementos en la ventana principal del navegador. Si usásemos ids genéricas como container o input, estas </em>entrarían en conflicto con las ids usadas dentro de Firefox, o las ids de otras extensiones de superposición. Usando espaciado de nombres minimiza los problemas de compatibilidad con otras extensiones. Usamos camel casing para los nombres de archivos, y todo en minúsculas con barras para las ids de elementos y los nombres de clases de los estilos CSS.</div> -</div> -</div> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><script type=<span class="code-quote">"application/x-javascript"</span> - src=<span class="code-quote">"chrome:<span class="code-comment">//xulschoolhello/content/browserOverlay.js"</span> /></span></pre> -</div> -</div> - -<p>Al igual que en HTML, esto incluye un script en JavaScript. Puedes tener tantos elementos <em>scripts</em> en un archivo XUL como necesites. Miraremos su código más tarde.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">También es posible que te hayas dado cuenta en el formato de nuestro código, y preguntarte sobre las reglas que seguimos. Nuestra regla general es que la longitud de la línea no sea superior a 80 caracteres. Esto puede parecer muy restrictivo, sobre todo en los archivos XML, pero este número ha sido elegido para permitir a casi todos los editores de texto que manejen estos archivos de manera sencilla. Incluso un editor de textos antiguo desde la línea de comandos funciona bien que cortan sus líneas antes de los 80 caracteres. La tabulación es muy directa: 2 espacios en blanco para indentar. Nunca usamos caracteres TAB, a excepción de los Makefiles, los cuáles cubriremos más adelante. La mayoría de nuestros estándares de código se basan en los estándares de Mozilla u otros conocidos.</div> -</div> -</div> - -<p>Nos saltaremos algo de código qie se cubrirá en la sección de localización, moviéndonos así a la parte importante del contenido:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><menubar id="main-menubar"> - <menu id="xulschoolhello-hello-menu" label="&xulschoolhello.hello.label;" - accesskey="&xulschoolhello.helloMenu.accesskey;" insertafter="helpMenu"> - <menupopup> - <menuitem id="xulschoolhello-hello-menu-item" - label="&xulschoolhello.hello.label;" - accesskey="&xulschoolhello.helloItem.accesskey;" - oncommand="XULSchoolChrome.BrowserOverlay.sayHello(event);" /> - </menupopup> - </menu> -</menubar></pre> -</div> -</div> - -<p>Este es el código que añade el menú de Hola Mundo a la ventana del navegador. Para escribir este código, necesitamos algo de conocimiento sobre el código XUL en <em>browser.xul</em>. Necesitábamos saber que la id del menú principal es <em>main-menubar</em>. Estamos añadiendo un menú nuestro propio, y diciéndole a Firefox que lo añada a la barra de menú principal, justo después del menú de ayuda. Ese es el propósito del atributo:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">insertafter=<span class="code-quote">"helpMenu"</span></pre> -</div> -</div> - -<p><em>helpMenu</em> es la id del elemento del menú que corresponde al menú de Ayuda en la ventana principal del navegador. Más adelante veremos como podemos encontrar cosas como las ids de los elementos del navegador, pero por ahora miraremos a los elementos que componen el menú de Hola Mundo.</p> - -<p>El elemento <a href="/en/XUL/menubar" title="en/XUL/menubar">menubar</a> representa la barra de menús que normalmente ves arriba del todo de una ventana de aplicación. La ventana principal de Firefox tiene una, pero pocas otras ventanas tienen. También es raro para ventanas adicionales de una extensión tengan sus propias barras de menú.</p> - -<p>Hemos añadido el menú de Hola Mundo justo en la "raíz" de la barra de menús así que sería muy fácil para ti localizarlo, pero no es una práctica recomendada. Imaginemos si todas las extensiones añadieran menús a la barra de menús de arriba; teniendo unas pocas extensiones haría que el menú pareciese como un salpicadero de un avión, lleno de opciones. El lugar recomendado para los menús de extensiones es bajo el menú de <em>Herramientas</em>, así que el código se parecería a este:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><menupopup id=<span class="code-quote">"menu_ToolsPopup"</span>> - <menu id=<span class="code-quote">"xulschoolhello-hello-menu"</span> label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.hello.label;"</span> - accesskey=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.helloMenu.accesskey;"</span> - insertafter=<span class="code-quote">"javascriptConsole,devToolsSeparator"</span>> - <menupopup> - <menuitem id=<span class="code-quote">"</span><span class="code-quote">xulschoolhello</span><span class="code-quote">-hello-menu-item" - </span> label=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.hello.label;"</span> - accesskey=<span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.helloItem.accesskey;"</span> - oncommand=<span class="code-quote">"XULSchoolChrome.BrowserOverlay.sayHello(event);"</span> /> - </menupopup> - </menu> -</menupopup></pre> -</div> -</div> - -<p>Estamos superponiendo un menú que está más adentro en nuestro árbol XUL, pero no parece importar porque todo lo que necesitamos es la id del elemento que queremos superponer. En estado es el elemento <a href="/en/XUL/menupopup" title="en/XUL/menupopup">menupopup</a> que está dentro del elemento del <a href="/en/XUL/menu" title="en/XUL/menu">menú</a> de Herramientas. El atributo <em>insertafter</em> le dice a Firefox que añada el menú debajo del objeto de la Consola de Errores (formalmente conocida como la Consola de JavaScript) en el menú de Herramientas, como se recomienda en la <a href="/en/Extensions/Extension_etiquette" title="en/Extension Etiquette"><span class="external">Extension Etiquette page</span></a>. Discutiremos más de los menús más adelante en este tutorial. Por ahora vamos a centrarnos en la siguiente línea:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">oncommand=<span class="code-quote">"XULSchoolChrome.BrowserOverlay.sayHello(event);"</span></pre> -</div> -</div> - -<p>This attribute defines an event handler. The <em>command</em> event is the most frequently used in Firefox, since it corresponds to the main action for most UI elements. The value of the attribute is JavaScript code that invokes a function. This function is defined in the JS file that was included with the <em>script</em> tag. The JS function will be called once the user clicks on the menu item in the Hello World menu. All event handlers define a special object named <em>event</em>, which is usually good to pass as an argument to the function. Event handlers are explained in greater depth further ahead.</p> - -<p>Now let's look at the JavaScript file and see what's going on when the event is fired.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">/** - * XULSchoolChrome namespace. - */ -if ("undefined" == typeof(XULSchoolChrome)) { - var XULSchoolChrome = {}; -};</pre> -</div> -</div> - -<p>The <em>XULSchoolChrome</em> namespace is defined. All objects and variables we define in this JavaScript are global, meaning that scripts in Firefox and other extensions can see them and interact with them. This also means that if we define an object called <em>MenuHandler</em> or some other generic name, it's likely going to conflict with an existing object. What we do here is define a single global object: <em>XULSchoolChrome</em>. Now we know that all of our objects are inside this object, which is unlikely to be duplicated or overwritten by other extensions.</p> - -<p>You can read more about the <a href="/en/JavaScript/Reference/Operators/Special/typeof" title="en/Core JavaScript 1.5 Reference/Operators/Special Operators/typeof Operator"><span class="external">typeof operator</span></a>. If you're unfamiliar with JavaScript or this particular syntax, initializing an object as <em>{}</em> is the equivalent of initializing it to <em>new Object()</em>.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">/** - * Controls the browser overlay <span class="code-keyword">for</span> the Hello World extension. - */ -XULSchoolChrome.BrowserOverlay = {</pre> -</div> -</div> - -<p>Finally, <em>BrowserOverlay</em> is our object. Naming and referencing objects in such a long and verbose manner can feel uncomfortable at first, but it's worth the cost.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">We use <a class="external" href="http://java.sun.com/j2se/javadoc/writingdoccomments/index.html">Javadoc</a> style comments on all namespaces, objects and object members. This is a similar standard to the one used in Mozilla code, and some tools can generate documentation automatically from Javadoc.</div> -</div> -</div> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">sayHello : function(aEvent) { - let stringBundle = document.getElementById("xulschoolhello-string-bundle"); - let message = stringBundle.getString("xulschoolhello.greeting.label"); - - window.alert(message); -}</pre> -</div> -</div> - -<p>And, finally, this is our function declaration. Three lines of code are all we need for it to work. The first line in the body of the function declares a variable that will hold the <a href="/en/XUL/stringbundle" title="en/XUL/stringBundle">stringbundle</a> element defined in the overlay. The variable is declared using <em>let,</em> which is similar to <em>var</em> but with more restricted scope. Here you can read more about <a href="/en/JavaScript/New_in_JavaScript/1.7#Block_scope_with_let" title="en/New in JavaScript 1.7#Block scope with let"><span class="external">let declarations</span></a>. It's worth noting that this is a relatively new addition to JavaScript in Firefox and you should use <em>var</em> if you're creating an extension compatible with very old versions.</p> - -<p>Just like in regular JS, we can use the <a href="/en/DOM" title="en/DOM"><span class="external">DOM</span></a> (Document Object Model) in order to manipulate the XUL document. First we get a reference of the <a href="/en/XUL/stringbundle" title="en/XUL/stringbundle"><span class="external">stringbundle element</span></a> in the document. This is a special element that allows us to obtain localized strings dynamically, by only providing a "key" that identifies the string. This is what we do on the second line. We call the <a href="/en/XUL/stringbundle#m-getString" title="en/XUL/stringbundle#m-getString">getString method</a> of the bundle element and get the localized message to be displayed. We then call the <a href="/en/DOM/window.alert" title="en/DOM/window.alert">window.alert</a> function with the message, just like we would do in an HTML document.</p> - -<h3 id="Locale">Locale</h3> - -<p>There are two types of locale files: DTD and properties, and in this example we use them both. DTD is the most efficient way of showing text in XUL, so you should use it whenever possible. It is somewhat inflexible so it can't be used for dynamically generated text, hence the need for an alternate way of getting localized strings.</p> - -<p>Looking back at the menu code, you probably noticed some attributes such as this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">label=<span class="code-quote">"&xulschoolhello.hello.label;"</span> accesskey=<span class="code-quote">"&xulschoolhello.helloItem.accesskey;"</span></pre> -</div> -</div> - -<p>These attributes define the text that you see on the menus, and they are string keys that are defined in our DTD file, <em>browserOverlay.dtd</em>. The DTD file was included in the XUL file with the following code:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><!DOCTYPE overlay SYSTEM "chrome://xulschoolhello/locale/browserOverlay.dtd" ></pre> -</div> -</div> - -<p>And in the DTD file you can see the association between keys and localized strings:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><!ENTITY xulschoolhello.hello.label <span class="code-quote">"Hello World!"</span>> -<!ENTITY xulschoolhello.helloMenu.accesskey <span class="code-quote">"l"</span>> -<!ENTITY xulschoolhello.helloItem.accesskey <span class="code-quote">"H"</span>></pre> -</div> -</div> - -<p>Notice that on the XUL file you enclose the string key with <em>&</em> and <em>;</em> while on the DTD file you only specify the key. You may get weird parsing errors or incorrect localization if you don't get it right.</p> - -<p>Access keys are the shortcuts that allow you to quickly navigate a menu using only the keyboard. They are also the only way to navigate a menu for people with accessibility problems, such as partial or total blindness, or physical disabilities that make using a mouse very difficult or impossible. You can easily recognize the access keys on Windows because the letter that corresponds to the access key is underlined, as in the following image:</p> - -<div> -<p><img alt="" class="internal" src="../../../../@api/deki/files/4226/=accesskeys.png" style="height: 58px; width: 167px;"></p> -</div> - -<p>Most user interface controls have the <em>accesskey</em> attribute, and you should use it. The value of the access key is localized because it should match a letter in the label text. You should also be careful to avoid access key repetition. For example, within a menu or submenu, access keys should not be repeated. In a window you have to be more careful picking access keys because there are usually more controls there. You have to be specially careful when picking access keys on an overlay. In our case, we can't use the letter "H" as an accesskey in the Main menu item, because it would be the same as the access key in the Help menu. Same goes with "W" and the Window menu on Mac OS. So we settled on the letter "l".</p> - -<p>DTD strings are resolved and set when the document is being loaded. If you request the <em>label</em> attribute value for the Hello World menu using DOM, you get the localized string, not the string key. You cannot dynamically change an attribute value with a new DTD key, you have to set the new value directly:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let helloItem = document.getElementById(<span class="code-quote">"xulschoolhello-hello-menu-item"</span>); - -<span class="code-comment">// The alert will say <span class="code-quote">"Hello World!"</span> -</span>alert(helloItem.getAttribute(<span class="code-quote">"label"</span>)); -<span class="code-comment">// Wrong -</span>helloItem.setAttribute(<span class="code-quote">"label"</span>, <span class="code-quote">"&</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.hello2.label;"</span>); -<span class="code-comment">// Better -</span>helloItem.setAttribute(<span class="code-quote">"label"</span>, <span class="code-quote">"Alternate message"</span>); -<span class="code-comment">// Right! -</span>helloItem.setAttribute(<span class="code-quote">"label"</span>, someStringBundle.getString(<span class="code-quote">"</span><span class="code-quote">xulschoolhello</span><span class="code-quote">.hello2.label"</span>));</pre> -</div> -</div> - -<p>This is the reason DTD strings are not a solution for all localization cases, and the reason we often need to include string bundles in XUL files:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><stringbundleset id="stringbundleset"> - <stringbundle id="xulschoolhello-string-bundle" - src="chrome://xulschoolhello/locale/browserOverlay.properties" /> -</stringbundleset></pre> -</div> -</div> - -<p>The <a href="/en/XUL/stringbundleset" title="en/XUL/stringbundleset">stringbundleset</a> element is just a container for <a href="/en/XUL/stringbundle" title="en/XUL/stringbundle">stringbundle</a> elements. There should only be one per document, which is the reason why we overlay the <em>stringbundleset</em> that is in <em>browser.xul</em>, hence the very generic id. We don't include the <em>insertbefore</em> or <em>insertafter</em> attributes because the ordering of string bundles doesn't make a difference. The element is completely invisible. If you don't include any of those ordering attributes in an overlay element, Firefox will just append your element as the last child of the parent element.</p> - -<p>All you need for the string bundle is an id (to be able to fetch the element later) and the chrome path to the properties file. And, of course, you need the properties file:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">xulshoolhello.greeting.label = Hi! How are you?</pre> -</div> -</div> - -<p>The whitespace around the equals sign is ignored. Just like in <em>install.rdf</em>, comments can be added using the # character at the beginning of the line. Empty lines are ignored as well.</p> - -<p>You will often want to include dynamic content as part of localized strings, like when you want to inform the user about some stat related to the extension. For example: "Found 5 words matching the search query". Your first idea would probably be to simply concatenate strings, and have one "Found" property and another "words matching..." property. This is not a good idea. It greatly complicates the work of localizers, and grammar rules on different languages may change the ordering of the sentence entirely. For this reason it's better to use parameters in the properties:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">xulshoolhello.search.label = Found %S words matching the search query!</pre> -</div> -</div> - -<p>Then you use <a href="/en/XUL/stringbundle#m-getFormattedString" title="en/XUL/stringbundle#m-getFormattedString">getFormattedString</a> instead of <em>getString</em> in order to get the localized string. Thanks to this we don't need to have multiple properties, and life is easier for translators. You can read more about it on the <a href="/en/XUL_Tutorial/Property_Files#Text_Formatting" title="en/XUL Tutorial/Property Files#Text Formatting">Text Formatting section</a> of the XUL Tutorial. Also have a look at the <a href="/en/Localization_and_Plurals" title="en/Localization and Plurals">Plurals and Localization</a> article, that covers a new localization feature in Firefox 3 that allows you to further refine this last example to handle different types of plural forms that are also language-dependent.</p> - -<h3 id="Skin">Skin</h3> - -<p>Styling XUL is very similar to styling HTML. We'll look into some of the differences when we cover the XUL Box Model, and other more advanced topics. There isn't much styling you can do to a minimal menu and a very simple alert message, so the Hello World extension only includes an empty CSS file and the compulsory global skin file:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><?xml-stylesheet type=<span class="code-quote">"text/css"</span> href=<span class="code-quote">"chrome:<span class="code-comment">//global/skin/"</span> ?> -</span><?xml-stylesheet type=<span class="code-quote">"text/css"</span> - href=<span class="code-quote">"chrome:<span class="code-comment">//xulschoolhello/skin/browserOverlay.css"</span> ?></span></pre> -</div> -</div> - -<p>The global skin CSS file holds the default styles for all XUL elements and windows. Forgetting to include this file in a XUL window usually leads to interesting and often unwanted results. In our case we don't really need to include it, since we're overlaying the main browser XUL file, and that file already includes this global CSS. At any rate it's better to always include it. This way it's harder to make the mistake of not including it. You can enter the chrome path in the location bar and inspect the file if you're curious.</p> - -<p>This covers all of the files in the Hello World extension. Now you should have an idea of the basics involved in extension development, so now we'll jump right in and set up a development environment. But first, a little exercise.</p> - -<h2 id="Exercise">Exercise</h2> - -<p>Change the welcome message that is displayed in the alert window and move the Hello World menu to the Tools Menu, where it belongs. Repackage the XPI and re-install it. You can just drag the XPI file to the browser and it will be installed locally. Test it and verify your changes worked. If you run into problems at installation, it's likely that you didn't reproduce the XPI structure correctly, maybe adding unnecessary folders. Note that on Firefox 4 and above, on Windows and some Linux distributions, the Tools menu is hidden by default. It can be enabled using the Alt key.</p> - -<p>Once you're done, you can look at this reference solution: <a href="/@api/deki/files/5141/=xulschoolhello2.xpi" title="https://developer.mozilla.org/@api/deki/files/5141/=xulschoolhello2.xpi">Hello World 2</a>.</p> - -<p>{{ PreviousNext("Escuela_XUL/Introducción_a_las_extensiones_de_Firefox", "Escuela_XUL/Montando_un_ambiente_de_desarrollo") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/enlazando_contenido_remoto/index.html b/files/es/mozilla/tech/xul/escuela_xul/enlazando_contenido_remoto/index.html deleted file mode 100644 index bc80d6b948..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/enlazando_contenido_remoto/index.html +++ /dev/null @@ -1,231 +0,0 @@ ---- -title: Enlazando contenido remoto -slug: Mozilla/Tech/XUL/Escuela_XUL/Enlazando_contenido_remoto -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Connecting_to_Remote_Content ---- -<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}}{{AddonSidebar}}</p> - -<p>{{ PreviousNext("Escuela_XUL/Interceptando_cargas_de_página", "Escuela_XUL/Personalizar_elementos_XUL_con_XBL") }}</p> - -<h2 id="Using_XMLHttpRequest">Using XMLHttpRequest</h2> - -<p><a href="/en/nsIXMLHttpRequest" title="en/XMLHttpRequest">XMLHttpRequest</a> is an API for transferring XML between a local script and a remote server via HTTP. It is an integral part of the modern web, and all major browsers support it. Besides XML, it can be used to retrieve data in other formats, for example JSON, HTML and plain text. In this section we'll look into the XML and JSON communication mechanisms.</p> - -<pre class="brush: js">let url = "<a class="external" href="http://www.example.com/" rel="freelink">http://www.example.com/</a>"; -let request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] - .createInstance(Components.interfaces.nsIXMLHttpRequest); -request.onload = function(aEvent) { - window.alert("Response Text: " + aEvent.target.responseText); -}; -request.onerror = function(aEvent) { - window.alert("Error Status: " + aEvent.target.status); -}; -request.open("GET", url, true); -request.send(null); -</pre> - -<p>In this example we demonstrate how to make a XMLHttpRequest call in asynchronous mode. You can see that an instance of the XMLHttpRequest class is created and it holds all functionality for making a request. We create this instance using XPCOM instead of the usual way (<code>new XMLHttpRequest()</code>) because this way works both in chrome and non-chrome code.</p> - -<p>Following initialization, <em>onload</em> and <em>onerror</em> handlers are registered to a callback function to handle the response returned from the remote server. In both cases <em>aEvent.target</em> is an {{ interface("nsIXMLHttpRequest") }}. In the <em>onload</em> callback function, the <em>responseText</em> parameter contains the server response as text.</p> - -<p>If the response is an XML document, the <em>responseXML</em> property will hold an XMLDocument object that can be manipulated using DOM methods. Sometimes the server doesn't specify an XML Content-Type header, which is necessary for the XML parsing to happen automatically. You can use <em>overrideMimeType</em> to force the response to be parsed as XML.</p> - -<pre class="brush: js">request.overrideMimeType("text/xml"); // do this before sending the request! -</pre> - -<p>The <em>open</em> method takes two required parameters: the HTTP request method and the URL to send the request. The HTTP request method can be "GET", "POST" or "PUT". Sending a POST request requires you to set the content type of the request and to pass the post data to the send() method as below.</p> - -<pre class="brush: js">request.open("POST", url, true); -request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); -request.send("data=hello&version=2"); -</pre> - -<p>The third parameter for the <em>open</em> method specifies whether the request should be handled asynchronously or not. In asynchronous mode code execution continues immediately after the <em>send</em> call. In synchronous mode the code and user interface are blocked while waiting for a response to come back.</p> - -<div class="note"><strong>Note:</strong> Requests can take a long time to process and you don't want users to be stuck waiting while a request is obtained and processed. Therefore, <strong>it is very important that XMLHttpRequest calls are always done asynchronously</strong>.</div> - -<p>Now let's look at the most common types of content you can use to communicate with remote servers.</p> - -<h2 id="JSON_content">JSON content</h2> - -<p><a href="/en/JSON" title="en/JSON">JSON</a> is a very lightweight and simple data representation format, similar to the object representation used in JavaScript. Unlike JavaScript, the JSON format doesn't allow any kind of code that can be run, only data.</p> - -<p>JSON used to be risky in terms of security because the favored way of parsing it was to use the JavaScript <a href="/en/eval" title="en/eval">eval</a> function. Since <em>eval</em> executes any code contained in the string, workarounds had to be devised in order to close security holes. Luckily, Firefox now provides a few alternatives for extension developers. The <a href="/en/JSON" title="en/JSON">JSON</a> page explains in detail how to parse JSON data in different versions of Firefox and other applications.</p> - -<p>Assume we need to parse the following data:</p> - -<pre class="brush: js">{"shops": [{"name": "Apple", "code": "A001"}, {"name": "Orange"}], "total": 100} -</pre> - -<p>When the <em>onload</em> callback function is called, the response text is converted into a JS object using the <em>parse</em> method. You can then use this object like any other JavaScript objects in your code.</p> - -<pre class="brush: js">request.onload = function(aEvent) { - let text = aEvent.target.responseText; - let jsObject = JSON.parse(text); - - window.alert(jsObject.shops[1].name); // => "Orange" - window.alert(jsObject.total); // => 2; -}; -</pre> - -<p>The JavaScript object can also be serialized back with the <em>stringify</em> method.</p> - -<pre class="code-javascript">let string = JSON.stringify(jsObject); -</pre> - -<h2 id="XML_content">XML content</h2> - -<p>XML is possibly the most popular data interchange format. Let's assume that the XML returned from remote server is this:</p> - -<pre class="code-xml"><span class="code-tag"><?xml version=<span class="code-quote">"1.0"</span>?></span> -<span class="code-tag"><data></span> - <span class="code-tag"><shops></span> - <span class="code-tag"><shop></span> - <span class="code-tag"><name></span>Apple<span class="code-tag"></name></span> - <span class="code-tag"><code></span>A001<span class="code-tag"></code></span> - <span class="code-tag"></shop></span> - <span class="code-tag"><shop></span> - <span class="code-tag"><name></span>Orange<span class="code-tag"></name></span> - <span class="code-tag"></shop></span> - <span class="code-tag"></shops></span> - <span class="code-tag"><total></span>2<span class="code-tag"></total></span> -<span class="code-tag"></data></span> -</pre> - -<p>When a valid XML response comes back from the remote server, the XML document object can be manipulated using different DOM methods, to display the data in the UI or store it into a local datasource.</p> - -<pre class="brush: js">request.onload = function(aEvent) { - let responseXML = aEvent.target.responseXML; - let rootElement = responseXML.documentElement; - - if (rootElement && "parseerror" != rootElement.tagName) { - let shopElements = rootElement.getElementsByTagName("shop"); - let totalElement = rootElement.getElementsByTagName("total")[0]; - - window.alert(shopElements[1].getElementsByTagName("name")[0].firstChild.nodeValue); // => Orange - window.alert(totalElement.firstChild.nodeValue); // => 2 - } -}; -</pre> - -<p>Using DOM functions is good for simple XML documents, but DOM manipulation code can become too complicated if the documents are more complex. There are a couple of tools you can use to process these documents more efficiently:</p> - -<h3 id="Using_XPath">Using XPath</h3> - -<blockquote> -<p>XPath stands for XML Path Language, it uses a non-XML syntax that provides a flexible way of addressing (pointing to) different parts of an XML document.</p> -</blockquote> - -<p>Taken from the <a href="/en/XPath" title="en/XPath">XPath page</a>.</p> - -<p>You can use XPath to quickly access specific nodes in an XML or HTML document with a simple query mechanism. XPath can also be used to extract information from web pages once they load, along with the page load interception techniques discussed previously.</p> - -<p>XPath is very useful for cases when you're receiving large and complex XML files, and you only need some of the data contained in them. Using XPath to parse a complete XML document is probably not a good idea performance-wise.</p> - -<h3 id="Using_XSLT">Using XSLT</h3> - -<p><a href="/en/XSLT" title="en/XSLT">XSLT</a> (eXtensible Stylesheet Language Transformations) is another tool used to manipulate XML documents and transform them into other forms of text output, such as HTML, XUL, and so on.</p> - -<p>We can not cover all transformations to various output formats, so we'll just look into converting an XML document to XUL.</p> - -<p>First you need to create an XSLT stylesheet that acts as a template. This template will transform the XML you receive (in our case, the example XML document above) and convert it into XUL. The <a class="external" href="http://www.w3schools.com/xsl/">XSLT tutorial</a> contains details for building these templates.</p> - -<pre class="code-xml"><span class="code-tag"><?xml version=<span class="code-quote">"1.0"</span> encoding=<span class="code-quote">"utf-8"</span>?></span> -<<span class="code-keyword">xsl:stylesheet</span> version=<span class="code-quote">"1.0"</span> - <span class="code-keyword">xmlns:xsl</span>=<span class="code-quote">"http://www.w3.org/1999/XSL/Transform"</span> - <span class="code-keyword">xmlns:xul</span>=<span class="code-quote">"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"</span>> - <span class="code-tag"><<span class="code-keyword">xsl:template</span> match=<span class="code-quote">"/data"</span>></span> - <span class="code-tag"><xul:vbox></span> - <span class="code-tag"><<span class="code-keyword">xsl:for-each</span> select=<span class="code-quote">"shops/name"</span>></span> - <span class="code-tag"><xul:hbox></span> - <span class="code-tag"><xul:label value=<span class="code-quote">"Name:"</span> /></span> - <span class="code-tag"><xul:label></span> - <span class="code-tag"><<span class="code-keyword">xsl:value-of</span> select=<span class="code-quote">"."</span> /></span> - <span class="code-tag"></xul:label></span> - <span class="code-tag"></xul:hbox></span> - <span class="code-tag"></<span class="code-keyword">xsl:for-each</span>></span> - <span class="code-tag"><xul:hbox></span> - <span class="code-tag"><xul:label value=<span class="code-quote">"Total:"</span> /></span> - <span class="code-tag"><xul:label></span> - <span class="code-tag"><<span class="code-keyword">xsl:value-of</span> select=<span class="code-quote">"total"</span> /></span> - <span class="code-tag"></xul:label></span> - <span class="code-tag"></xul:hbox></span> - <span class="code-tag"></xul:vbox></span> - <span class="code-tag"></<span class="code-keyword">xsl:template</span>></span> -<span class="code-tag"></<span class="code-keyword">xsl:stylesheet</span>></span> -</pre> - -<p>Next you need to read the XSLT stylesheet as a file stream and parse it into a document object. After that, the XSLT stylesheet can be imported into an XSLT processor as shown below. Now, the processor is ready to perform the transformation.</p> - -<pre class="brush: js">let domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"] - .createInstance(Components.interfaces.nsIDOMParser); -let fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"] - .createInstance(Components.interfaces.nsIFileInputStream); -let xsltProcessor = Components.classes["@mozilla.org/document-transformer;1?type=xslt"] - .createInstance(Components.interfaces.nsIXSLTProcessor); -let xslDocument; - -fileStream.init(someXSLFile, -1, 0x01, 0444); // read only - -// parse from the XSLT stylesheet file stream -xslDocument = domParser.parseFromStream( - fileStream, null, fileStream.available(), "text/xml"); - -// import the XSLT stylesheet to the XSLT processor -xsltProcessor.importStylesheet(xslDocument); -</pre> - -<p>Finally, you can either use {{ ifmethod("nsIXSLTProcessor","transformToDocument") }} or {{ ifmethod("nsIXSLTProcessor","transformToFragment") }} methods to transform the XML document. The {{ ifmethod("nsIXSLTProcessor","transformToDocument") }} method returns a DOM Document with the results of the transformation, whereas, the {{ ifmethod("nsIXSLTProcessor","transformToFragment") }} method returns a DOM DocumentFragment node. In this example code, the first child of the XUL document is appended to a XUL element after the transformation.</p> - -<pre class="brush: js">request.onload = function(aEvent) { - let responseXML = aEvent.target.responseXML; - let xulNode; - - // transform the XML document to a XUL document - xulDocument = xsltProcessor.transformToDocument(responseXML); - - // append the XUL node to a XUL element - xulNode = document.adoptNode(xulDocument.firstChild); - document.getElementById("foo").appendChild(xulNode); -}; -</pre> - -<p>We effectively transformed the XML file into XUL and integrated it into the UI.</p> - -<div class="note"><strong>Note:</strong> Security should be your number one priority when handling remote content. Do not allow event handlers or any other kinds of code to be passed through your parsers. If you need your generated XUL to have JS code in it, all of it should be added locally, never from the remote source.</div> - -<p>Here are a couple of practical situations were you may want to use XSLT:</p> - -<ol> - <li>Convert a large XML document directly into XUL.</li> - <li>Filter a complex XML file and generate a simpler XML document with only the data you need, so then you can use regular DOM functions to read it.</li> - <li>Convert XML into SQL statements. You could use this to generate a script to run on your local database. You would of course need to be very careful about escaping characters and protecting yourself against SQL injection attacks.</li> - <li>Convert XML into RDF. This was more useful when RDF was the default storage format. You can still use RDF as an intermediate format, though, and then use templates to generate XUL and display the data.</li> -</ol> - -<h2 id="HTTP_debugging">HTTP debugging</h2> - -<p>When you start debugging HTTP requests, you may find it hard to know exactly what data was sent, especially with POST data. We recommend you to use extensions like <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/966">Tamper Data</a>. They help you to track HTTP/HTTPS requests and responses occurring in Firefox.</p> - -<p>After installation, you can find a Tamper Data menu item in the menu bar:</p> - -<ul> - <li>Tools > Tamper Data or</li> - <li>View > Sidebar > Tamper Data</li> -</ul> - -<p>Once you open the Tamper Data view, all requests and responses will begin to appear in it. You can discover some interesting things about Firefox like this, such as the automatic update URLs for extensions, and the behavior of web applications such as Gmail.</p> - -<p>If you click on the "Start Tamper" button, for every request made you will get a popup dialog for tampering with it before it is sent. You can use it to view or even modify the data in a request, and then inspect the result. This can be a lot of work because there is a lot of web activity in a normal Firefox window, so use it sparingly.</p> - -<p>A tutorial on Tamper Data can be found <a class="external" href="http://www.jimbojw.com/wiki/index.php?title=Tamper_Data">here</a>.</p> - -<div class="note"><strong>Note:</strong> You should always test your connection code to cover edge cases, like when there is no Internet connection, or the computer is connected to a local network with no Internet access (like at an airport or hotel room). Make sure you're not telling users everything is OK, or worse, bombarding them with error messages.</div> - -<p>{{ PreviousNext("Escuela_XUL/Interceptando_cargas_de_página", "Escuela_XUL/Personalizar_elementos_XUL_con_XBL") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/index.html b/files/es/mozilla/tech/xul/escuela_xul/index.html deleted file mode 100644 index 94497a9507..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/index.html +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Escuela XUL -slug: Mozilla/Tech/XUL/Escuela_XUL -tags: - - Plugins - - Rerencias - - Tutoriales - - XUL - - extensiones -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School ---- -<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>{{AddonSidebar}}</p> - -<p>El proyecto Escuela <a href="/es/XUL" title="es/XUL">XUL</a> es un tutorial completo para la creación de extensiones, enfocándose en el desarrollo de extensiones para Firefox. Es recomendable que lo leas completamente al menos una vez. Como Firefox cambia rápidamente, el contenido en este tutorial debería ser actual y válido.</p> - -<dl> - <dt>Introducción</dt> - <dd> - <ul> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Introduction" title="es/Escuela XUL/Introducción">Introducción</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Getting_Started_with_Firefox_Extensions" title="en/XUL School/Getting Started with Firefox Extensions">Comenzando con las Extensiones de Firefox</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/The_Essentials_of_an_Extension" title="es/Escuela XUL/Elementos esenciales de una extensión">Elementos Esenciales de una Extensión</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Setting_Up_a_Development_Environment" title="es/Escuela XUL/Montando un ambiente de desarrollo">Configurando un Ambiente de Desarrollo</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/JavaScript_Object_Management" title="es/Escuela XUL/Uso de objetos en JavaScript">Uso de Objetos en JavaScript</a></li> - </ul> - </dd> - <dt>Funcionalidad básica</dt> - <dd> - <ul> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Adding_menus_and_submenus" title="es/Escuela XUL/Agregar menus y submenus">Agregar menus y submenus</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Adding_Toolbars_and_Toolbar_Buttons" title="es/Escuela XUL/Agregar barras de herramientas y botones para éstas">Agregar barras de herramientas y botones para éstas</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Adding_Events_and_Commands" title="es/Escuela XUL/Agregar eventos y comandos">Agregar eventos y comandos</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Adding_windows_and_dialogs" title="es/Escuela XUL/Agregar ventanas y dialogos">Agregar ventanas y dialogos</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Adding_sidebars" title="es/Escuela XUL/Agregar barras laterales">Agregar barras laterales</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/User_Notifications_and_Alerts" title="es/Escuela XUL/Notificaciones de usuario y alertas">Notificaciones de usuario y alertas</a></li> - </ul> - </dd> - <dt>Funcionalidad intermedia</dt> - <dd> - <ul> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Intercepting_Page_Loads" title="es/Escuela XUL/Interceptando cargas de página">Interceptando cargas de página</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Connecting_to_Remote_Content" title="es/Escuela XUL/Enlazando contenido remoto">Conexión con Contenido Remoto</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Handling_Preferences" title="es/Escuela XUL/Manejo de preferencias">Manejo de preferencias</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Local_Storage" title="es/Escuela XUL/Almacenamiento local">Almacenamiento Local</a></li> - </ul> - </dd> - <dt>Temas avanzados</dt> - <dd> - <ul> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/The_Box_Model" title="es/Escuela XUL/El modelo de caja">El modelo de caja</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/XPCOM_Objects" title="es/Escuela XUL/Objetos XPCOM">Objetos XPCOM</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Observer_Notifications" title="es/Escuela XUL/Notificaciones Observer">Notificaciones Observer</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Custom_XUL_Elements_with_XBL" title="es/Escuela XUL/Personalizar elementos XUL con XBL">Personalizar elementos XUL con XBL</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Mozilla_Documentation_Roadmap" title="es/Escuela XUL/Documentación de Mozilla">Documentación de Mozilla</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Useful_Mozilla_Community_Sites" title="es/Escuela XUL/Sitios útiles de la comunidad Mozilla">Sitios útiles de la comunidad Mozilla</a></li> - </ul> - </dd> - <dt>Apéndices</dt> - <dd> - <ul> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Appendix_A:_Add-on_Performance" title="es/Escuela XUL/Apéndice A: Rendimiento de los Add-ons">Apéndice A: Rendimiento de los Add-ons</a></li> - <li><a href="/es/Escuela_XUL/Apéndice_B:_Instalar_y_desinstalar_Scripts" title="en/XUL School/Appendix B: Install and Uninstall Scripts">Ap</a><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Appendix_B:_Install_and_Uninstall_Scripts" title="es/Escuela XUL/Apéndice A: Rendimiento de los Add-ons">éndice</a><a href="/es/Escuela_XUL/Apéndice_B:_Instalar_y_desinstalar_Scripts" title="es/Escuela XUL/Apéndice B: Instalar y desinstalar Scripts"> B: Instalar y desinstalar Scripts</a></li> - <li><a href="/es/Escuela_XUL/Apéndice_C:_Evitar_usar_eval_en_los_Add-ons" title="es/Escuela XUL/Apéndice C: Evitar usar eval en los Add-ons">Ap</a><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Appendix_C:_Avoid_using_eval_in_Add-ons" title="es/Escuela XUL/Apéndice A: Rendimiento de los Add-ons">éndice</a><a href="/es/Escuela_XUL/Apéndice_C:_Evitar_usar_eval_en_los_Add-ons" title="es/Escuela XUL/Apéndice C: Evitar usar eval en los Add-ons"> C: Evitar usar eval en los Add-ons</a></li> - <li><a href="/es/Escuela_XUL/Apéndice_D:_Cargar_Scripts" title="es/Escuela XUL/Apéndice D: Cargar Scripts">Ap</a><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Appendix_D:_Loading_Scripts" title="es/Escuela XUL/Apéndice A: Rendimiento de los Add-ons">éndice</a><a href="/es/Escuela_XUL/Apéndice_D:_Cargar_Scripts" title="es/Escuela XUL/Apéndice D: Cargar Scripts"> D: Cargar Scripts</a></li> - <li><a href="/es/Escuela_XUL/Apéndice_E:_DOM_e_inserción_HTML" title="es/Escuela XUL/Apéndice E: DOM e inserción HTML">Ap</a><a href="/es/Escuela_XUL/Apéndice_A:_Rendimiento_de_los_Add-ons" title="es/Escuela XUL/Apéndice A: Rendimiento de los Add-ons">éndice</a><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/DOM_Building_and_HTML_Insertion" title="es/Escuela XUL/Apéndice E: DOM e inserción HTML"> E: DOM e inserción HTML</a></li> - <li><a href="https://developer.mozilla.org/en-US/docs/XUL/School_tutorial/Appendix_F:_Monitoring_DOM_changes" title="XUL/School_tutorial/Appendix F: Monitoring DOM changes">Appendix F: Monitoreando cambios DOM</a></li> - </ul> - </dd> -</dl> - -<p>El proyecto Escuela <a href="/es/XUL" title="es/XUL">XUL</a> fue desarrollado por <a class="external" href="http://appcoast.com/" title="http://appcoast.com/">Appcoast</a> (Anteriormente Glaxstar). El proyecto es ahora publicado aquí bajo las <a href="https://developer.mozilla.org/Project:Copyrights" title="https://developer.mozilla.org/Project:Copyrights">siguientes licencias</a>. Su contenido ha sido necesariamente modificado de la fuente original.</p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/introducción_a_las_extensiones_de_firefox/index.html b/files/es/mozilla/tech/xul/escuela_xul/introducción_a_las_extensiones_de_firefox/index.html deleted file mode 100644 index 758ef60e25..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/introducción_a_las_extensiones_de_firefox/index.html +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: Introducción a las extensiones de Firefox -slug: Mozilla/Tech/XUL/Escuela_XUL/Introducción_a_las_extensiones_de_Firefox -translation_of: >- - Archive/Add-ons/Overlay_Extensions/XUL_School/Getting_Started_with_Firefox_Extensions ---- -<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}}{{AddonSidebar}}</p> - -<p>{{ PreviousNext("Escuela_XUL/Introducción", "Escuela_XUL/Elementos_esenciales_de_una_extensión") }}</p> - -<h2 id="What's_a_Firefox_Extension">What's a Firefox Extension?</h2> - -<blockquote> -<p>Extensions add new functionality to Mozilla applications such as Firefox and Thunderbird. They can add anything from a toolbar button to a completely new feature. They allow the application to be customized to fit the personal needs of each user if they need additional features, while keeping the applications small to download.</p> -</blockquote> - -<p>Taken from the <a href="/es/Extensiones" title="es/Extensiones">Extensions page</a>.</p> - -<p>As described in the quoted text, an extension is a small application that adds something new to one or more Mozilla applications. This tutorial focuses on extensions for Firefox, but the same (or very similar) principles apply to creating extensions for other applications such as Thunderbird, Seamonkey, and Flock.</p> - -<p>It is also worth noting that there are differences between the definition of <em>extension</em> and <em>add-on</em>. All extensions are add-ons, but add-ons can also be themes, plugins, or language packs. This tutorial is about extension development, but themes and language packs are developed in a very similar way. Plugins are entirely different, and they will not be covered on this tutorial. You can read more about plugins and their development in the <a href="/en/Plugins" title="en/Plugins">Plugins page</a>.</p> - -<p>Firefox provides a very rich and flexible architecture that allows extension developers to add advanced features, customize the user's experience, and completely replace and remove parts of the browser. The <a class="link-https" href="https://addons.mozilla.org" title="https://addons.mozilla.org/">Mozilla Add-ons</a> repository (AMO) holds an extensive number of extensions with a wide variety of functions: content filtering (<a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/1865" title="https://addons.mozilla.org/en-US/firefox/addon/1865">AdBlock Plus</a>, <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/722" title="https://addons.mozilla.org/en-US/firefox/addon/722">NoScript</a>), web application interaction (<a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/3615" title="https://addons.mozilla.org/en-US/firefox/addon/3615">Delicious Bookmarks</a>, <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/5202" title="https://addons.mozilla.org/en-US/firefox/addon/5202">eBay Companion</a>), web development (<a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/6622" title="https://addons.mozilla.org/en-US/firefox/addon/6622">DOM Inspector</a>, <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/1843" title="https://addons.mozilla.org/en-US/firefox/addon/1843">Firebug</a>), and child protection (<a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/5881" title="https://addons.mozilla.org/en-US/firefox/addon/5881">Glubble For Families</a>). These are very advanced and complex extensions, and you'll learn most of what it takes to create extensions like these (Glaxstar actually worked on 3 of those listed).</p> - -<p>We'll begin by looking into a very simple extension.</p> - -<h2 id="The_Hello_World_Extension">The Hello World Extension</h2> - -<p>Our sample extensions and this tutorial in general are meant for Firefox version 3 and above, but most of it works on previous versions of Firefox as well. We'll try to make it clear when we're discussing a feature that only works on some versions of Firefox.</p> - -<p>We'll now begin with a basic "Hello World" extension. Let's start by installing the extension. Click on the link below.</p> - -<p><a href="/@api/deki/files/5139/=xulschoolhello1.xpi" title="https://developer.mozilla.org/@api/deki/files/5139/=xulschoolhello1.xpi">Install Hello World</a></p> - -<p>This will either trigger an install or a file download, depending on the Content-type the webserver is using to serve the file. The appropriate content type to trigger an install is <strong>application/x-<strong>xpinstall</strong></strong>. In this case a file download should occur.</p> - -<p>If the content type is set correctly, you will probably get notified that the site is not allowed to install add-ons on Firefox. This is a security measure that prevents sites from installing extensions without user consent. This is necessary because malicious extensions can do the same level of harm as any malicious program: stealing data, erasing or replacing files, and causing unwanted behavior in general. AMO is the only pre-allowed site because all published add-ons on AMO have gone through a review process that includes security checks.</p> - -<p>After downloading the file, you can drag and drop it into the Firefox content area, and the installation should begin.</p> - -<p>You'll see a window telling you that you're about to install an extension, with some additional information such as the name of the author. You'll see a message saying that the author cannot be verified. Only extensions signed with a digital certificate can verify authorship. Signed extensions are rare, but we'll cover how to sign them later on.</p> - -<p>Click on the Install Now button. After the extension is installed, you'll be asked to restart Firefox. Installing, uninstalling, enabling and disabling add-ons (except plugins) require a restart to complete, and there's no easy way to work around it. This is an important point to keep in mind if you're building an extension that manipulates other extensions or themes. There's a <a class="link-https" href="https://bugzilla.mozilla.org/show_bug.cgi?id=256509" title="https://bugzilla.mozilla.org/show_bug.cgi?id=256509">very old bug</a> that tracks this issue.</p> - -<p>Now, after restarting the browser, you'll see the Add-ons Manager window, showing the extension name, version, and a brief description.</p> - -<p><img alt="addonman.png" class="default internal" src="/@api/deki/files/4137/=addonman.png"></p> - -<p>Close the Add-ons window. Look at the main Firefox window and see if you notice anything different.</p> - -<p>Did you see it? There's a new menu on the main menu bar, labeled "Hello World!". If you open the menu and then the menu item below, you'll see a nice alert message (for some definitions of 'nice'). Click on the OK button to close it.</p> - -<p><img alt="" class="internal" src="/@api/deki/files/4138/=helloworldalert.png" style="height: 126px; width: 326px;"></p> - -<p>That's all the extension does. Now let's take a closer look at it.</p> - -<h2 id="Extension_Contents">Extension Contents</h2> - -<p>You may have noticed that the extension file you installed is named xulschoolhello1.xpi. <a href="/en/XPI" title="en/XPI">XPI</a> (pronounced "zippy") stands for Cross-Platform Installer, because the same installer file can work on all major platforms, and this is the case for most extension XPIs. XPIs are simply compressed ZIP files, but Firefox recognizes the XPI extension and triggers the installation process when an XPI link is clicked.</p> - -<p>To look into the XPI file you need to download it first, not install it. If the server triggers an install when clicking on a link or button, what you need to do is right click on the <a href="/@api/deki/files/4225/=xulschoolhello1.xpi" title="https://developer.mozilla.org/@api/deki/files/4225/=xulschoolhello1.xpi">install link</a>, and choose the Save Link As... option.</p> - -<p>Next, we'll decompress the XPI file. One way to do this is to rename the file so that it uses the <em>zip</em> extension instead of the <em>xpi</em>. Another way is to open the file using a ZIP tool. Most operating systems ship with a ZIP compression utility, and there are more advanced tools available online. Make your pick, and decompress the file in a convenient location. You should see a directory structure similar to this one:</p> - -<ul> - <li>xulschoolhello1 - <ul> - <li>chrome.manifest</li> - <li>install.rdf</li> - <li>chrome - <ul> - <li>xulschoolhello.jar</li> - </ul> - </li> - </ul> - </li> -</ul> - -<p>The JAR file contains most of the code, so we'll need to extract the contents of that file as well. Just like XPIs, all you need is a ZIP utility to decompress the file. After doing that, you'll have something like this:</p> - -<ul> - <li>xulschoolhello1 - <ul> - <li>chrome.manifest</li> - <li>install.rdf</li> - <li>chrome - <ul> - <li>xulschoolhello.jar</li> - <li>xulschoolhello - <ul> - <li>content - <ul> - <li>browserOverlay.xul</li> - <li>browserOverlay.js</li> - </ul> - </li> - <li>locale - <ul> - <li>en-US - <ul> - <li>browserOverlay.dtd</li> - <li>browserOverlay.properties</li> - </ul> - </li> - </ul> - </li> - <li>skin - <ul> - <li>browserOverlay.css</li> - </ul> - </li> - </ul> - </li> - </ul> - </li> - </ul> - </li> -</ul> - -<p>That's a lot of files for something so simple! Well, don't worry, we'll shortly see the purpose of all of these files and realize this <em>is</em> quite simple. In the next section we'll inspect these files and see what they do.</p> - -<p>{{ PreviousNext("Escuela_XUL/Introducción", "Escuela_XUL/Elementos_esenciales_de_una_extensión") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/introduction/index.html b/files/es/mozilla/tech/xul/escuela_xul/introduction/index.html deleted file mode 100644 index f6fd9f2d96..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/introduction/index.html +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Introduction -slug: Mozilla/Tech/XUL/Escuela_XUL/Introduction -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Introduction ---- -<div>{{Next("XUL_School/Getting_Started_with_Firefox_Extensions")}}</div> - -<p>Welcome to the XUL School Tutorial!</p> - -<p>This tutorial is meant to be the stepping stone that will turn you into a professional Firefox extension developer in no time. We have poured years of XUL experience into it, providing many solutions for problems extension developers commonly run into.</p> - -<p>XUL School was created by <a href="http://appcoast.com/" title="http://appcoast.com/">Appcoast</a> (formerly Glaxstar), one of the few companies dedicated to building high-quality Firefox extensions. A team of over a dozen XUL developers conformed Glaxstar at the time this tutorial was created, and the combined experiences of years creating Firefox extensions are reflected here.</p> - -<p>With this tutorial you'll learn how to develop Firefox extensions. You'll learn how to quickly do the most common tasks in extension development, comparing several different approaches to solve them. In most cases we'll provide code samples that you can easily copy and adapt to your needs, as well as some working example extensions. The tutorial aims to be as brief as possible, often falling back on Mozilla documentation for more detailed information. You can think of it as a quick guide to the expansive world that is the Mozilla platform. Most links in this documentation are meant to be clicked and read.</p> - -<p>We'll start with a brief introduction to some key concepts, in case you're not familiar with Mozilla and Firefox.</p> - -<h2 id="Mozilla_and_Firefox">Mozilla and Firefox</h2> - -<p>The term <a href="http://en.wikipedia.org/wiki/Mozilla" title="http://en.wikipedia.org/wiki/Mozilla">Mozilla</a> can be used to refer to several concepts: the Mozilla project, the <a href="http://en.wikipedia.org/wiki/Mozilla_Foundation" title="http://en.wikipedia.org/wiki/Mozilla_Foundation">Mozilla Foundation</a>, the <a href="http://en.wikipedia.org/wiki/Mozilla_Corporation" title="http://en.wikipedia.org/wiki/Mozilla_Corporation">Mozilla Corporation</a> and the old <a href="http://en.wikipedia.org/wiki/Mozilla_Application_Suite" title="http://en.wikipedia.org/wiki/Mozilla_Application_Suite">Mozilla browser</a>. Even Firefox is sometimes referred to as "Mozilla". If you're unfamiliar with these terms, it's good that you take some time and learn a little about Mozilla. This will help you understand the culture that surrounds the Mozilla community.</p> - -<p>Mozilla has spawned several <a href="http://www.mozilla.org/projects/" title="http://www.mozilla.org/projects/">products and projects</a>, the most notable being the Mozilla Firefox web browser. Firefox is one of the most successful open source projects in history, combining the openness, standards-compliance and sophistication of open source with the focus on user experience and powerful outreach more commonly seen in less open companies.</p> - -<p>Version 1.0 of Firefox was released in November 2004, version 2.0 in October 2006, and version 3.0 in June 2008. This tutorial was written after Firefox 3 was released, and has been updated with time. While most of it should still work for creating extensions in Firefox 3 (and even Firefox 2), it is strongly recommended that you aim to support modern Firefox versions, to encourage users to stay up to date with security fixes. A release that is more than 6 months old is likely vulnerable to published security bugs.</p> - -<p>Firefox y otras aplicaciones Mozilla pueden ser vistas como composed of two different parts: a user interface layer that is distinct for each project, and a common platform on top of which the interface layer is built. The user interface is built with technology known as <a href="/en-US/docs/XUL" title="XUL">XUL</a>, and the platform is known as <a href="/en-US/docs/XULRunner" title="XULRunner">XULRunner</a>.</p> - -<h2 id="XUL">XUL</h2> - -<p><a href="/en-US/docs/XUL" title="XUL">XUL</a> (pronounced "zool") is one of many technologies used for creating Mozilla-based products and extensions. It is only one part of the development landscape, but given that it's practically exclusive to Mozilla, it tends to be used to identify all Mozilla-related development. You'll sometimes read terms like "XUL applications" and "XUL extensions", but rarely will they refer to projects that are exclusively built with XUL. It usually means that the projects were built using Mozilla technologies. Even this project, called XUL School, covers several other technologies such as JavaScript, CSS, XBL and XPCOM.</p> - -<h2 id="XULRunner">XULRunner</h2> - -<p><a href="/en-US/docs/XULRunner" title="XULRunner">XULRunner</a> includes the <a href="/en-US/docs/Gecko" title="Gecko">Gecko rendering engine</a>, the <a href="/en-US/docs/Necko" title="Necko">Necko networking library</a>, and several other components that provide OS-independent file management, accessibility, and localization, among others. It is this very powerful platform that has allowed such a fast growth of the development community surrounding Mozilla and Firefox.</p> - -<p>XULRunner is available in binary form at the <a href="/en-US/docs/XULRunner" title="XULRunner">XULRunner</a> page, and it is the base for several projects, such as Songbird, Miro and Eudora. There's a very comprehensive list of XULRunner applications in the <a href="/en-US/docs/XULRunner_Hall_of_Fame" title="XULRunner Hall of Fame">XULRunner Hall of Fame</a>.</p> - -<h3 id="Gecko">Gecko</h3> - -<p>The <a href="/en-US/docs/Gecko" title="Gecko">Gecko engine</a> is the part of Firefox used to render web pages and its own user interface. You can identify the level of compatibility of web standards in <a href="http://en.wikipedia.org/wiki/List_of_web_browsers#Gecko-based_browsers" title="http://en.wikipedia.org/wiki/List_of_web_browsers#Gecko-based_browsers">Gecko-based browsers</a> looking at their <a href="http://en.wikipedia.org/wiki/User_agent" title="http://en.wikipedia.org/wiki/User_agent">User Agent</a> string, which should include the Gecko version. Gecko versions are somewhat independent from Firefox versions, and you can see a mapping of Firefox versions and Gecko versions at the <a href="/en-US/docs/Gecko" title="Gecko">Gecko page</a>. The User Agent String for Firefox at the time of this writing (in US English, Mac OS X) is:</p> - -<p>Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:<strong>25.0.1</strong>) Gecko/20100101 Firefox/25.0.1</p> - -<p>The highlighted section is the Gecko version: 25.0.1. You can read and copy the user agent string of any Firefox window, choosing "Help > Troubleshooting Information" from the main menu.</p> - -<h2 id="On_to_the_Tutorial">On to the Tutorial</h2> - -<p>With the basic concepts out of the way, we can now get right into extension development. You are probably still wondering what exactly is an extension, what can it do, and how can you make them. Well, this whole tutorial is devoted to explaining that to you.</p> - -<p>Welcome to the world of extension development. Now let's get to it.</p> - -<div>{{Next("XUL_School/Getting_Started_with_Firefox_Extensions")}}</div> - -<p><small>This tutorial was kindly donated to Mozilla by Appcoast.</small></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/manejo_de_preferencias/index.html b/files/es/mozilla/tech/xul/escuela_xul/manejo_de_preferencias/index.html deleted file mode 100644 index 9c3f436636..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/manejo_de_preferencias/index.html +++ /dev/null @@ -1,305 +0,0 @@ ---- -title: Manejo de preferencias -slug: Mozilla/Tech/XUL/Escuela_XUL/Manejo_de_preferencias -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Handling_Preferences ---- -<blockquote> -<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> -</blockquote> - -<p>{{LegacyAddonsNotice}}{{AddonSidebar}}</p> - -<p>{{ PreviousNext("Escuela_XUL/Notificaciones_Observer", "Escuela_XUL/Almacenamiento_local") }}</p> - -<h2 id="Preferences_in_Firefox">Preferences in Firefox</h2> - -<p>Mozilla applications are highly customizable. Preferences are used to store settings and information to change their default behavior. To open the preferences window in Firefox, select the following from the main menu:</p> - -<ul> - <li>On Windows, Tools > Options</li> - <li>On Mac, Firefox > Preferences</li> - <li>On Linux, Edit > Preferences</li> -</ul> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">Keep in mind the usage of the terms "Preferences" and "Options" in different platforms. If you need to refer to the term "preference" in any of your locale files, you must change the string depending on the operating system. Tip: you can use <a href="/en/DOM/window.navigator.platform" title="en/DOM/window.navigator.platform">window.navigator.platform</a> in your chrome code to figure out the operating system Firefox is running on. You can use the <a href="/en/XPCOM_Interface_Reference/nsIAppShellService#Attributes" title="en/XPCOM Interface Reference/nsIAppShellService#Attributes">Hidden DOM Window</a> in non-chrome code.</div> -</div> -</div> - -<p>Firefox loads user preferences from a number of sources. Each source is a JS file that contains some special functions not available in regular code. The following files are used:</p> - -<ul> - <li>Default preferences: these are stored in the directory <em>defaults/pref</em> in the Firefox installation directory.</li> - <li>Current preferences: these are stored in the profile directory with the name <em>prefs.js</em>. This is where the user's settings are stored. This file is updated when preferences are modified by the user.</li> - <li>User preferences: the file <em>user.js</em> in the user's profile directory holds additional preferences the user has set. This file is never written to by Firefox, but you may wish to set preferences manually in this file to override other settings.</li> - <li><a href="/en/Automatic_Mozilla_Configurator/Locked_config_settings" title="en/Automatic Mozilla Configurator/Locked config settings">Lockfile settings</a>: these preferences are stored in a file that usually has the name <em>mozilla.cfg</em> or <em>netscape.cfg</em>. The file may be located on a network. It is intended to be used by an administrator or ISP to set settings centrally. In addition, certain preferences may be locked such that users cannot change them. Locked preferences are disabled in the Preferences window.</li> -</ul> - -<p>Firefox exposes its most common high-level preferences through the Preferences window and other parts of its UI. In reality there are thousands of other preferences Firefox handles that are not readily available to the user. These are hidden because they are too advanced or obscure for regular users to manage, and because the Preferences window should be as easy to use as possible. To access all other preferences, enter "about:config" into the Location Bar. This XUL page lists all the preferences defined in the Firefox installation, allowing you to change them as you please. As the warning message states, you should be very careful when changing preferences. Incorrect values can make Firefox behave oddly or break altogether.</p> - -<p>You can type on the "Filter" textbox to search for specific preferences. If you type the word "homepage", it will filter all the preferences and display only the ones which include the word "homepage" in its name or value. Right-clicking on the list reveals several options that allow you to modify preference values and add new ones. Preferences with non-default values are highlighted in bold. All changes done in about:config are saved to the <em>prefs.js</em> file.</p> - -<p>The list in about:config is not complete. Some Firefox preferences have no default value, so they are left out unless you add them manually. An extensive specification of Firefox preferences can be seen <a class="external" href="http://kb.mozillazine.org/Category:Preferences">in this page</a>. You don't need to know them by heart; if doing task X requires some preference, then it's better to look for an explanation on how to do X rather than diving into the preferences list and see if you can find the preference you need. MDC articles and other guides are usually good at specifying the preferences you'll need to use.</p> - -<h2 id="Adding_preferences_to_an_extension">Adding preferences to an extension</h2> - -<p>Extensions can read and write Firefox preferences and, most importantly, create and manage their own. The <a href="/en/Code_snippets/Preferences" title="en/Code snippets/Preferences">Preferences System</a> provides a simple, unified storage facility for name / value mappings. When your storage needs are more complicated than this, you'll need more advanced APIs that will be discussed in a section further ahead.</p> - -<p>To add preferences to your extension you should first create a JS preferences file that describes the preferences and their default values, although setting defaults is not required. As mentioned earlier, a preference with no default value can be set later on.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">We recommend that you include all of your extension preferences in the JS defaults file. It makes it easier to compile a list of the preferences your extensions handle, and to document what they do.</div> -</div> -</div> - -<p>The preferences file you need to create should be <em>defaults/preferences/yourextensionname.js</em>, under your extension root. The naming of the JS file is not compulsory, but it is the standard most extensions use.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">The purpose of the <em>defaults</em> directory is to hold non-code files your extension needs. In the past we have used this directory to store XSLT files for XML transformations and local storage template files (more on this later). It's the best place to put miscellaneous files your extension needs.</div> -</div> -</div> - -<p>Download this <a href="/@api/deki/files/5145/=HelloWorld5.zip" title="https://developer.mozilla.org/@api/deki/files/5145/=HelloWorld5.zip">sample Hello World using preferences</a>. There are a couple of additions in the Makefiles, to include the preference file <em>xulschoolhello.js</em>. The contents of the file are fairly simple:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">// Amount of messages shown to the user. -pref("extensions.xulschoolhello.message.count", 0);</pre> -</div> -</div> - -<p>This defines a preference we'll use to keep track of the amount of times we have displayed a greeting message to the user. Its default value is 0. You'll see this preference appear in about:config after installing the extension. Just type "xulschool" in the filter box to see your new preference.</p> - -<div class="note">Always begin your preference names with <em>extensions</em>, followed by some namespacing and finally the actual name of the preference. Name parts are normally separated by dots.</div> - -<p>Now let's look at how we actually manage the preference values.</p> - -<h2 id="Managing_Preferences_with_FUEL">Managing Preferences with FUEL</h2> - -<p><a href="/en/Toolkit_API/FUEL" title="en/FUEL">FUEL</a> is a JS library integrated into Firefox that was meant to facilitate extension development. It fell a little short of its goals, but it is useful for preference handling. Firefox-based applications like Flock include FUEL, and SeaMonkey includes a FUEL equivalent called <a href="/en/Toolkit_API/SMILE" title="en/Toolkit API/SMILE">SMILE</a> since version 2.</p> - -<p>We modified our JSM sample extension so that it uses a preference instead of an internal variable. The main difference in functionality is that after closing Firefox and reopening it, our extension remembers how many greetings have been displayed before. The original extension only kept track of the greetings shown in a browser session. This new version persists this number across sessions.</p> - -<p>Since the only reason we used non-chrome code in the JSM sample extension was to store the message count in a single location, we can easily modify this new extension so that it uses chrome code exclusively. There's no need for JavaScript Code Modules or XPCOM anymore. We're making this point because using the FUEL library from chrome code is slightly different thant using it from non-chrome code. The difference lies in how to get the "root" <a href="/en/Toolkit_API/extIApplication" title="en/FUEL/Application">Application object</a>:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">// chrome code. -Application.something - -// non-chrome code. -let application = - Cc["@mozilla.org/fuel/application;1"].getService(Ci.fuelIApplication); -application.something</pre> -</div> -</div> - -<p>In the chrome you have the global Application object ready to use, while in non-chrome code you need to get it as an XPCOM service. It <em>is</em> an XPCOM service, with the difference that it can be more easily accessed in the chrome.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">FUEL only works in Firefox 3 and above.</div> -</div> -</div> - -<p>The Application object has a <em>prefs</em> property of type <a href="/en/Toolkit_API/extIPreferenceBranch" title="en/FUEL/PreferenceBranch">PreferenceBranch</a>. You can use it to manage preferences easily.</p> - -<p>First, you get an object that represents your preference:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this._countPref = - application.prefs.get("extensions.xulschoolhello.message.count");</pre> -</div> -</div> - -<p>Then you can get or set its value using the <em>value</em> property.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">/** - * Returns the current message count. - * @return the current message count. - */ -get count() { return this._countPref.value; }, - -/** - * Increments the message count by one. - */ -increment : function() { - this._countPref.value++; -}</pre> -</div> -</div> - -<p>The <em>prefs</em> object also has methods that allow you to get and set preference values directly, but we prefer this approach.</p> - -<h4 id="Preference_Listeners">Preference Listeners</h4> - -<p>Sometimes you'll want to be notified when a preference changes its value. For example, if we wanted to have a display of the message count somewhere in the browser, we should use a preference listener to keep it up to date. This way we know we have the right value even if the user changes it manually in about:config.</p> - -<p>To do this in FUEL, add an event listener for the "change" event:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this._countPref.events.addListener("change", this);</pre> -</div> -</div> - -<p>The listener object should implement the <a href="/en/Toolkit_API/extIEventListener" title="en/FUEL/EventListener">EventListener</a> interface. Similarly to observers, all you need to do is have a <em>handleEvent</em> method in a JS object. Or you can use an anonymous function that takes an <a href="/en/Toolkit_API/extIEventItem" title="en/FUEL/EventItem">EventItem</a> object.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this._countPref.events.addListener("change", function(aEvent) { /* do stuff. */ });</pre> -</div> -</div> - -<p>Always remember to remove listeners when you don't need them anymore.</p> - -<h2 id="Managing_Preferences_with_XPCOM">Managing Preferences with XPCOM</h2> - -<p>The preferences system is implemented with XPCOM. FUEL is only a wrapper that gives the XPCOM services a friendlier face, so using either is pretty much the same. Using XPCOM is a little more verbose, as usual.</p> - -<p>We use the <a href="/en/XPCOM_Interface_Reference/nsIPrefBranch" title="en/NsIPrefBranch">Preferences Service</a> in order to get and set preference values:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this._prefService = - Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); -// ... -get count() { - return this._prefService.getIntPref("extensions.xulschoolhello.message.count"); -}, -increment : function() { - let currentCount = - this._prefService.getIntPref("extensions.xulschoolhello.message.count"); - - this._prefService.setIntPref("extensions.xulschoolhello.message.count", currentCount + 1); -}</pre> -</div> -</div> - -<p>One important thing to keep in mind is that the "get" methods of the service can throw an exception if the preference is not found. If you are going to use XPCOM, you should always set a default value to your preferences, or use a try / catch block to prevent unhandled errors.</p> - -<h4 id="Preference_Listeners_2">Preference Listeners</h4> - -<p>The XPCOM way to add a listener was mentioned in the XPCOM section when describing the <em>QueryInterface</em> method:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this._prefService.QueryInterface(Ci.nsIPrefBranch2); -this._prefService.addObserver(prefName, this, false); -this._prefService.QueryInterface(Ci.nsIPrefBranch);</pre> -</div> -</div> - -<p>All the QI'ing is necessary because the <a href="/en/XPCOM_Interface_Reference/nsIPrefBranch2#addObserver()" title="en/NsIPrefBranch2#addObserver()">addObserver</a> method is in a different interface, and other than for adding and removing observers, we use the nsIPrefBranch interface for everything related to preferences.</p> - -<p>Then, create the observer method:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">observe : function(aSubject, aTopic, aData) { - if ("nsPref:changed" == aTopic) { - let newValue = aSubject.getIntPref(aData); - // do something. - } -},</pre> -</div> -</div> - -<p>Always remember to remove the observer when you don't need it anymore:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this._prefService.QueryInterface(Ci.nsIPrefBranch2); -this._prefService.removeObserver(prefName, this);</pre> -</div> -</div> - -<h2 id="Preference_Windows">Preference Windows</h2> - -<p>It's very common for extensions to have a few settings that their users can change to tailor them to their needs. Since there are some subtleties related to preference management, there are some facilities provided in XUL and Firefox that make this much easier to deal with.</p> - -<p>The standard way of opening a preferences window is to open the Add-ons Manager, select the add-on, and then click on the Preferences button. In order to have this button enabled in your extension you need to add the following line to <em>install.rdf</em>:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><em:optionsURL>chrome:<span class="code-comment">//xulschoolhello/content/preferencesWindow.xul</em:optionsURL></span></pre> -</div> -</div> - -<p>If you want to open this window from a different place in the UI, such as a menu item or a button in a toolbar, you need to take into account that the opening behavior of a Preferences window is different depending on the operating system. This is how we do it:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">openPreferences : function() { - if (null == this._preferencesWindow || this._preferencesWindow.closed) { - let instantApply = - Application.prefs.get("browser.preferences.instantApply"); - let features = - "chrome,titlebar,toolbar,centerscreen" + - (instantApply.value ? ",dialog=no" : ",modal"); - - this._preferencesWindow = - window.openDialog( - "<a class="external" rel="freelink">chrome://xulschoolhello/content/preferencesWindow.xul</a>", - "xulschoolhello-preferences-window", features); - } - - this._preferencesWindow.focus(); -},</pre> -</div> -</div> - -<p>This code is based on the code that opens Preference windows from the Add-ons Manager. It does 2 things:</p> - -<ol> - <li>Check if the Preferences window is already open. In that case, just give it focus.</li> - <li>Make the window modal in systems where the instant apply rule is not used. Notice that this is a preference that users can switch, so checking for the operating system is not good enough.</li> -</ol> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">The general philosophy in non-Windows systems is that a change in a preference applies immediately. Preference windows don't have any buttons, or just an OK or Close button. On Windows, changing preferences don't apply until the user click on the OK button. The user can click on the Cancel button and none of the changes performed in the window will apply. This is why it makes sense to have Preference windows be modal on Windows. This way the user is urged to apply or discard any changes instead of being able to ignore the Preferences window.</div> -</div> -</div> - -<p>For preferences windows you should always use the <a href="/en/XUL/prefwindow" title="en/XUL/prefwindow">prefwindow</a> element instead of <a href="/en/XUL/window" title="en/XUL/window">window</a> in your XUL file. Firefox will know if it needs to add OK and Cancel buttons or not.</p> - -<p>In most cases, your preferences window will have a few options that can be displayed all at once. If you have many preferences, you can organize them using the <a href="/en/XUL/prefpane" title="en/XUL/prefpane">prefpane</a> element. This creates a visually appealing tabbed view, just like the one in the Firefox Preferences window. The <em>prefpane</em> is just a container, and you can have as many as you want. The tabs at the top of the window will need icons, and just like with toolbar buttons there are subtle differences between operating systems.</p> - -<p>The <em>prefwindow</em> allows you to use the <a href="/en/XUL/preferences" title="en/XUL/preferences">preferences</a> and <a href="/en/XUL/preference" title="en/XUL/preference">preference</a> elements, which facilitate preference handling. The <em>preferences</em> element is just a container, and you should have one per window, or one per <em>prefpane</em> if you have those. The element and its children are completely invisible, and their purpose is to list the preferences to be used in the window/pane.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><preferences> - <preference id=<span class="code-quote">"xulschoolhello-message-count-pref"</span> - name=<span class="code-quote">"extensions.xulschoolhello.message.count"</span> type=<span class="code-quote">"<span class="code-object">int</span>"</span> /> - <!-- More preference elements. --> - -</preferences></pre> -</div> -</div> - -<p>After you define the preferences you need, you associate them with the form elements in your window or pane using the <a href="/en/XUL/Attribute/preference" title="en/XUL/Attribute/preference">preference attribute</a>:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><textbox preference=<span class="code-quote">"xulschoolhello-message-count-pref"</span> type=<span class="code-quote">"number"</span> - min=<span class="code-quote">"0"</span> max=<span class="code-quote">"100"</span> /></pre> -</div> -</div> - -<p>In this case we use a numeric field to set the message count preference. Changing the value in the control will change the preference (depending on the instant apply rule), and vice versa. You may be able to create a Preferences window without a single line of JS code thanks to the <em>preference</em> element.</p> - -<p>Finally, groupboxes are a good idea to organize the contents of the window and preference panes. They are heavily stylized in the Firefox Preferences window, so you should include the same CSS file that is included in it (<a class="external" rel="freelink">chrome://browser/skin/preferences/preferences.css</a>). This way you don't have to rewrite all the CSS rules defined for Firefox. You should also look at the <em>class</em> values set to elements in the XUL file, so that your Preferences window is just like the one in Firefox and your extension is better integrated into the application and the native OS look and feel.</p> - -<p>{{ PreviousNext("Escuela_XUL/Notificaciones_Observer", "Escuela_XUL/Almacenamiento_local") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/montando_un_ambiente_de_desarrollo/index.html b/files/es/mozilla/tech/xul/escuela_xul/montando_un_ambiente_de_desarrollo/index.html deleted file mode 100644 index e280fda079..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/montando_un_ambiente_de_desarrollo/index.html +++ /dev/null @@ -1,244 +0,0 @@ ---- -title: Montando un ambiente de desarrollo -slug: Mozilla/Tech/XUL/Escuela_XUL/Montando_un_ambiente_de_desarrollo -translation_of: >- - Archive/Add-ons/Overlay_Extensions/XUL_School/Setting_Up_a_Development_Environment ---- -<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}}{{AddonSidebar}}</p> - -<p>{{ PreviousNext("Escuela_XUL/Elementos_esenciales_de_una_extensión", "Escuela_XUL/Agregar_menus_y_submenus") }}</p> - -<h2 id="Getting_the_right_tools">Getting the right tools</h2> - -<p>There are 3 tools that we think are essential for effective add-on development (or any kind of development, really): a source code editor, a source control system, and a build system.</p> - -<p>In regards to code editing, there's no official Mozilla IDE. On the other hand, extensions use the same (or similar) languages that are used for web development, so most text editors and IDEs are up to the task. Most XUL tools and plugins you'll find online are merely templates that generate the folder structure for the project, and that's not much help.</p> - -<p>We recommend <a class="external" href="http://www.activestate.com/komodo_edit/" title="http://www.activestate.com/komodo_edit/">Komodo Edit</a>. It's free, open source, and cross-platform. It's based on the Mozilla XULRunner platform, so it has support for some of the particularities in Firefox extension development. Komodo Edit has automatic completion for XUL tags and attributes, and it supports <a href="/en/Mozilla_CSS_Extensions" title="en/Mozilla CSS Extensions">Mozilla's CSS extensions</a> (CSS values and properties beginning with "-moz"). It has an add-on system similar to the one in Firefox, and there are some Komodo extensions that provide additional help in extension development. That is more than what you can get with most other editors, so we recommend you to give it a try. All of our examples are handled with Komodo Edit, so if you see a <em>.kpf</em> file in an example you downloaded, this is a Komodo project file.</p> - -<p>For source control, we just recommend that you have it. We mostly use <a class="external" href="http://subversion.tigris.org/">Subversion</a>, but any other will do, and it won't be necessary for examples or exercises presented in this tutorial.</p> - -<p>To package XPI files, we use <a class="external" href="http://www.gnu.org/software/make/">make</a>. We chose <em>make</em> because this is the system used by Mozilla to build Firefox, and it is available for all operating systems. <em>make</em> is a default tool in most UNIX-based systems. It can be installed on Mac OS X as part of the XCode Tools package, and on Windows through <a class="external" href="http://www.cygwin.com/">cygwin</a>. In <em>cygwin</em> installations you'll have to explicitly check the <em>make</em> and <em>zip</em> utilities from the long list of packages to download and install.</p> - -<p>Also make sure that <em>make</em> is in the executable system path. After setting up <em>make</em>, you should be able to open a command line window, run "make -ver", and get the installed version of <em>make</em> as output.</p> - -<p>We recommend you set up <em>make</em> in your system, since our examples come with all the necessary files to build and install the resulting XPI using this tool. It will save you a lot of packaging time. Or you can create an equivalent system using batch, Ant or whatever you prefer.</p> - -<h2 id="Build_system">Build system</h2> - -<p>Let's start by downloading the project used to build the second version of Hello World, from the exercise in the last section.</p> - -<p><a href="/@api/deki/files/5142/=HelloWorld2.zip" title="https://developer.mozilla.org/@api/deki/files/5142/=HelloWorld2.zip">Hello World 2 Project</a>.</p> - -<p>Unzip the file anywhere you want. Inside the <em>HelloWorld2</em> directory, you'll see two directories: <em>bin</em> and <em>src</em>. The <em>bin</em> directory should be empty. This is where all the resulting build files will be created, and where you'll find the extension XPI file once you get it to build.</p> - -<p>Open the project file (<em>HelloWorld2.kpf</em>) from the <em>src</em> directory in Komodo Edit. In the Projects tab you should be able to see the directory structure inside the <em>src</em> directory. This structure should be familiar, as it is almost identical to the unpacked XPI from the previous section.</p> - -<p>The only notable additions are <em>Makefile</em> under src and <em>Makefile.in</em> under <em>chrome</em>. These are the files that <em>make</em> uses to build the XPI. You should take some time to read them and understand them, or at least identify the parts that you should change to get a project of your own going. This <a class="external" href="http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_toc.html">GNU Make Manual</a> is a very good reference to get to know <em>make</em> and Makefiles.</p> - -<p>In most cases you'll only need to change the first lines in the file <em>Makefile</em>. These define the extension name (which will also be the name of the JAR file), the extension id (as specified in <em>install.rdf</em>) and the name of the profile directory where the extension will be installed during development and testing. More about this further ahead.</p> - -<p>Let's try and build the XPI from the command line first. Open the command line program in your system and navigate to the <em>src</em> directory in your project. Run the following command:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">make</pre> -</div> -</div> - -<p>That's it. If everything went well, you should see an output similar to this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">Creating chrome JAR file. - adding: content/browserOverlay.js (deflated 42%) - adding: content/browserOverlay.xul (deflated 59%) - adding: skin/browserOverlay.css (stored 0%) - adding: locale/en-US/browserOverlay.dtd (deflated 52%) - adding: locale/en-US/browserOverlay.properties (stored 0%) -Creating chrome JAR file. Done! -Creating XPI file. - adding: install.rdf (deflated 50%) - adding: chrome.manifest (deflated 60%) - adding: chrome/xulschoolhello.jar (deflated 30%) -Creating XPI file. Done! - -Build finished successfully.</pre> -</div> -</div> - -<p>If you inspect the <em>bin</em> directory, you should see the <em>xulschoolhello2.xpi</em> file, and a <em>build</em> directory with copies of the project files. The <em>build</em> directory is just a temporary location where files are copied before the final XPI is built. If you run <em>make</em> again, you'll only see the last line of the build process. That is because <em>make</em> can tell that the files in the <em>build</em> directory are up to date, and nothing needs to be done. Making changes on source files will make <em>make</em> run the necessary steps to build the XPI again.</p> - -<p>You can clean up the <em>bin</em> directory by just running the following command (again, from the <em>src</em> directory):</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">make clean</pre> -</div> -</div> - -<p>You can also run these commands from Komodo. Click on Tools > Run Command.... In the "Run" textbox you should type this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">bash -c <span class="code-quote">"make"</span></pre> -</div> -</div> - -<p>Or add "clean" for the clean command. The "bash -c" part forces Komodo to use <em>bash</em>, which for some reason can't be set properly as the default command shell. It isn't necessary to add this, but it's better so that it is consistent with the <em>make</em> command we'll see next.</p> - -<p>In the "Start in" textbox you should choose <em>%p</em>(directory path of active project). If you don't see this textbox, click on the "More" button. You also have the option to save the command, by clicking on the "Add to Toolbox" checkbox. To see the Toolbox, click on View > Tabs > Toolbox, from the main menu. With that, you should now have a very easy way to build your XPI, by just double clicking on the created commands.</p> - -<p>We can make it even better. Once you're testing and debugging your code, you'll find that constantly building and installing an XPI can be very tedious. This is the reason why we introduced "make install". This only works if your extension is already installed in a Firefox profile. Just like in the provided project, you need the add-on id and profile location set in the file <em>Makefile</em>. We use this information to locate the installation path of the extension and overwrite the installed files. If Firefox is open at the time you run "make install", you'll have to restart it in order to see the changes. It's still better than installing the XPI all over again.</p> - -<p>In order to set the profile location to the right value, you should read the <a class="external" href="http://support.mozilla.com/en-US/kb/Profiles">support article on profiles</a>, at the Mozilla Support site. We'll also delve deeper in this topic later on in this section.</p> - -<p>To make "make install" work on non-Windows systems, you need an extra step. The install process requires using an environment variable called <em>OSTYPE</em>, which is not exported. Long story short, if you want to run it from a command line, you need to run:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">export OSTYPE; make install</pre> -</div> -</div> - -<p>And in the command in Komodo, you should enter the following:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">bash -c <span class="code-quote">"export OSTYPE; make install"</span></pre> -</div> -</div> - -<p>The <em>export</em> command won't work correctly unless you use "bash -c".</p> - -<div class="note">The file <em>Makefile</em> specifies which profile folder the add-on will be reinstalled to. This is set in the <em>profile_dir</em> variable (set to "xulschool-dev" in this case). When creating a development profile for your add-on, make sure you choose an easy name for the profile folder, and set it in your <em>Makefile</em> in order to take advantage of the install command.</div> - -<h3 id="Building_IDL_files">Building IDL files</h3> - -<p>Some extensions require developing XPCOM components to add certain advanced functions. There's a section dedicated to XPCOM in this tutorial, but we'll briefly discuss the impact it has on building the extension. You can skip this section and keep it present as a reference in case you do need to use XPCOM in your project.</p> - -<p>XPCOM interfaces are defined using IDL files. These are text files that define the attributes and methods in one or more interfaces. These IDL files are compiled into binary form and included in the extension as XPT files.</p> - -<p>To compile an IDL file to XPT, you need a command line tool called <em>xpidl</em>. This tool is included in the Mozilla <a href="/en/Gecko_SDK" title="en/Gecko SDK">Gecko SDK</a>. If you need to compile IDLs, go to the SDK page and download a compiled version for your system. Also note any prerequisites you may need. If your system is not listed in the supported builds, you'll have to build the SDK yourself from the Mozilla source. Good luck with that.</p> - -<p>You should also set up your environment so that <em>xpidl.exe</em> (or just <em>xpidl</em> on other systems) is in the default executable path, and also add a variable called GECKO_SDK, that points to your SDK build:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">export GECKO_SDK=/path/to/your/sdk</pre> -</div> -</div> - -<p>Our build system should pick it up from there. To make it work in Komodo in Unix-based systems, we add the command to the <em>.bash_login</em> file in the home directory, and we modify the commands to this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">bash -c <span class="code-quote">". ~/.bash_login; make"</span></pre> -</div> -</div> - -<p>An example project with XPCOM components is included in the XPCOM section. There is also a mention about building C++ XPCOM, which is something much more complicated.</p> - -<h3 id="Signing_extensions">Signing extensions</h3> - -<p>In order to provide additional security for your users, you can choose to <a href="/en/Signing_an_extension" title="en/Signing an extension">add a signature to your extension</a>. The signature verifies that you are the author of this extension, and it can only be done if you have a valid certificate provided by a trusted Certificate Authority.</p> - -<p>The only noticeable difference for the user is that the XPI installation dialog will say that the extension was created by you, making the dialog a little easier to trust. It's not common to sign extensions because most users will trust the official add-ons site (AMO) rather than rely on extension signatures. On the other hand, it is standard practice for big companies to sign their extensions.</p> - -<p>You'll need to download some libraries in order to be able to sign your extension. Follow the <a href="/en/Signing_an_extension" title="en/Signing an extension"><span class="external">instructions</span></a>, and add something like the following to your Makefile:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"># The directory where the signature sources are located. -signature_dir := signature - -# The signing key /certificate file. -signature_extra_files := $(build_dir)/META-INF/manifest.mf \ - $(build_dir)/META-INF/zigbert.sf -# The signing key /certificate file. -signature_rsa_file = $(build_dir)/META-INF/zigbert.rsa# The signing key /certificate file. -signature_files := $(signature_extra_files) \ - $(signature_rsa_file) - -$(signature_files): $(build_dir) $(xpi_built) - @signtool -d $(signature_dir) -k $(cert_name) \ - -p $(cert_password) $(build_dir)</pre> -</div> -</div> - -<p>Keep in mind that your password should not be in your Makefiles, and you must be very careful with the certificate information. Ideally this should be handled by a single person, and only done near the end of the release process. You should also have a different <em>make</em> command, such as <em>make signed</em> in order to distinguish the signed and unsigned development builds.</p> - -<h2 id="Firefox_profile_management">Firefox profile management</h2> - -<p>It is good development practice to keep your test environment separate from everything else. You don't want unstable extensions to break your everyday Firefox profile, risking data loss. It's much better to have a different "version" of Firefox for testing. This is what Firefox profiles are for.</p> - -<p>You can learn about setting up multiple Firefox profiles in the Mozilla Support article <a class="external" href="http://support.mozilla.com/en-US/kb/Managing+profiles">Managing Profiles</a>. You can have as many profiles as you like. You can also mix them with multiple Firefox installations. For instance, you may want to test your extension in Firefox 3.5 and Firefox 3.6, or test it in a localized version of Firefox. You can install as many Firefox versions as you want, and mix profiles and versions.</p> - -<p>On Windows and Linux it's easy to create shortcuts for every profile you create, using the commands mentioned in the support article.</p> - -<p>For Mac OS X developers, there is also a way to set up "shortcuts". You can do this by opening the Automator application, choosing Run Shell Script and then entering the profile-loading script in the textbox:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">/Applications/Firefox.app/Contents/MacOS/firefox-bin -no-remote -p MyProfile > /dev/<span class="code-keyword">null</span> &</pre> -</div> -</div> - -<p>You can change "/dev/null" to a file location, in case you want to see <em>dump</em> output from Firefox, or other extensions. The last <em>&</em> prevents Automator from waiting for your Firefox session to finish. Save this as an Application, not a Workflow. And you probably want to have these on your Desktop or Dock, for easy access.</p> - -<p>There are also some configuration changes you shloud make in your testing profiles, so that you get detailed error information in case something fails. The Firefox <a href="/en/Error_Console" title="en/Error Console">Error Console</a> (Tools > Error Console) normally displays JavaScript errors that occur on web pages, but with some tweaking you can get error information from your extension. Read this piece on <a href="/en/Setting_up_extension_development_environment#Development_preferences" title="en/Setting up extension development environment#Development preferences"><span class="external">Development preferences</span></a>.</p> - -<h2 id="Developer_extensions">Developer extensions</h2> - -<p>There's a wide variety of Firefox extensions that aid web development and add-on development. A good place to look for them is the <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/browse/type:1/cat:4">Mozilla Add-ons site</a>, and there's also a good <a href="/en/Setting_up_extension_development_environment#Development_extensions" title="en/Setting up extension development environment#Development extensions"><span class="external">development extension list</span></a> here. In this section we'll cover a few that we have found to be very useful.</p> - -<h3 id="DOM_Inspector">DOM Inspector</h3> - -<p>The <a href="/en/DOM_Inspector" title="en/DOM Inspector"><span class="external">DOM Inspector</span></a> used to be part of Firefox as an installer option, but since Firefox 3 it has been separated as another add-on you can add and remove. It's a very useful inspection tool that lets you look into the DOM of HTML and XUL documents, as well as applied CSS rules and associated JavaScript objects. <a href="/en/DOM_Inspector/Introduction_to_DOM_Inspector" title="en/Introduction to DOM Inspector">Introduction to DOM Inspector</a> is a good guide on how to get started using it.</p> - -<p>The DOM inspector is particularly useful in finding out how to overlay a window, and how to replace default CSS style rules. You can see the names of the files involved, which gives you a good starting point when looking into the <a class="external" href="http://mxr.mozilla.org/">Mozilla source</a>. You can even change styles, attributes and execute Javascript code in it, although that's not completely reliable.</p> - -<h3 id="JavaScript_Debugger">JavaScript Debugger</h3> - -<p>The name says it all. The <a href="/en/Venkman" title="en/Venkman">Venkman JavaScript Debugger</a> is a great way to trace execution of your JavaScript code.</p> - -<p>To debug extension and browser code, right-click on the Loaded Scripts panel and uncheck Exclude Browser Files. The list of loaded scripts will grow long to include all of the scripts in Firefox. Having our file naming conventions prove very useful in this case. You can set breakpoints, step in and out of methods, and even get profiling information from Javascript execution. You can inspect variables, keep track of watch expressions, and evaluate arbitrary JS at any point in execution.</p> - -<p>This extension has seen little maintenance in quite some time, so it is very buggy. It is specially unreliable when debugging code in Javascript XPCOM and XBL files. Nevertheless, it is a valuable tool when trying to figure out why a certain function is misbehaving.</p> - -<h3 id="Tamper_Data">Tamper Data</h3> - -<p><a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/966" title="https://addons.mozilla.org/en-US/firefox/addon/966">Tamper Data</a> intercepts HTTP requests and their responses. It allows you to cancel them and even replace payload data before it is sent. There are several similar extensions, such as <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/3829">Live HTTP Headers</a>, but Tamper Data is the one that we use the most. We'll cover more on HTTP debugging later on.</p> - -<h3 id="Firebug">Firebug</h3> - -<p>The <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/1843" title="https://addons.mozilla.org/en-US/firefox/addon/1843">Firebug</a> extension includes pretty much all tools mentioned so far, but it's mostly focused on web development. The <a class="external" href="http://getfirebug.com/wiki/index.php/Chromebug_User_Guide" title="http://getfirebug.com/wiki/index.php/Chromebug_User_Guide">Chromebug</a> extension helps in making Firebug more useful for extension development, but it may still not be powerful enough to replace all of the previously mentioned add-ons.</p> - -<p>On the other hand, Firebug has a very friendly, integrated user interface, and sees much more development that its counterparts. It's definitely worth a try.</p> - -<h3 id="Leak_Monitor">Leak Monitor</h3> - -<p>Memory leaks have always been a big criticism drawn against Firefox. Mozilla has proven with time that they take memory usage seriously, improving performance on several critical areas and removing all kinds of memory leaks.</p> - -<p>However, extensions are also capable of causing memory leaks. If you want your extension to be included in the Mozilla Add-ons site, you better not have any memory leaks. <a href="/en/Using_XPCOM_in_JavaScript_without_leaking" title="en/Using XPCOM in JavaScript without leaking"><span class="external">Using XPCOM in JavaScript</span></a> has some guidelines you should follow to avoid them. One of the most common errors developers make is to register a JS event listener or observer, and never removing it. The simple practice of always including removal code for everything you add makes a big difference.</p> - -<p>To make sure your extension doesn't leak, you should use the <a href="/en/Leak_Monitor" title="en/Leak Monitor"><span class="external">Leak Monitor extension</span></a> when testing it. Always test opening and closing windows. Leaks usually surface when doing this.</p> - -<h2 id="Exercise">Exercise</h2> - -<ul> - <li>Set up a new Firefox profile for XUL School. Make sure you can open and close your XUL School Firefox without having to close the instance of Firefox you use to browse normally (you <em>do</em> use Firefox, don't you?). Make any modifications you want to the XUL School project, and use <em>make</em> and <em>make install</em> to see the extension work with your changes.</li> - <li>Install DOM Inspector. Use it to locate the menu you created. Inspect the CSS rules Firefox applies to it by default. Look at the final, computed style for the menu items. Browse around the rest of the Firefox DOM, and try to figure out what the nodes correspond to in the Firefox UI.</li> - <li>Install the JavaScript Debugger. Add a breakpoint to your hello wold function and run it. Inspect the variables available in the scope. Run JavaScript code in the console to the right-hand side.</li> - <li>Install the Tamper Data extension. Open the Tamper Data window and go to a AJAX-heavy page such as Gmail or Facebook (don't click on the Start Tamper button, it's not necessary for this). Try to identify what is going on with some of the requests being sent.</li> -</ul> - -<p>Now that you know how to quickly monitor your project and test changes, we'll learn how to add new UI elements to Firefox, through overlays and new windows.</p> - -<p>{{ PreviousNext("Escuela_XUL/Elementos_esenciales_de_una_extensión", "Escuela_XUL/Agregar_menus_y_submenus") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/notificaciones_de_usuario_y_alertas/index.html b/files/es/mozilla/tech/xul/escuela_xul/notificaciones_de_usuario_y_alertas/index.html deleted file mode 100644 index efce29ae52..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/notificaciones_de_usuario_y_alertas/index.html +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: Notificaciones de usuario y alertas -slug: Mozilla/Tech/XUL/Escuela_XUL/Notificaciones_de_usuario_y_alertas -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/User_Notifications_and_Alerts ---- -<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>{{ PreviousNext("Escuela_XUL/Personalizar_elementos_XUL_con_XBL", "Escuela_XUL/Documentación_de_Mozilla") }}</p> - -<p>It is often the case that extensions need to notify users about important events, often requiring some response. Using modal dialogs and alerts is usually a bad idea. They interrupt the user's workflow, demanding immediate action before anything else can be done. Users will find them annoying and probably will learn to dismiss them as quickly as possible without even reading what they have to say. Or they will just get rid your add-on.</p> - -<p>This section lists a few alternatives that give you the possibility of notifying the user and requesting action without being too annoying.</p> - -<h2 id="The_notificationbox_element">The notificationbox element</h2> - -<p>You have probably seen these before. The "remember password" prompt is the one that shows up the most often. They are thin boxes that appear from beneath the tab list and above the page content, with some text and maybe a few buttons. This kind of notification is implemented with a <a href="/en/XUL/notificationbox" title="en/XUL/notificationbox">notificationbox</a>.</p> - -<p>This kind on notification is very easy to implement, it doesn't interrupt the user and is easy to read and dismiss, so it is our recommended way of displaying alerts and notifications. There's a catch, though: these notifications are <em>inside</em> the current tab, so switching tabs will make a notification disappear. The notification shows up again when you come back to the tab that displayed it. This means that these notifications make the most sense when they are related to the page currently being displayed, such as a page trying to install an add-on, or a site you just entered a password on.</p> - -<p>Notification boxes are very easy to create, and are very customizable:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let nb = gBrowser.getNotificationBox(); -let acceptButton = new Object(); -let declineButton = new Object(); -let message = - this._bundle.getString("xulschoolhello.friendMessage.label"); -let that = this; - -acceptButton.label = - this._bundle.getString("xulschoolhello.acceptButton.label"); -acceptButton.accessKey = - this._bundle.getString("xulschoolhello.acceptButton.accesskey"); -acceptButton.popup = null; -acceptButton.callback = function() { that.acceptRequest(); }; -// similarly for decline button. -nb.appendNotification( - message, "xulschoolhello-friend-notification", - "<a class="external" rel="freelink">chrome://xulschoolhello/skin/friend-notification.png</a>", - nb.PRIORITY_INFO_HIGH, [ acceptButton, declineButton ]);</pre> -</div> -</div> - -<p>All browser tabs have a notification box by default, so you don't need to do any overlaying. The <em>notificationbox</em> elements can be obtained from the <em>gBrowser</em> object. In this case we don't pass any arguments to <a href="/en/XUL/tabbrowser#m-getNotificationBox" title="en/XUL/tabbrowser#m-getNotificationBox">getNotificationBox</a> so that we get the notification box that corresponds to the tab currently on display. The <a href="/en/XUL/notificationbox#m-appendNotification" title="en/XUL/notificationbox#m-appendNotification">appendNotification</a> method takes the message, id, image (32x32), level and buttons. The level argument determines the "strength" of the message, indicated by its background color when it is displayed. You should look for the level that better fits your message, and use the lowest applicable level, to prevent the user from getting used to dismissing high-level notifications. The buttons are represented by simple JS data objects. This is all explained in detail in the <a href="/en/XUL/notificationbox" title="en/XUL/notificationbox">notificationbox</a> page.</p> - -<p>Notification boxes are designed to be easily dismissed. All notifications have an additional close button, so you should take into account that it's possible that none of your custom buttons will be clicked. Also, clicking on any of your custom buttons will cause the notification to be immediately closed, so you should only use notification boxes for single-step processes.</p> - -<h2 id="The_Alerts_Service">The Alerts Service</h2> - -<p>This is a very good option when you want to alert users about events without requiring input from them. Alerts are displayed in an OS-specific way, so their look is native. You can associate an action to the user clicking on the alert. Another advantage is that you use an XPCOM service to do this (<a href="/en/XPCOM_Interface_Reference/nsIAlertsService" title="en/XPCOM Interface Reference/nsIAlertsService">nsIAlertsService</a>), so you can easily trigger alerts from chrome and non-chrome code. On the other hand, alerts are displayed only temporarily</p> - -<p>Using the Alerts Service is similar to using notification boxes:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let alertsService = - Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService); -let title = this._bundle.getString("xulschoolhello.greeting.title"); -let message = this._bundle.getString("xulschoolhello.greeting.label"); - -alertsService.showAlertNotification( - "<a class="external" rel="freelink">chrome://xulschoolhello/skin/hello-notification.png</a>", - title, message, true, "", this, "XULSchool Hello Message");</pre> -</div> -</div> - -<p>We pass <em>this</em> as an argument, assuming that <em>this</em> is an object that implements <a href="/en/XPCOM_Interface_Reference/nsIObserver" title="en/nsIObserver">nsIObserver</a>. We do this when we need to handle clicks on the alert box. The image can have any size, but it is recommended that you use a medium, fixed size.</p> - -<p>The main disadvantage of using alerts is that support for the Alerts Service is not guaranteed for all platforms and Firefox versions. Support for Windows has existed since Firefox 2. For Mac OS X, support was added on Firefox 3, and only through a third-party tool called Growl. On Linux systems, we have confirmed that it works on Firefox 3 on Ubuntu Linux, but we haven't tested all distributions and Firefox versions.</p> - -<p>Because of the inconsistent support and temporary nature of these alerts, we don't recommend using this service to show information the user needs to know and can't get in any other way.</p> - -<h2 id="Custom_alerts">Custom alerts</h2> - -<p>Creating custom solutions for alerting the user is not complicated, given the advantages of XUL overlays and CSS positioning. However, these solutions are prone to be buggy and have accessibility issues. You should use the 2 alternatives mentioned above whenever possible. If none of those fit your needs then this is an acceptable solution.</p> - -<p>An easy way to display alerts is to include a hidden box in your overlay, which you can fill with any content you need before removing the hidden attribute so that it is displayed to the user. The best locations for this kind of box are above and below the tab browser. Below is preferrable because it only cuts the bottom part of the current page, as opposed to pushing down all tabs and content. Notification boxes are a good guideline to what you should aim for: thin, informative and easy to dismiss.</p> - -<p>Another option is to also add a hidden box to the overlay, but use CSS positioning to locate it where you want. This usually means that the box will be hovering on top of the page's content, and there are a few things you must know about this. First of all, switching tabs will probably make your alert disappear. This is probably due to the fact that the browser tab box uses a deck internally, and that affects <a class="external" href="http://www.w3schools.com/Css/pr_pos_z-index.asp">z-indexing</a>. You'll have to code around this using tab events in order to know when to re-display your alert. Another problem you need to take into account is that transparency of floating XUL on the Mac OS version of Firefox 2 doesn't work. You'll end up with a box with a white background you can't get rid of . On Firefox 3 and above, this seems to have been corrected, using the <a href="/en/XUL/panel" title="en/XUL/panel">panel</a> element.</p> - -<p>The bottom right corner of the browser is the recommended location for an alert, because it normally doesn't block the part of the content where the user is reading, or the most important parts of page content, such as menus and titles.</p> - -<p>Remember this is not a recommended practice. Imagine having multiple extensions notifying you in their own custom way, probably even at the same time! This is not good from a UI perspective, so you consider custom alerts the very last resort.</p> - -<p>{{ PreviousNext("Escuela_XUL/Personalizar_elementos_XUL_con_XBL", "Escuela_XUL/Documentación_de_Mozilla") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/objetos_xpcom/index.html b/files/es/mozilla/tech/xul/escuela_xul/objetos_xpcom/index.html deleted file mode 100644 index 497781a405..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/objetos_xpcom/index.html +++ /dev/null @@ -1,378 +0,0 @@ ---- -title: Objetos XPCOM -slug: Mozilla/Tech/XUL/Escuela_XUL/Objetos_XPCOM -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/XPCOM_Objects ---- -<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}}{{AddonSidebar}}</p> - -<p>{{ PreviousNext("Escuela_XUL/Uso_de_objetos_en_JavaScript", "Escuela_XUL/Notificaciones_Observer") }}</p> - -<h2 id="XPCOM">XPCOM</h2> - -<blockquote> -<p><strong>XPCOM</strong> is a cross platform component object model, similar to Microsoft COM.</p> -</blockquote> - -<p>Taken from the <a href="/en/XPCOM" title="en/XPCOM">XPCOM page</a>.</p> - -<p>Firefox can be seen as composed of two layers. The largest of the two is a compiled platform, mostly written in C++. On top of it lies the chrome, mostly written in XML, Javascript and CSS. In fact, you can separate the two. We often mention other "Mozilla based applications". Well, those are applications that, simply put, take the underlying platform with perhaps a few changes and additions, and then write their own chrome layer. This lower layer is called <a href="/en/XULRunner" title="en/XULRunner">XULRunner</a>, and it is a very powerful platform, providing a very robust development base for web-enabled, cross-platform applications. The fact that it allows to easily create OS-independent applications is a big selling point for XULRunner.</p> - -<p>XPCOM is the way in which the two layers (XULRunner and chrome) communicate. Most of the objects and functions in the lower layers are hidden from the chrome; those that need to be publicized are exposed through XPCOM components and interfaces. You can think of XPCOM as a reference to all the capabilities available on the lower layers of Firefox.</p> - -<p>Using XPCOM components is relatively simple, as you've seen in previous examples.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this.obsService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);</pre> -</div> -</div> - -<p>The <em>Cc</em> object (<a href="/en/Components.classes" title="en/Components.classes">Components.classes</a>) is an index to static objects and class definitions available through XPCOM. The string between the brackets is just an identifier, in this case corresponding to the Observer service. You'll usually know what string to use by reading examples and documentation. There is no comprehensive list of these (that we know of), and that's understandable since it would be a very long list, and it can be extended by add-ons. If you want to see the list in your current Firefox installation, just run the following code in the Error Console:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">var str = ""; for (var i in Components.classes) { str += i + "\n" }; str</pre> -</div> -</div> - -<p>A run on Firefox 3.6.2 with a few extensions installed yields 876 strings. That's quite a lot. Luckily, you'll only need to know a handful of those for extension development. The <em>@mozilla.org/</em> prefix is just a way to keep things namespaced. We would use something like <em>@xulschool.com/</em> to make our own components.</p> - -<p>Components are either services (static objects) or instances of classes, just like the objects we handle in JS. The method you call on <em>Cc["some-string"]</em> should either be <em>getService</em> or <em>createInstance</em>, depending on what you're asking for. In most cases it is very clear which one to call, but in case of doubt, look for documentation on it. Those two methods always receive the interface identifier as an argument.</p> - -<p>Similarly to <em>Cc</em>, <em>Ci</em> (<a href="/en/Components.interfaces" title="en/Components.interfaces">Components.interfaces</a>) is an index of available interfaces. A modified version of the last code snippet produces an even longer list of available interfaces. Just like in component identifiers, the <em>nsI</em> prefix is just a way of keeping things in order. The NS stands for Netscape, Mozilla's predecessor. The "I" stands for interface. Our interfaces should begin with something like <em>xsIHello</em>.</p> - -<p>An interface is just a definition of a set of attributes and methods that an object implementing it should have. XPCOM components can implement multiple interfaces, and they often do. Let's look at the Preference service as an example of this. We'll look at its documentation in a very old XUL site called <a class="external" href="http://www.xulplanet.com/">XUL Planet</a>. All of its documentation was planned to be migrated to MDC, but it looks like it was never finished and XUL Planet was discontinued. Their XPCOM documentation is better in terms of seeing the relationships between components and interfaces, so we'll use that.</p> - -<p>Another useful resource is <a class="external" href="http://www.oxymoronical.com/experiments/xpcomref/" title="http://www.oxymoronical.com/experiments/xpcomref/">this XPCOM reference</a>. This is generated from source, and it's kept relatively up to date. It shows the relationships between components and interfaces, but it's more of a source browser than a documentation reference.</p> - -<p>Stepping into the time machine, we see the <a class="external" href="http://web.archive.org/web/20080311100120/http://www.xulplanet.com/references/xpcomref/comps/c_preferencesservice1.html" title="http://web.archive.org/web/20080311100120/http://www.xulplanet.com/references/xpcomref/comps/c_preferencesservice1.html">Preferences Service component page</a>. Right at the top you can see a list of the interfaces it implements, with a link to a documentation page for each one of them. Then you'll see a list of all members of this object, with some documentation about it. It is particularly important to note that, for every member in the component, you'll see in what interface this member is defined. Clicking on the link for the <em>getBranch</em> method takes you to the <a class="external" href="http://web.archive.org/web/20080305031645/www.xulplanet.com/references/xpcomref/ifaces/nsIPrefService.html#method_getBranch" title="http://web.archive.org/web/20080305031645/www.xulplanet.com/references/xpcomref/ifaces/nsIPrefService.html#method_getBranch">nsIPrefService documentation page</a>, where you can see more details on the interface and the method. You can also see a list of what components implement this interface. All of this documentation is generated from the one present in the Firefox source files, so it's in general very complete and well written. It's a shame XUL Planet is no longer with us.</p> - -<p>Interfaces can be awkward to handle. If you want to call a method or use an attribute of interface X in a component, you first need to "cast" the component to interface X. This is done via the <em>QueryInterface</em> method that is included in all XPCOM components.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this._prefService = - Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); - -this._prefValue = this._prefService.getBoolPref("somePreferenceName"); - -this._prefService.QueryInterface(Ci.nsIPrefBranch2); -this._prefService.addObserver("somePreferenceName", this, false); -this._prefService.QueryInterface(Ci.nsIPrefBranch);</pre> -</div> -</div> - -<p>This is a common piece of code you'll see when initializing components or JSM that rely on preferences. We use the Preferences Service to get and set preference values, such as the preference value we're getting on the fourth line of code. These methods are in the <em>nsIPrefBranch</em> interface. The <em>getService</em> and <em>createInstance</em> methods allow you to get the component already set to an interface. In many cases you only need to use one interface, and you won't have to worry about <em>QueryInterface</em>. But in this case we need to change the interface to <em>nsIPrefBranch2</em>, which is the one that includes the method that adds a preference observer. Then we change it back, because after that we only need to get and set preferences, and those methods are in <em>nsIPrefBranch</em>.</p> - -<div class="note">Trying to access methods or attributes without having the right interface set will result in an exception being thrown.</div> - -<h2 id="Passing_parameters">Passing parameters</h2> - -<p>Passing parameters to XPCOM methods is no different from other JS objects, with some exceptions. In general, you can rely on JavaScript's ability to transform values to the correct type, but it's usually best to pass the right type in the first place. This section is a quick guide on how to read XPCOM documentation, which basically amounts to understanding the syntax of <a href="/en/XPIDL" title="en/XPIDL">XPIDL</a>, the language used to specify XPCOM interfaces.</p> - -<p>At MDC, you'll see stuff like this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">void setCharPref(in string aPrefName, in string aValue);</pre> -</div> -</div> - -<p>One of the most important details to notice is that both paratemers have the <em>in</em> keyword. This specifies that these are input parameters, values that the method will use to perform its actions. When is a parameter not an <em>in</em> parameter? In some methods the <em>out</em> keyword is used for parameters that are return values in reality. This is done for certain value types that are not valid as return values in IDL, such as typed arrays.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">void getChildList(in string aStartingAt, out unsigned long aCount,[array, size_is(aCount), retval] out string aChildArray);</pre> -</div> -</div> - -<p>This method returns an array of strings. The first parameter is an input that tells the method where to start looking. The second one will hold the length of the return array, and the third parameter will hold the array itself. Note the metadata included in the square brackets, indicating that the parameter is an array, and that its size is determined by the <em>aCount</em> parameter. Here's one way to invoke this method:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let childArrayObj = new Object(); -let childArray; - -this._prefService.getChildList("", {}, childArrayObj); - -// .value holds the actual array. -childArray = childArrayObj.value;</pre> -</div> -</div> - -<p>The general rule for <em>out</em> parameters is that you can pass an empty object, and then you can get the result by accessing the <em>value</em> attribute in this object after the method call. The method will set <em>value</em> for you. Also, since JS arrays have the <em>length</em> attribute to get their length, there's no need for the second parameter to be used, so we just pass it an empty object that we won't use. The second parameter is only necessary for callers from within C++ code that use pointers instead of high-level arrays.</p> - -<p>Some commonly used XPCOM methods require other XPCOM types as parameters. The <em>addObserver</em> method in <em>nsIPrefBranch2</em> is an example of this.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">void addObserver(in string aDomain, in nsIObserver aObserver, in boolean aHoldWeak);</pre> -</div> -</div> - -<p>Luckily, you don't have to do anything special if you want to register your JS object as a preference observer. The <em>nsIObserver</em> has a single method <em>observe</em>, so all you need to do is have an <em>observe</em> method in your object and you'll be OK.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">XULSchool.PrefObserver = { - init: function() { - - this._prefService = - Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch2); - // pass 'this' as if it implemented nsIObserver. - this._prefService.addObserver( - "extensions.xulschoolhello.somePref", this, false); - }, - - observe : function(aSubject, aTopic, aData) { - // do stuff here. - } -};</pre> -</div> -</div> - -<p>Finally, here's a table summarizing the types you will most likely encounter in XPCOM interfaces, and how to handle them:</p> - -<table style="width: 100%;"> - <tbody> - <tr> - <th class="confluenceTh">JS type</th> - <th class="confluenceTh">IDL types</th> - <th class="confluenceTh">Notes</th> - </tr> - <tr> - <td class="confluenceTd">Strings</td> - <td class="confluenceTd">AUTF8String, string, wstring, char*, others</td> - <td class="confluenceTd">Historically there have been several string types in XPCOM. The currently favored type for most cases is <em>AUTF8String</em>. You can read more about it in the <a href="/En/Mozilla_internal_string_guide" title="En/Mozilla internal string guide">XPCOM String Guide</a>.</td> - </tr> - <tr> - <td class="confluenceTd">Integers</td> - <td class="confluenceTd">short, unsigned short, long, unsigned long, PRInt32, PRUInt32</td> - <td class="confluenceTd"><em>PRInt32</em> is the equivalent to <em>long</em>. Most <em>PR*</em> types have an easier to read equivalent, so it is better to use those.</td> - </tr> - <tr> - <td class="confluenceTd">Floating point</td> - <td class="confluenceTd">float</td> - <td class="confluenceTd"> </td> - </tr> - <tr> - <td class="confluenceTd">Boolean</td> - <td class="confluenceTd">boolean, PRBool</td> - <td class="confluenceTd"> </td> - </tr> - <tr> - <td class="confluenceTd">Void</td> - <td class="confluenceTd">void</td> - <td class="confluenceTd"> </td> - </tr> - <tr> - <td class="confluenceTd">Timestamps</td> - <td class="confluenceTd">PRTime</td> - <td class="confluenceTd">This type is used to pass timestamps measured in milliseconds, such as the output of the <em>getTime()</em> method in a Javascript Date object.</td> - </tr> - </tbody> -</table> - -<p>There are more details about XPIDL in the <a href="/en/XPIDL/Syntax" title="en/XPIDL/Syntax">XPDIL Syntax definition</a>.</p> - -<h2 id="Creating_Your_Own_Components">Creating Your Own Components</h2> - -<h3 id="JavaScript_XPCOM_Components">JavaScript XPCOM Components</h3> - -<p>As we've said before, we recommend using JSM whenever you can. Yet there are some cases where you don't have a choice and you have to create XPCOM components to add a specific feature. In these cases you can choose between compiled XPCOM components, written in C++, or JS XPCOM components. You should favor the latter, they are much less complicated to make and maintain.</p> - -<p>Most of the time you'll need 2 source files for a JS XPCOM component: the IDL interface file, and the implementation JS file. In your final extension XPI you'll need to include the JS implementation file, and the XPT file, which is a compiled version of your IDL file. You won't need the IDL or XPT files if your components only use pre-existing Firefox interfaces. In this case you may also find it easier to implement your component using JSM and the <a href="/en/JavaScript_code_modules/XPCOMUtils.jsm" title="en/JavaScript code modules/XPCOMUtils.jsm">XPCOMUtils module</a>.</p> - -<p>Download this version of the <a href="/@api/deki/files/5144/=HelloWorld4.zip" title="https://developer.mozilla.org/@api/deki/files/5144/=HelloWorld4.zip">Hello World project with XPCOM</a> to see how XPCOM files are structured in the project and built. (Your build will probably break, we'll cover this later on.)</p> - -<p>In the <em>components</em> directory, the file <em>xsIHelloCounter.idl</em> has the following contents:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">#include "nsISupports.idl" - -/** - * Counter for the Hello World extension. Keeps track of how many times the - * hello world message has been shown. - */ -[scriptable, uuid(BD46F689-6C1D-47D0-BC07-BB52B546B8B5)] -interface xsIHelloCounter : nsISupports -{ - /* The maximum allowed count. */ - const short MAX_COUNT = 100; - - /* The current count. */ - readonly attribute short count; - - /** - * Increments the display count and returns the new count. - * @return the incremented count. - */ - short increment(); -};</pre> -</div> -</div> - -<p>The bits about <em>nsISupports</em> are common to most XPCOM interface definitions. <em>nsISupports</em> is the base interface for all interfaces, so it should always be included, except for cases where your interface extends another interface. In those cases you just need to replace <em>nsISupports</em> with the interface you're extending. You can also extend from multiple interfaces, by including a comma-separated list of interfaces instead of only one.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">[scriptable, uuid(BD46F689-6C1D-47D0-BC07-BB52B546B8B5)]</pre> -</div> -</div> - -<p>The <em>scriptable</em> qualifier says that this component can be accessed from JS code. This can also be specified on a per-method basis, which is something you'll see in some of the interfaces in Firefox, but it's not likely you'll have to do it in your own components. The second part defines a UUID for the interface. You must generate a new one for each interface, and you should change it every time the interface changes. In this case you're forced to use UUID, the email address format used for extension ids won't work.</p> - -<p>We included a constant, an attribute and a method to display examples of the 3, but this is clearly an overly elaborate way to keep a simple counter.</p> - -<p>You can define numeric and boolean constants in IDL files, but not string constants. This is a known limitation of XPIDL, and a simple workaround is to define a <em>readonly attribute</em> instead. This means you have to define a getter in the implementation file, though. You can access constants through a reference of the component, or directly from the interface:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">// these are equivalent. -max = Ci.xsIHelloCounter.MAX_COUNT; -max = counterReference.MAX_COUNT;</pre> -</div> -</div> - -<p>The implementation file, <em>xsHelloCounter.js</em>, is much longer. We'll analyze it piece by piece.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; -const Ce = Components.Exception;</pre> -</div> -</div> - -<p>You should be familiar with this already, although there are a couple of additions, <a href="/en/Components.results" title="en/Components.results">Components.results</a> and <a href="/en/Components.Exception" title="en/Components.Exception">Components.Exception</a>. They'll be used further ahead.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">const CLASS_ID = Components.ID("{37ED5D2A-E223-4386-9854-B64FD38932BF}"); -const CLASS_NAME = "Hello World Counter"; -const CONTRACT_ID = "@xulschool.com/counter;1";</pre> -</div> -</div> - -<p>These constants are used at the bottom, in the component registration code. They specify the details of the component, such as a unique UUID (you have to generate it too and it must be different from the IDL UUID), a descriptive name (this isn't used anywhere that we know of), and the contract ID, which is the string you use to get a reference to the component. The <em>";1"</em> at the end of the string is supposed to indicate the version of the component, although it shouldn't change much. It can be useful if there are multiple incompatible versions of the component installed at the same time.</p> - -<p>The implementation object itself should be easy to understand. The only aspects to take into account are that methods and attributes must have the same names as their IDL counterparts, and that the <em>QueryInterface</em> method is implemented:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">QueryInterface : function(aIID) { - if (!aIID.equals(Ci.xsIHelloCounter) && - !aIID.equals(Ci.nsISupports)) { - throw Cr.NS_ERROR_NO_INTERFACE; - } - - return this; -}</pre> -</div> -</div> - -<p>The method is very simple, it validates that the caller is requesting a supported interface, otherwise it throws an exception.</p> - -<p>The rest of the code looks long and complicated, but it is pretty much the same for all components, so you shouldn't worry too much about it. All you have to do to use it in other components is copy it and change some names. The purpose of this code is to register the component so that you can get references to it just like all other Firefox components. It is better read from bottom to top.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">function NSGetModule(aCompMgr, aFileSpec) { - return CounterModule; -}</pre> -</div> -</div> - -<p>This piece of code is the first one that Firefox looks for in all implementation files in the <em>components</em> directory. It simply returns the object that precedes it.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">var CounterModule = { - // registerSelf, unregisterSelf, getClassObject, canUnload -};</pre> -</div> -</div> - -<p>The only thing you may need to change here is when you need to use the <a href="/en/XPCOM_Interface_Reference/nsICategoryManager" title="en/nsICategoryManager">Category Manager</a>. The Category Manager is a service that allows you to register your component under categories that are either pre-existing or you make up. The service also allows you to get all components registered in a category and invoke methods on them. One common use for this service is registering a component as a <a href="/en/XPCOM_Interface_Reference/nsIContentPolicy" title="en/nsIContentPolicy">Content Policy</a>. With it you can detect and filter URL loads. This is covered further ahead in another section of the tutorial.</p> - -<p>The <em>add</em> and <em>delete</em> calls to the Category Manager would have to be done in the <em>registerSelf</em> and <em>unregisterSelf</em> methods:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">registerSelf : function(aCompMgr, aLocation, aLoaderStr, aType) { - - let categoryManager = - Cc[@mozilla.org/categorymanager;1].getService(Ci.nsICategoryManager); - - aCompMgr.QueryInterface(Ci.nsIComponentRegistrar); - aCompMgr.registerFactoryLocation( - CLASS_ID, CLASS_NAME, CONTRACT_ID, aLocation, aLoaderStr, aType); - categoryManager.addCategoryEntry( - "content-policy", "XULSchool Hello World", CONTRACT_ID, true, true); -},</pre> -</div> -</div> - -<p>In this case the component would need to implement <em>nsIContentPolicy</em>.</p> - -<p>And, finally, the factory object.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">var CounterFactory = { - /* Single instance of the component. */ - _singletonObj: null, - - createInstance: function(aOuter, aIID) { - if (aOuter != null) { - throw Cr.NS_ERROR_NO_AGGREGATION; - } - // in this case we need a unique instance of the service. - if (!this._singletonObj) { - this._singletonObj = MessageCounter; - } - - return this._singletonObj.QueryInterface(aIID); - } -};</pre> -</div> -</div> - -<p>If we wanted a class that can be instantiated, instead of a singleton service, the Factory would look like this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">var CounterFactory = { - - createInstance: function(aOuter, aIID) { - if (aOuter != null) { - throw Cr.NS_ERROR_NO_AGGREGATION; - } - - return (new Counter()).QueryInterface(aIID); - } -};</pre> -</div> -</div> - -<p>The instructions on how to build an IDL file are included in the section <a href="/en/XUL_School/Setting_Up_a_Development_Environment" title="en/XUL School/Setting Up a Development Environment">Setting up a Development Environment</a>.</p> - -<h2 id="C_XPCOM_Components">C++ XPCOM Components</h2> - -<p>You do not want to do this unless it's really necessary.</p> - -<p>There are few reasons you might need to use binary XPCOM. One of them is adding functionality to Firefox that it doesn't support natively. In that, you would either need to implement this feature for every platform, or limit your extension compatibility to the ones you'll support. You'll need to build a library file for each one of them: DLL for Windows, dylib for Mac (Intel and PPC) and .so for Linux and similar.</p> - -<p>We won't get into details about this because it's certainly not tutorial material. <a class="external" href="http://nerdlife.net/building-a-c-xpcom-component-in-windows/" title="http://nerdlife.net/building-a-c-xpcom-component-in-windows/">This blog post</a> details the XPCOM build set up. And you'll need to read the <a href="/En/Developer_Guide/Build_Instructions" title="en/Build Documentation">Build Documentation</a> thoroughly to understand how this all works.</p> - -<div class="note">If you need to interact with system libraries without really needing to create one of your own, you should consider using c-types instead. The <a href="/en/js-ctypes" title="en/JavaScript code modules/ctypes.jsm">c-types module</a> is a new bridge between JavaScript and native binaries, introduced in Firefox 3.7. With it, you can interact with existing system libraries without using XPCOM at all.</div> - -<p>{{ PreviousNext("Escuela_XUL/Uso_de_objetos_en_JavaScript", "Escuela_XUL/Notificaciones_Observer") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/personalizar_elementos_xul_con_xbl/index.html b/files/es/mozilla/tech/xul/escuela_xul/personalizar_elementos_xul_con_xbl/index.html deleted file mode 100644 index f01864d483..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/personalizar_elementos_xul_con_xbl/index.html +++ /dev/null @@ -1,544 +0,0 @@ ---- -title: Personalizar elementos XUL con XBL -slug: Mozilla/Tech/XUL/Escuela_XUL/Personalizar_elementos_XUL_con_XBL -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Custom_XUL_Elements_with_XBL ---- -<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}}{{AddonSidebar}}</p> - -<p> </p> - -<p>{{ PreviousNext("Escuela_XUL/Enlazando_contenido_remoto", "Escuela_XUL/Notificaciones_de_usuario_y_alertas") }}</p> - -<blockquote> -<p><strong>XML Binding Language</strong> (<strong>XBL</strong>, sometimes also called Extensible Bindings Language) is a language for describing bindings that can be attached to elements in other documents. The element that the binding is attached to, called the <em>bound element</em>, acquires the new behavior specified by the binding.</p> -</blockquote> - -<p>Taken from the <a href="/en/XBL" title="en/XBL">XBL page</a>.</p> - -<p>This somewhat cryptic explanation describes a very simple concept: with XBL you can create your own custom elements. XBL is heavily used in XUL, but in theory it could be applied to any XML language. XBL was submitted to the <a class="external" href="http://w3.org/">W3C</a> for standardization, but for now it's used in XUL almost exclusively.</p> - -<p>With XBL you can define new elements and define their properties, attributes, methods and event handlers. Many complex elements such as tabs, buttons and input controls are implemented using XBL and simpler XUL elements. As explained earlier, XUL is really just boxes, text and images.</p> - -<p>We'll look into XBL using a modified version of the Hello World extension. Download the <a href="/@api/deki/files/5146/=HelloWorld6.zip" title="https://developer.mozilla.org/@api/deki/files/5146/=HelloWorld6.zip">Hello World XBL project</a>, build it and test it for a while. You should see a new item in the Hello World menu, that opens a Binding Test window where you can add "Persons" to a list.</p> - -<h2 id="XBL_Basics">XBL Basics</h2> - -<p>In order to create an XBL binding you'll need 2 files: the XBL file and a CSS file that binds an element name to your XBL declaration. If you look into the <em>content</em> directory, you'll see both files:</p> - -<ul> - <li><em>person.xml</em> - this is the main binding file. It holds all the code necessary to control the new element we created. We'll look into the code throughout the rest of this section. For now, just notice the opening part of the <em>binding</em> element: <em><binding id="person"></em>.</li> - <li><em>bindings.css</em> - this is the file that associates the element name to the XBL file. It associates the <em>xshelloperson</em> element name to the binding defined in the XBL file. Since you can have more than one binding per file, the "#person" part points to the id of the one we want. This CSS file is located in the content because it's not something we would normally want to be replaced by a skin, and it's not really defining style; it defines content behavior instead.</li> -</ul> - -<div class="note">If you use bindings on toolbar elements, remember to include the CSS file in the customize dialog, using the <em>style</em> directive in the <em>chrome.manifest</em> file.</div> - -<p>With those 2 files properly defined, we can now use the new element. If you look at file <em>bindingDialog.xul</em>, you'll see that the CSS stylesheet is included, which means that the <em>xshelloperson</em> tag can now be used just like any XUL tag. In this case we're adding the "Persons" dynamically, so you'll have to look into the JS file to see how <em>xshelloperson</em> elements are created and added to the DOM just like any other.</p> - -<pre class="brush: js">addPerson : function(aEvent) { - // ... - let person = document.createElement("xshelloperson"); - // ... - person.setAttribute("name", name); - person.setAttribute("greeting", greeting); - // ... - personList.appendChild(person); - // ... -}, -</pre> - -<p>This is where the advantage of XBL is obvious: we only need to create a single node and set some attributes. We didn't need to create a whole XUL structure that would require around 7 nodes <strong>every time</strong> a "Person" is created. XBL provides the encapsulation we needed to manage these nodes as a unit.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">As a bonus, you should look into the usage of <a href="/en/XPCOM_Interface_Reference/nsIFilePicker" title="en/NsIFilePicker">nsIFilePicker</a> to open a "Open File" dialog in a way that looks native for all systems.</div> -</div> -</div> - -<p>Now let's look into the XBL file, <em>p</em><em>erson.xml.</em></p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><bindings xmlns="http://www.mozilla.org/xbl" - xmlns:xbl="http://www.mozilla.org/xbl" - xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"></pre> -</div> -</div> - -<p>The <a href="/en/XUL/bindings" title="en/XUL/bindings">bindings</a> element is the root of the document, and it's a container for <a href="/en/XUL/binding" title="en/XUL/binding">binding</a> elements. Notice how the default namespace for the document is XBL, and the XUL namespace is defined as "xul". You'll need to keep this in mind when defining the content of the binding, because weird things can happen if you don't add "xul:" to your content nodes.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><binding id="person"></pre> -</div> -</div> - -<p>In general, you should only have one binding per file. Bindings tend to require many lines of code, and having more than one ends up making gigantic, unbrowsable files. On the other hand, if your bindings are small and have a strong relationship with each other, it makes sense to keep them together. As for the CSS file, it's usually good to have a single file declaring all bindings in your extension.</p> - -<h2 id="Content">Content</h2> - -<p>Under the <a href="/en/XBL/XBL_1.0_Reference/Elements#content" title="en/XBL/XBL 1.0 Reference/Elements#content">content</a> tag you define the XUL content that will be displayed for your element.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><content> - <xul:hbox> - <xul:image class="xulshoolhello-person-image" xbl:inherits="src=image" /> - <xul:vbox flex="1"> - <xul:label xbl:inherits="value=name" /> - <xul:description xbl:inherits="value=greeting" /> - </xul:vbox> - <xul:vbox> - <xul:button label="&xulshoolhello.remove.label;" - accesskey="&xulshoolhello.remove.accesskey;" - oncommand="document.getBindingParent(this).remove(event);" /> - </xul:vbox> - </xul:hbox> -</content></pre> -</div> -</div> - -<p>Our element is very simple, displaying an image, a couple of text lines and a button. Here are a couple of important things to notice:</p> - -<ul> - <li>The "xul:" namespace must be used for all XUL tags you have in your content.</li> - <li>The <em>xbl:inherits</em> attribute lets your inner XUL use the attributes that are set on the node. So, if you have this: <em><xshelloperson name="Pete" greeting="Good morning" image="" /></em>, then those attribute values are "inherited" to the content nodes that have this special attribute. The <em>value</em> attribute of the <em>xul:label</em> element would be "Pete".</li> - <li>The <em>oncommand</em> attribute of the button has some code you've probably never seen before: <em>document.getBindingParent(this)</em>. This code gets the DOM object that corresponds to the <em>xshelloperson</em> tag, allowing you access to its methods and properties. In this case we're calling the <em>remove</em> method, which we will discuss later on.</li> -</ul> - -<p>If you need to create a container element, or any other element that has child nodes, you can use the XBL <a href="/en/XBL/XBL_1.0_Reference/Elements#children" title="en/XBL/XBL 1.0 Reference/Elements#children">children</a> tag in your content to indicate the place where the child nodes will be inserted. The <em>includes</em> attribute gives you a little more flexibility with children, but it's rarely needed.</p> - -<p>One important thing to take into account is that you shouldn't use the <em>id</em> attribute in any <em>content</em> nodes. These nodes are part of the XUL DOM just like any other, and having an <em>id</em> attribute is bound to cause problems, given that you could have more than instance of your element in the same document and then multiple inner items with the same <em>id</em>. In order to work around this problem, the <em>anonid</em> attribute is used instead:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre> <xul:label anonid="xulshoolhello-name-label" xbl:inherits="value=name" /></pre> -</div> -</div> - -<p>And then, in order to get a reference to the node from the JS code in your binding, we use the <a href="/en/XBL/XBL_1.0_Reference/DOM_Interfaces#getAnonymousElementByAttribute" title="en/XBL/XBL 1.0 Reference/DOM Interfaces#getAnonymousElementByAttribute">getAnonymousElementByAttribute</a> DOM method:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let nameLabel = - document.getAnonymousElementByAttribute( - this, "anonid", "xulshoolhello-name-label");</pre> -</div> -</div> - -<h2 id="Implementation">Implementation</h2> - -<p>The <a href="/en/XBL/XBL_1.0_Reference/Binding_Implementations" title="en/XBL/XBL 1.0 Reference/Binding Implementations">implementation</a> section defines most of the scripting side of your element. Here you can define methods and properties, as well as a <a href="/en/XBL/XBL_1.0_Reference/Elements#constructor" title="en/XBL/XBL 1.0 Reference/Elements#constructor">constructor</a> and a <a href="/en/XBL/XBL_1.0_Reference/Elements#destructor" title="en/XBL/XBL 1.0 Reference/Elements#destructor">destructor</a> for your element. JavaScript code is enclosed in <em>CDATA</em> sections to prevent JS and XML syntax conflicts.</p> - -<h3 id="Properties_and_Fields">Properties and Fields</h3> - -<p>The <a href="/en/XBL/XBL_1.0_Reference/Elements#field" title="en/XBL/XBL 1.0 Reference/Elements#field">field</a> and <a href="/en/XBL/XBL_1.0_Reference/Elements#property" title="en/XBL/XBL 1.0 Reference/Elements#property">property</a> tags allow you to handle element variables and access them from outside of the element.</p> - -<p>A <em>field</em> holds a value that can be changed, except when the <em>readonly</em> attribute is set. It's very similar to a JS object variable, and we generally use a <em>field</em> for private variables inside of the element.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><field name="fieldName">defaultValue</field></pre> -</div> -</div> - -<p>From inside your binding methods, you can access fields with:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this.fieldName</pre> -</div> -</div> - -<p>You can also access them from outside of the element, if you have a reference to it:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">elementRef.fieldName</pre> -</div> -</div> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">Just like with JS objects, all fields are publicly accessible, and we use a "_" to indicate a field is "private". </div> -</div> -</div> - -<p>A <em>property</em> is a little more robust. It is defined using a getter and setter method, allowing read-only and write-only properties, as well as more complex behavior. There are two properties defined in our binding, which are just meant for easier access to the two text attributes in the element. We use the shorthand version of the <em>property</em> tag:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><property name="name" onget="return this.getAttribute('name');" - onset="this.setAttribute('name', val);" /></pre> -</div> -</div> - -<p>There's a less compact version of the property tag that should be used if the getter or setter code involves more than one line of code:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><property name="name"> - <getter><![CDATA[ - return this.getAttribute('name'); - ]]></getter> - <setter><![CDATA[ - this.setAttribute('name', val); - ]]></setter> -</property></pre> -</div> -</div> - -<p>Properties can be accessed just the same as fields, and they're the ones we prefer for public members.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">When you add a node to a XUL document using an XBL binding, all normal DOM operations can be performed on it. You can move it around, delete it or clone it. But there is one thing you need to know about moving or cloning your node: <strong>all internal state in the node will be lost</strong>. This means that all your properties and fields will be reset. If you want some value to be preserved after such DOM operations, you must set it as an attribute and not an internal value.</div> -</div> -</div> - -<h3 id="Methods">Methods</h3> - -<p>Our "Person" binding has a single method that removes the item from the list:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><method name="remove"> - <parameter name="aEvent" /> - <body><![CDATA[ - this.parentNode.removeChild(this); - ]]></body> -</method></pre> -</div> -</div> - -<p>As you can see, it's very easy to define a method and the parameters it takes. You can also have a return value using the <em>return</em> keyword, just like on regular JS code. The method uses the parent node to remove the Person node. Simple enough.</p> - -<p>You can do almost anything from XBL code, including using XPCOM components, JS Code Modules and available chrome scripts. The main setback is that you can't have <em>script</em> tags defined in a binding, so you depend on the scripts that have been included in the XUL files that use the binding. Also unlike scripts, you can include stylesheets using the <a href="/en/XBL/XBL_1.0_Reference/Elements#stylesheet" title="en/XBL/XBL 1.0 Reference/Elements#stylesheet">stylesheet</a> XBL element. DTD and properties files can be handled just like in regular XUL.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">There are two conflicting patterns that you should always keep in mind: encapsulation and separation of presentation and logic. Encapsulation mandates that you try to keep your XBL free of outside dependencies. That is, you shouldn't assume that script X will be included somewhere, because not including it will cause the binding to fail. This suggests that you should keep everything inside your binding. On the other hand, a binding is really just a presentation module. Most XUL elements have basic presentation logic, and any other functionality is processed elsewhere. Plus, XBL files are significantly harder to manage than regular JS files. We prefer to err on the side of simplicity and keep the XBL as simple as possible. If that means having outside dependencies, so be it. But you can still keep some separation and versatility by using custom events to communicate to the outside world. This way you reduce your dependency on specific scripts, and your tag behaves more like the rest.</div> -</div> -</div> - -<p>Just like fields and properties, methods are easy to invoke if you have a reference to the object that corresponds to the node.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">We have experienced problems when calling methods and setting properties on XBL nodes right after they are created and inserted to the document. This is likely due to some asynchronous operation related to node insertion. If you need to perform an operation to a node right after insertion, we recommend using a timeout to delay the operation (a timeout set to 0 works well).</div> -</div> -</div> - -<h2 id="Handlers">Handlers</h2> - -<p>The <a href="/en/XBL/XBL_1.0_Reference/Elements#handlers" title="en/XBL/XBL 1.0 Reference/Elements#handlers">handlers</a> and <a href="/en/XBL/XBL_1.0_Reference/Elements#handler" title="en/XBL/XBL 1.0 Reference/Elements#handler">handler</a> XBL elements are used to define event handlers for the element. We have a "click" handler that displays the greeting when the "Person" element is clicked:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><handler phase="bubbling" event="click"><![CDATA[ - window.alert(this.greeting); -]]></handler></pre> -</div> -</div> - -<p>Handlers are not necessary all that often, since in most cases you'll need the events to only apply to a part of the binding, not the whole thing. In those cases you just add regular event attributes to the nodes inside the <em>content</em> tag.</p> - -<h2 id="Inheritance">Inheritance</h2> - -<p>Inheritance is one of the most powerful features of XBL. It allows you to create bindings that extend existing bindings, allowing lots of code reuse and subtle behavior modifications. All you need is to use the <em>extends</em> attribute of the binding element:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><binding id="manager" - extends="chrome://xulschoolhello/content/person.xml#person"></pre> -</div> -</div> - -<p>This gives you an exact copy of the "Person" binding that you can override as you please.</p> - -<p>You could, for instance, just add a <em>content</em> tag with significantly different XUL content, and leave the <em>implementation</em> alone. You do need to be careful about keeping all <em>anonid</em> attributes consistent, and even some DOM structure if the code does node traversal. Sadly, you can't override only some part of the content. If you want to override it, you have to override all of it.</p> - -<p>A more common inheritance use case is when you want to change the behavior of some methods and properties. You can leave the content alone by not including the <em>content</em> tag, and then just add the methods and properties you wish to override. All you need to do is match the names of the originals. All methods and properties that are not overriden will maintain their original behavior.</p> - -<p>With inheritance you could take the <a href="/en/XUL/richlistbox" title="en/XUL/richlistbox">richlistbox</a> element and modify it to make a rich item tree, or create a switch button that changes state everytime it's clicked. And all with very little additional code. Keep it in mind when creating your custom elements because it can save you lots of time.</p> - -<h2 id="Replacing_Existing_XUL_Elements">Replacing Existing XUL Elements</h2> - -<p>As seen in the beginning of this section, the actual binding process is determined by a simple CSS rule that associates the tag name with the binding. This means that you can change the binding for pretty much any element in Firefox by just adding a CSS rule! This is very powerful: it allows you to change almost any aspect of the interface of any XUL window. In conjuntion with inheritance, it's even easy to do. You can enrich the UI of a Firefox window by extending and replacing elements, which is what the <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/1815">Console²</a> extension does in order to improve the Error Console window.</p> - -<p>Replacing elements should always be a last resort solution, specially if it is done on the main browser window. It's very easy to break the UI of the application or other extensions if you do this the wrong way, so be very careful about it. If you only need to change some specific instances of an element, use very specific CSS rules.</p> - -<p>You can use the <a href="/en/CSS/-moz-binding" title="en/CSS/-moz-binding">-moz-binding</a> property with any CSS selector.</p> - -<p>{{ PreviousNext("Escuela_XUL/Enlazando_contenido_remoto", "Escuela_XUL/Notificaciones_de_usuario_y_alertas") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> - -<p>{{ PreviousNext("Escuela_XUL/Enlazando_contenido_remoto", "Escuela_XUL/Notificaciones_de_usuario_y_alertas") }}</p> - -<blockquote> -<p><strong>XML Binding Language</strong> (<strong>XBL</strong>, sometimes also called Extensible Bindings Language) is a language for describing bindings that can be attached to elements in other documents. The element that the binding is attached to, called the <em>bound element</em>, acquires the new behavior specified by the binding.</p> -</blockquote> - -<p>Taken from the <a href="/en/XBL" title="en/XBL">XBL page</a>.</p> - -<p>This somewhat cryptic explanation describes a very simple concept: with XBL you can create your own custom elements. XBL is heavily used in XUL, but in theory it could be applied to any XML language. XBL was submitted to the <a class="external" href="http://w3.org/">W3C</a> for standardization, but for now it's used in XUL almost exclusively.</p> - -<p>With XBL you can define new elements and define their properties, attributes, methods and event handlers. Many complex elements such as tabs, buttons and input controls are implemented using XBL and simpler XUL elements. As explained earlier, XUL is really just boxes, text and images.</p> - -<p>We'll look into XBL using a modified version of the Hello World extension. Download the <a href="/@api/deki/files/5146/=HelloWorld6.zip" title="https://developer.mozilla.org/@api/deki/files/5146/=HelloWorld6.zip">Hello World XBL project</a>, build it and test it for a while. You should see a new item in the Hello World menu, that opens a Binding Test window where you can add "Persons" to a list.</p> - -<h2 id="XBL_Basics_2">XBL Basics</h2> - -<p>In order to create an XBL binding you'll need 2 files: the XBL file and a CSS file that binds an element name to your XBL declaration. If you look into the <em>content</em> directory, you'll see both files:</p> - -<ul> - <li><em>person.xml</em> - this is the main binding file. It holds all the code necessary to control the new element we created. We'll look into the code throughout the rest of this section. For now, just notice the opening part of the <em>binding</em> element: <em><binding id="person"></em>.</li> - <li><em>bindings.css</em> - this is the file that associates the element name to the XBL file. It associates the <em>xshelloperson</em> element name to the binding defined in the XBL file. Since you can have more than one binding per file, the "#person" part points to the id of the one we want. This CSS file is located in the content because it's not something we would normally want to be replaced by a skin, and it's not really defining style; it defines content behavior instead.</li> -</ul> - -<div class="note">If you use bindings on toolbar elements, remember to include the CSS file in the customize dialog, using the <em>style</em> directive in the <em>chrome.manifest</em> file.</div> - -<p>With those 2 files properly defined, we can now use the new element. If you look at file <em>bindingDialog.xul</em>, you'll see that the CSS stylesheet is included, which means that the <em>xshelloperson</em> tag can now be used just like any XUL tag. In this case we're adding the "Persons" dynamically, so you'll have to look into the JS file to see how <em>xshelloperson</em> elements are created and added to the DOM just like any other.</p> - -<pre class="brush: js">addPerson : function(aEvent) { - // ... - let person = document.createElement("xshelloperson"); - // ... - person.setAttribute("name", name); - person.setAttribute("greeting", greeting); - // ... - personList.appendChild(person); - // ... -}, -</pre> - -<p>This is where the advantage of XBL is obvious: we only need to create a single node and set some attributes. We didn't need to create a whole XUL structure that would require around 7 nodes <strong>every time</strong> a "Person" is created. XBL provides the encapsulation we needed to manage these nodes as a unit.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">As a bonus, you should look into the usage of <a href="/en/XPCOM_Interface_Reference/nsIFilePicker" title="en/NsIFilePicker">nsIFilePicker</a> to open a "Open File" dialog in a way that looks native for all systems.</div> -</div> -</div> - -<p>Now let's look into the XBL file, <em>p</em><em>erson.xml.</em></p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><bindings xmlns="http://www.mozilla.org/xbl" - xmlns:xbl="http://www.mozilla.org/xbl" - xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"></pre> -</div> -</div> - -<p>The <a href="/en/XUL/bindings" title="en/XUL/bindings">bindings</a> element is the root of the document, and it's a container for <a href="/en/XUL/binding" title="en/XUL/binding">binding</a> elements. Notice how the default namespace for the document is XBL, and the XUL namespace is defined as "xul". You'll need to keep this in mind when defining the content of the binding, because weird things can happen if you don't add "xul:" to your content nodes.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><binding id="person"></pre> -</div> -</div> - -<p>In general, you should only have one binding per file. Bindings tend to require many lines of code, and having more than one ends up making gigantic, unbrowsable files. On the other hand, if your bindings are small and have a strong relationship with each other, it makes sense to keep them together. As for the CSS file, it's usually good to have a single file declaring all bindings in your extension.</p> - -<h2 id="Content_2">Content</h2> - -<p>Under the <a href="/en/XBL/XBL_1.0_Reference/Elements#content" title="en/XBL/XBL 1.0 Reference/Elements#content">content</a> tag you define the XUL content that will be displayed for your element.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><content> - <xul:hbox> - <xul:image class="xulshoolhello-person-image" xbl:inherits="src=image" /> - <xul:vbox flex="1"> - <xul:label xbl:inherits="value=name" /> - <xul:description xbl:inherits="value=greeting" /> - </xul:vbox> - <xul:vbox> - <xul:button label="&xulshoolhello.remove.label;" - accesskey="&xulshoolhello.remove.accesskey;" - oncommand="document.getBindingParent(this).remove(event);" /> - </xul:vbox> - </xul:hbox> -</content></pre> -</div> -</div> - -<p>Our element is very simple, displaying an image, a couple of text lines and a button. Here are a couple of important things to notice:</p> - -<ul> - <li>The "xul:" namespace must be used for all XUL tags you have in your content.</li> - <li>The <em>xbl:inherits</em> attribute lets your inner XUL use the attributes that are set on the node. So, if you have this: <em><xshelloperson name="Pete" greeting="Good morning" image="" /></em>, then those attribute values are "inherited" to the content nodes that have this special attribute. The <em>value</em> attribute of the <em>xul:label</em> element would be "Pete".</li> - <li>The <em>oncommand</em> attribute of the button has some code you've probably never seen before: <em>document.getBindingParent(this)</em>. This code gets the DOM object that corresponds to the <em>xshelloperson</em> tag, allowing you access to its methods and properties. In this case we're calling the <em>remove</em> method, which we will discuss later on.</li> -</ul> - -<p>If you need to create a container element, or any other element that has child nodes, you can use the XBL <a href="/en/XBL/XBL_1.0_Reference/Elements#children" title="en/XBL/XBL 1.0 Reference/Elements#children">children</a> tag in your content to indicate the place where the child nodes will be inserted. The <em>includes</em> attribute gives you a little more flexibility with children, but it's rarely needed.</p> - -<p>One important thing to take into account is that you shouldn't use the <em>id</em> attribute in any <em>content</em> nodes. These nodes are part of the XUL DOM just like any other, and having an <em>id</em> attribute is bound to cause problems, given that you could have more than instance of your element in the same document and then multiple inner items with the same <em>id</em>. In order to work around this problem, the <em>anonid</em> attribute is used instead:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre> <xul:label anonid="xulshoolhello-name-label" xbl:inherits="value=name" /></pre> -</div> -</div> - -<p>And then, in order to get a reference to the node from the JS code in your binding, we use the <a href="/en/XBL/XBL_1.0_Reference/DOM_Interfaces#getAnonymousElementByAttribute" title="en/XBL/XBL 1.0 Reference/DOM Interfaces#getAnonymousElementByAttribute">getAnonymousElementByAttribute</a> DOM method:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let nameLabel = - document.getAnonymousElementByAttribute( - this, "anonid", "xulshoolhello-name-label");</pre> -</div> -</div> - -<h2 id="Implementation_2">Implementation</h2> - -<p>The <a href="/en/XBL/XBL_1.0_Reference/Binding_Implementations" title="en/XBL/XBL 1.0 Reference/Binding Implementations">implementation</a> section defines most of the scripting side of your element. Here you can define methods and properties, as well as a <a href="/en/XBL/XBL_1.0_Reference/Elements#constructor" title="en/XBL/XBL 1.0 Reference/Elements#constructor">constructor</a> and a <a href="/en/XBL/XBL_1.0_Reference/Elements#destructor" title="en/XBL/XBL 1.0 Reference/Elements#destructor">destructor</a> for your element. JavaScript code is enclosed in <em>CDATA</em> sections to prevent JS and XML syntax conflicts.</p> - -<h3 id="Properties_and_Fields_2">Properties and Fields</h3> - -<p>The <a href="/en/XBL/XBL_1.0_Reference/Elements#field" title="en/XBL/XBL 1.0 Reference/Elements#field">field</a> and <a href="/en/XBL/XBL_1.0_Reference/Elements#property" title="en/XBL/XBL 1.0 Reference/Elements#property">property</a> tags allow you to handle element variables and access them from outside of the element.</p> - -<p>A <em>field</em> holds a value that can be changed, except when the <em>readonly</em> attribute is set. It's very similar to a JS object variable, and we generally use a <em>field</em> for private variables inside of the element.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><field name="fieldName">defaultValue</field></pre> -</div> -</div> - -<p>From inside your binding methods, you can access fields with:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this.fieldName</pre> -</div> -</div> - -<p>You can also access them from outside of the element, if you have a reference to it:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">elementRef.fieldName</pre> -</div> -</div> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">Just like with JS objects, all fields are publicly accessible, and we use a "_" to indicate a field is "private". </div> -</div> -</div> - -<p>A <em>property</em> is a little more robust. It is defined using a getter and setter method, allowing read-only and write-only properties, as well as more complex behavior. There are two properties defined in our binding, which are just meant for easier access to the two text attributes in the element. We use the shorthand version of the <em>property</em> tag:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><property name="name" onget="return this.getAttribute('name');" - onset="this.setAttribute('name', val);" /></pre> -</div> -</div> - -<p>There's a less compact version of the property tag that should be used if the getter or setter code involves more than one line of code:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><property name="name"> - <getter><![CDATA[ - return this.getAttribute('name'); - ]]></getter> - <setter><![CDATA[ - this.setAttribute('name', val); - ]]></setter> -</property></pre> -</div> -</div> - -<p>Properties can be accessed just the same as fields, and they're the ones we prefer for public members.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">When you add a node to a XUL document using an XBL binding, all normal DOM operations can be performed on it. You can move it around, delete it or clone it. But there is one thing you need to know about moving or cloning your node: <strong>all internal state in the node will be lost</strong>. This means that all your properties and fields will be reset. If you want some value to be preserved after such DOM operations, you must set it as an attribute and not an internal value.</div> -</div> -</div> - -<h3 id="Methods_2">Methods</h3> - -<p>Our "Person" binding has a single method that removes the item from the list:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><method name="remove"> - <parameter name="aEvent" /> - <body><![CDATA[ - this.parentNode.removeChild(this); - ]]></body> -</method></pre> -</div> -</div> - -<p>As you can see, it's very easy to define a method and the parameters it takes. You can also have a return value using the <em>return</em> keyword, just like on regular JS code. The method uses the parent node to remove the Person node. Simple enough.</p> - -<p>You can do almost anything from XBL code, including using XPCOM components, JS Code Modules and available chrome scripts. The main setback is that you can't have <em>script</em> tags defined in a binding, so you depend on the scripts that have been included in the XUL files that use the binding. Also unlike scripts, you can include stylesheets using the <a href="/en/XBL/XBL_1.0_Reference/Elements#stylesheet" title="en/XBL/XBL 1.0 Reference/Elements#stylesheet">stylesheet</a> XBL element. DTD and properties files can be handled just like in regular XUL.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">There are two conflicting patterns that you should always keep in mind: encapsulation and separation of presentation and logic. Encapsulation mandates that you try to keep your XBL free of outside dependencies. That is, you shouldn't assume that script X will be included somewhere, because not including it will cause the binding to fail. This suggests that you should keep everything inside your binding. On the other hand, a binding is really just a presentation module. Most XUL elements have basic presentation logic, and any other functionality is processed elsewhere. Plus, XBL files are significantly harder to manage than regular JS files. We prefer to err on the side of simplicity and keep the XBL as simple as possible. If that means having outside dependencies, so be it. But you can still keep some separation and versatility by using custom events to communicate to the outside world. This way you reduce your dependency on specific scripts, and your tag behaves more like the rest.</div> -</div> -</div> - -<p>Just like fields and properties, methods are easy to invoke if you have a reference to the object that corresponds to the node.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">We have experienced problems when calling methods and setting properties on XBL nodes right after they are created and inserted to the document. This is likely due to some asynchronous operation related to node insertion. If you need to perform an operation to a node right after insertion, we recommend using a timeout to delay the operation (a timeout set to 0 works well).</div> -</div> -</div> - -<h2 id="Handlers_2">Handlers</h2> - -<p>The <a href="/en/XBL/XBL_1.0_Reference/Elements#handlers" title="en/XBL/XBL 1.0 Reference/Elements#handlers">handlers</a> and <a href="/en/XBL/XBL_1.0_Reference/Elements#handler" title="en/XBL/XBL 1.0 Reference/Elements#handler">handler</a> XBL elements are used to define event handlers for the element. We have a "click" handler that displays the greeting when the "Person" element is clicked:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><handler phase="bubbling" event="click"><![CDATA[ - window.alert(this.greeting); -]]></handler></pre> -</div> -</div> - -<p>Handlers are not necessary all that often, since in most cases you'll need the events to only apply to a part of the binding, not the whole thing. In those cases you just add regular event attributes to the nodes inside the <em>content</em> tag.</p> - -<h2 id="Inheritance_2">Inheritance</h2> - -<p>Inheritance is one of the most powerful features of XBL. It allows you to create bindings that extend existing bindings, allowing lots of code reuse and subtle behavior modifications. All you need is to use the <em>extends</em> attribute of the binding element:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre><binding id="manager" - extends="chrome://xulschoolhello/content/person.xml#person"></pre> -</div> -</div> - -<p>This gives you an exact copy of the "Person" binding that you can override as you please.</p> - -<p>You could, for instance, just add a <em>content</em> tag with significantly different XUL content, and leave the <em>implementation</em> alone. You do need to be careful about keeping all <em>anonid</em> attributes consistent, and even some DOM structure if the code does node traversal. Sadly, you can't override only some part of the content. If you want to override it, you have to override all of it.</p> - -<p>A more common inheritance use case is when you want to change the behavior of some methods and properties. You can leave the content alone by not including the <em>content</em> tag, and then just add the methods and properties you wish to override. All you need to do is match the names of the originals. All methods and properties that are not overriden will maintain their original behavior.</p> - -<p>With inheritance you could take the <a href="/en/XUL/richlistbox" title="en/XUL/richlistbox">richlistbox</a> element and modify it to make a rich item tree, or create a switch button that changes state everytime it's clicked. And all with very little additional code. Keep it in mind when creating your custom elements because it can save you lots of time.</p> - -<h2 id="Replacing_Existing_XUL_Elements_2">Replacing Existing XUL Elements</h2> - -<p>As seen in the beginning of this section, the actual binding process is determined by a simple CSS rule that associates the tag name with the binding. This means that you can change the binding for pretty much any element in Firefox by just adding a CSS rule! This is very powerful: it allows you to change almost any aspect of the interface of any XUL window. In conjuntion with inheritance, it's even easy to do. You can enrich the UI of a Firefox window by extending and replacing elements, which is what the <a class="link-https" href="https://addons.mozilla.org/en-US/firefox/addon/1815">Console²</a> extension does in order to improve the Error Console window.</p> - -<p>Replacing elements should always be a last resort solution, specially if it is done on the main browser window. It's very easy to break the UI of the application or other extensions if you do this the wrong way, so be very careful about it. If you only need to change some specific instances of an element, use very specific CSS rules.</p> - -<p>You can use the <a href="/en/CSS/-moz-binding" title="en/CSS/-moz-binding">-moz-binding</a> property with any CSS selector.</p> - -<p>{{ PreviousNext("Escuela_XUL/Enlazando_contenido_remoto", "Escuela_XUL/Notificaciones_de_usuario_y_alertas") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/sitios_útiles_de_la_comunidad_mozilla/index.html b/files/es/mozilla/tech/xul/escuela_xul/sitios_útiles_de_la_comunidad_mozilla/index.html deleted file mode 100644 index 02cd9bfa0f..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/sitios_útiles_de_la_comunidad_mozilla/index.html +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Sitios útiles de la comunidad Mozilla -slug: Mozilla/Tech/XUL/Escuela_XUL/Sitios_útiles_de_la_comunidad_Mozilla -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/Useful_Mozilla_Community_Sites ---- -<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}}{{AddonSidebar}}</p> - -<p>{{ Previous("Escuela_XUL/Documentación_de_Mozilla") }}</p> - -<p>The Mozilla Community is very rich and active. It's a very powerful tool you have when developing on top of the Mozilla platform, and you should take advantage of it in order to create a truly successful add-on .</p> - -<h2 id="AMO">AMO</h2> - -<p><a class="link-https" href="https://addons.mozilla.org/" title="https://addons.mozilla.org/">AMO</a> (Mozilla Add-ons) is the official Mozilla repository for add-ons. It allows you to upload, search and download all types of add-ons for Mozilla applications. This is the best way to get your extension to users from all around the world.</p> - -<p>Adding your extension to AMO is easy. All you need is your XPI, a few screenshots (good ones will make your extension much more appealing), and a few minutes to fill a couple of forms. But this won't make your extension public right away. AMO has a <a class="external" href="http://blog.mozilla.com/addons/2010/02/15/the-add-on-review-process-and-you/" title="http://blog.mozilla.com/addons/2010/02/15/the-add-on-review-process-and-you/">Review Process</a> that prevents malicious, insecure or low quality extensions to make it to the public site. Your extension begins in a sandbox with limited access, and once you nominate it an editor will review it and see if it is appropriate for the public AMO site, where everyone can see it and install it. The review process often takes a few weeks. Just be patient and make sure your extension follows <a class="link-https" href="https://addons.mozilla.org/en-US/developers/docs/policies/" title="https://addons.mozilla.org/en-US/developers/docs/policies/">AMO's policies</a> when you nominate it. You can still get a good number of downloads while being in the sandbox.</p> - -<p>One of the main advantages of using AMO is that it handles updates automatically for published add-ons. You just need to upload a new version of your extension, and once it's approved it will be pushed as an update to all your users. If you decide to host your own extension, you'll have to learn about the <a href="/en/Extension_Versioning,_Update_and_Compatibility#Update_RDF_Format" title="en/Extension Versioning, Update and Compatibility#Update RDF Format">update system</a> in order to push your own updates.</p> - -<h2 id="Babelzilla">Babelzilla</h2> - -<p><a class="external" href="http://www.babelzilla.org/" title="http://www.babelzilla.org/">Babelzilla</a> is a worldwide community of localizers. Developers submit their extensions using the Web Translation System (WTS) and volunteers around the world translate them to different languages. The community is very active, and you can be sure to get translations for the most commonly used languages within a few days of submitting your extension. You'll also receive feedback that you wouldn't notice by testing only in one language, which can reveal other bugs in your locale handling.</p> - -<p>There's a significant portion of users that use a localized version of Firefox, so you shouldn't neglect them. Using Babelzilla takes little time and is very valuable.</p> - -<h2 id="Mozdev">Mozdev</h2> - -<p><a class="external" href="http://www.mozdev.org/" title="http://www.mozdev.org/">mozdev.org</a> provides free project hosting and software development tools for Mozilla applications and add-ons. It is the only hosting service tailored to the needs of the Mozilla community.</p> - -<p>It offers many necessary services such as bug tracking, source code repositories, download mirrors and many communication tools. There are other free hosting sites such as Souceforge and Google Code that are also very good, but not as specialized as Mozdev. You should pick the one that best fits your development needs.</p> - -<h2 id="Conclusion">Conclusion</h2> - -<p>That's it!</p> - -<p>This is the end of the XUL School Tutorial. Hopefully this guide has helped you get started with add-on development and you're on your way to joining the large Mozilla add-ons developer community. The sheer volume of material can be overwhelming, but you can always come back and use this tutorial as a reference for your future development. Now all you need is a <a class="link-https" href="https://forums.addons.mozilla.org/viewforum.php?f=28" title="https://forums.addons.mozilla.org/viewforum.php?f=28">good idea</a> (in case you didn't have one already) and get started.</p> - -<p>Happy coding!</p> - -<p>{{ Previous("Escuela_XUL/Documentación_de_Mozilla") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> diff --git a/files/es/mozilla/tech/xul/escuela_xul/uso_de_objetos_en_javascript/index.html b/files/es/mozilla/tech/xul/escuela_xul/uso_de_objetos_en_javascript/index.html deleted file mode 100644 index ceca9d687d..0000000000 --- a/files/es/mozilla/tech/xul/escuela_xul/uso_de_objetos_en_javascript/index.html +++ /dev/null @@ -1,338 +0,0 @@ ---- -title: Uso de objetos en JavaScript -slug: Mozilla/Tech/XUL/Escuela_XUL/Uso_de_objetos_en_JavaScript -translation_of: Archive/Add-ons/Overlay_Extensions/XUL_School/JavaScript_Object_Management ---- -<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>{{ PreviousNext("Escuela_XUL/Agregar_barras_laterales", "Escuela_XUL/Objetos_XPCOM") }}</p> - -<h2 id="Chrome_JavaScript">Chrome JavaScript</h2> - -<p>In this section we'll look into how to handle JavaScript data effectively, beginning with chrome code, in ways which will prevent pollution of shared namespaces and conflicts with other add-ons resulting from such global namespace pollution.</p> - -<p>The first step to good JavaScript object management is having a namespace that you know will not conflict with Firefox code or other extensions. Namespace declaration is best located in a file of its own, so that you have this one JS file that should be included in all of your XUL files.</p> - -<p>We'll be using the placeholder <span class="namespace-name" style="color: gray;">〈Namespace〉</span> below. This needs to be replaced with an identifier name which is unique to your add-on. If your add-on is called <em>Sergeant Pepper</em>, for instance, then <code>SgtPepper</code> would be a good namespace name.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">/** - * <span class="namespace-name" style="color: gray;">〈Namespace〉</span> namespace. - */ -if (typeof <span class="namespace-name" style="color: gray;">〈Namespace〉</span> == "undefined") { - var <span class="namespace-name" style="color: gray;">〈Namespace〉</span> = {}; -}; -</pre> -</div> -</div> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">The naming standard that we normally follow is that the first part of the namespace corresponds to the development group (or company), and the second to the specific project. However, most extensions are small projects by individuals, so these examples follow a more practical approach of having just one namespace with the project name.</div> -</div> -</div> - -<p>Notice how the <span class="namespace-name" style="color: gray;">〈Namespace〉</span> namespace is declared using <em>var</em>. We need the namespace to be a global object that it can be used everywhere in the window chrome.</p> - -<p>You can include functions in any namespace, since namespaces are just regular JS objects. That should come in handy when you have general utility functions or properties that you want to use across all objects within the namespace. For instance, there are frequently used XPCOM services such as the Observer service that can be included as members in the namespace:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">/** - * <span class="namespace-name" style="color: gray;">〈Namespace〉</span> namespace. - */ -if (typeof <span class="namespace-name" style="color: gray;">〈Namespace〉</span> == "undefined") { - var <span class="namespace-name" style="color: gray;">〈Namespace〉</span> = { - /** - * Initializes this object. - */ - init : function() { - this.obsService = - Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); - } - }; - - /** - * Constructor. - */ - (function() { - this.init(); - }).apply(<span class="namespace-name" style="color: gray;">〈Namespace〉</span>); -}; -</pre> -</div> -</div> - -<p>JS objects can also be treated as string-indexed arrays:</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">// equivalent. -<span class="namespace-name" style="color: gray;">〈Namespace〉</span>.Hello = {}; -<span class="namespace-name" style="color: gray;">〈Namespace〉</span>["Hello"] = {}; - -// equivalent. -<span class="namespace-name" style="color: gray;">〈Namespace〉</span>.Hello.init(); -<span class="namespace-name" style="color: gray;">〈Namespace〉</span>.Hello["init"](); -</pre> -</div> -</div> - -<p>This is very useful in cases where you have to set attributes or functions with dynamically generated names. It's one of the funky properties of JavaScript: all objects are nothing more than name / value mappings. You can add or replace functions and attributes to any Javascript object, at any moment you want. This is an odd, but powerful feature that comes in handy at times when things get complicated. For instance, you could replace a method in any object in the Firefox chrome, so that it behaves differently than how it normally does. This should be a last resort option, but it is very useful at times.</p> -</div> -</div> - -<p>You usually need only one JS file to control a XUL window, since the code required is normally not that much. If you have complex behavior that requires too much code, look for ways to divide it into multiple objects and files. You can include as many scripts in a XUL window as you need.</p> - -<p>To initialize your chrome objects, it's usually better to run the initialization code from the "load" event handler for the window. The <a href="/en/XUL/Attribute/onload" title="en/XUL/Attribute/onload">load event</a> is fired after the DOM on the window has loaded completely, but before it's displayed to the user. This allows you to manipulate and possibly change elements in the window without the user noticing the changes.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">/** - * Controls the browser overlay <span class="code-keyword">for</span> the Hello World extension. - */ -<span class="namespace-name" style="color: gray;">〈Namespace〉</span>.BrowserOverlay = { - /** - * Initializes this object. - */ - init : function(aEvent) { - this._stringBundle = document.getElementById("xulschoolhello-string-bundle"); - // you can make changes to the window DOM here. - } - // more stuff -}; - -window.addEventListener( - "load", function() { <span class="namespace-name" style="color: gray;">〈Namespace〉</span>.BrowserOverlay.init(); }, false); -</pre> -</div> -</div> - -<p>There are some things you can't (or shouldn't) do inside load handlers, such as closing the window being loaded, or opening new windows, alerts or dialogs. The window has to finish loading before it can do any of these things. They are bad UI practices anyway and you should avoid them. If you really need to do something like this anyway, one way to do it is to have a timeout execute the code after a delay:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">init : function(aEvent) { - let that = this; - - this._stringBundle = document.getElementById("xs-hw-string-bundle"); - window.setTimeout( - function() { - window.alert(that._stringBundle.getString("xulschoolhello.greeting.label")); }, 0); -} -</pre> -</div> -</div> - -<p>The <a href="/en/DOM/window.setTimeout" title="en/DOM/window.setTimeout">setTimeout</a> function executes the function in the first parameter, after a delay in miliseconds specified by the second parameter. In this case we set the delay to 0, which means the function should be executed as soon as possible. Firefox has a minimum delay of 10-15ms (taken from <a class="external" href="http://ejohn.org/blog/analyzing-timer-performance/">this blog post</a>), so it won't really run instantly. It is more than enough to let the window finish its load.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">Use <a href="/en/DOM/window.setTimeout" title="en/DOM/window.setTimeout">window.setTimeout</a> and <a href="/en/DOM/window.setInterval" title="en/DOM/window.setInterval">window.setInterval</a> to control timed code execution. In case you're using JavaScript Code Modules or XPCOM objects, where a window object is not readily available, use an <a href="/en/XPCOM_Interface_Reference/nsITimer" title="en/nsITimer">nsITimer</a> instead. </div> -</div> -</div> - -<div class="note"><a class="external" href="http://dbaron.org/log/20100309-faster-timeouts" title="http://dbaron.org/log/20100309-faster-timeouts">This post</a> suggests a way to achieve a true zero ms timeout, as a simple way to achieve parallelism in JS code.</div> - -<p>Notice the way we send callback functions as parameters, and the use of an alternate reference for <em>this</em> which we always name <em>that</em>. This is all necessary due to a JavaScript feature (quirk would be a better word for it) called <a href="/en/JavaScript/Reference/Operators/Special/this" title="en/Core JavaScript 1.5 Reference/Operators/Special Operators/this Operator">Method Binding</a>. The consequence of doing this wrong is to have a <em>this</em> reference that doesn't do what you expected it to do. There are a few workarounds for this, and we use the ones we have found to be the most elegant and clear to read.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">The general guideline we follow is this: whenever you have to set a callback function parameter, wrap it in an anonymous function. That is, something like <em>function() { /* your code, usually a single function call. */ }</em>. If you have to use a reference to <em>this</em> inside the function, declare a variable called <em>that</em> that equals <em>this</em>, and use <em>that</em> in the anonymous function.</div> -</div> -</div> - -<p>JavaScript has a host of features that make it extremely flexible, but it also has some disadvantages, as it is not as strict as other languages, such as Java. A clear example of this is the fact that there are no <em>private</em> or <em>public</em> keywords that allow you to protect object members. As a alternative for this, a naming standard is frequently used to distinguish private and public members. There's no scope enforcement whatsoever, but this standard give others the chance to "play nice" and don't use private members.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">Use "<em>_"</em> at the beginning of private attributes and methods in JS objects. For example: <em>_stringBundle</em>, <em>_createUserNode()</em>.</div> -</div> -</div> - -<h3 id="Exercise">Exercise</h3> - -<p>Here's a short exercise to test a particular aspect of the chrome. Modify the Hello World extension so that the message says how many times it has been displayed. The message could say something like "Hello! This message has been shown 5 times." Keep the counter as a variable in the <em>BrowserOverlay</em> object, and increment it every time the message is going to be shown.</p> - -<p>Once you have this working right, try the following: open the message a few times, so that the number increments. Now open a new window and display the message from the new window. What do you think will happen? What will the count be this time?</p> - -<p>You probably didn't expect this, but the count was reset in the new window. Each window keeps its own counter, and now the extension is not behaving as expected. This is a fundamental lesson: <strong>the chrome is not global, it's window-specific.</strong> All of your scripts and objects are replicated for each window, and they work independently from each other. This is an issue that is very easy to overlook, since most Firefox users, specially power users, have a single window open at all times. You have to make sure you test your extension with multiple windows open; never assume everything will work the same as with a single window.</p> - -<p>Now, in most cases you'll need to coordinate data in a way that it is consistent for all open Firefox windows. There are several ways in which you can do this. Preferences is one of them, and they are covered in another section of this tutorial. Two other ways are JavaScript Code Modules (Firefox 3 and above), and XPCOM.</p> - -<h2 id="JavaScript_Code_Modules">JavaScript Code Modules</h2> - -<p><a href="/en/JavaScript_code_modules/Using" title="en/Using JavaScript code modules">JavaScript Code Modules</a> (also known as JSM) are new to Firefox 3, and they're the best tool for keeping everything in sync between windows. They're very simple to set up. The first thing you need to do is add an entry in the <em>chrome.manifest</em> file:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">resource xulschoolhello modules/ -</pre> -</div> -</div> - -<p>Javascript code modules are accessed with the <em>resource</em> protocol, which is very similar to the <em>chrome</em> protocol. Just like with the chrome, we define the package name and then a path. To keep things simple, just locate the JSM files in a <em>modules</em> directory under the root of our project. In order to access a file <em>messageCount.js</em> in this directory, the URL would be:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java">resource:<span class="code-comment">//xulschoolhello/messageCount.js</span> -</pre> -</div> -</div> - -<p>Code modules are regular JS files, so there's nothing new in regards to naming or file types. Mozilla has adopted a standard of using the extension <em>.jsm</em> for these files, but they say <em>.js</em> is fine as well. To keep things simple, specially regarding code editors and default file associations in the developer's system, we have decided to stick with <em>.js</em>.</p> - -<p>Download this version of the <a href="/@api/deki/files/5143/=HelloWorld3.zip" title="https://developer.mozilla.org/@api/deki/files/5143/=HelloWorld3.zip">Hello World project with JSM</a> to see the changes you need to make to the build system in order to include the files in the <em>modules</em> folder. They are minimal, and we add a very small <em>Makefile.in</em> file in the <em>modules</em> directory, just to keep everything separated and organized.</p> - -<p>With the setup out of the way, let's get to it. What are JavaScript Code Modules?</p> - -<p>A JavaScript Code Module is a regular JS file that specifies which of the declared elements in it are public. All module files should begin with the a declaration like this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="code-java"><span class="code-keyword">var</span> EXPORTED_SYMBOLS = [ <span class="code-quote">"<span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span>"</span> ]; -</pre> -</div> -</div> - -<p>EXPORTED_SYMBOLS is a special identifier that tells Firefox that this file is only publishing the object named <em><span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span></em>. Several objects, functions and variables can be declared on this file, but the only object visible from the outside will be <em><span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span></em>, which is a namespace in our case. Because of namespacing, we don't need to worry much about what to export, usually we just need the namespace object. All of the objects inside of it are exported as well, since they are members of the <em><span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span></em> object.</p> - -<p>Module files can be imported to a chrome script or to other code modules with the following line:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">Components.utils.import("<a class="external" rel="freelink">resource://xulschoolhello/messageCount.js</a>"); -</pre> -</div> -</div> - -<div class="note">When using <a href="/en/Components.utils.import" title="en/Components.utils.import">Components.utils.import</a>, code modules must be loaded using a <strong>file:</strong> or <strong>resource:</strong> URL pointing to a file on the disk. In particular, <strong>chrome:</strong> URLs (even those that point to a file outside a jar archive) are not valid.</div> - -<p>To get a better idea, let's look at the code of the modified Hello World example. We have defined two files, one to declare namespaces and another one for the message count functionality mentioned in the previous exercise.</p> - -<p>Here again we're using a placeholder, <span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span>, for the identifier name that you'll need to choose.</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">var EXPORTED_SYMBOLS = [ "<span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span>" ]; - -const { classes: Cc, interfaces: Ci } = Components; - -/** - * <span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span> namespace. - */ -var <span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span> = {}; -</pre> -</div> -</div> - -<p>This should all be familiar enough. We're declaring the namespace we'll use at the module level. We need a separate namespace for the chrome because the chrome namespace objects are repeated for each window, while the module namespace objects are unique for all windows. Setting window-specific data on code modules will lead to nothing but problems, so be careful when deciding what should be chrome and what shouldn't be. We needn't test for the pre-existence of our namespace object here, as modules are given their own namespace.</p> - -<p>The 2 declared constants above are used to reduce code size. We frequently need to use XPCOM components in our code, so instead of doing this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this.obsService = - Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService); -</pre> -</div> -</div> - -<p>It's better to do this:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">this.obsService = - Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); -</pre> -</div> -</div> - -<p>These 2 constants don't need to be defined in the overlay because they are already defined globally in the <em>browser.js</em> file in Firefox. We only need to define them when we're making windows of our own, or when we're working with code outside of the chrome (or porting your code to SeaMonkey, which doesn't have those constants declared in the main window).</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">Include the Cc and Ci constants in all XUL windows that are not overlays, all JSM files, and all XPCOM components (see further ahead). Do this even if you don't need them now. It's better to just make a habit out of it.</div> -</div> -</div> - -<p>This is a point that is worth highlighting: modules work outside of the window scope. Unlike scripts in the chrome, modules don't have access to objects such as <em>window</em>, <em>document</em>, or other global functions, such as <em>openUILink</em>. These are all UI components and UI operations anyway, so they are better done in the chrome.</p> - -<div class="panel" style="border-width: 1px;"> -<div class="panelContent"> -<div class="note">As a general guideline, we keep all of our business logic in JSM, available through service objects, and chrome scripts are limited to handle presentation logic.</div> -</div> -</div> - -<p>We handle most of our code through static objects, singleton objects that don't require instantiation. But it is sometimes necessary to define classes and be able to create multiple instances. Common cases include interacting with a local database or a remote API. Data will often be translated into arrays of entities, and those are better represented through classes. One way to define a class is as follows:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">/** - * User class. Represents a Hello World user (whatever that may be). - */ -<span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span>.User = function(aName, aURL) { - this._name = aName; - this._url = aURL; -}; - -/** - * User class methods. - */ -<span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span>.User.prototype = { - /* The name of the user. */ - - _name : null, - /* The URL of the user. */ - - _url : null, - - /** - * Gets the user name. - * @<span class="code-keyword">return</span> the user name. - */ - get name() { - return this._name; - }, - - /** - * Gets the user URL. - * @return the user URL. - */ - get url() { - return this._url; - } -}; -</pre> -</div> -</div> - -<p>In this example we defined a fictitious <em>User</em> class for the Hello World extension. Using the function keyword to define a class is odd, but this is just the JavaScript way: functions are also objects. The definition of the class acts as a constructor as well, and then you can define all other members using the <em>prototype</em> attribute. In this case we defined "getter" properties for the <em>name</em> and <em>url</em> members. This way we have immutable instances of our class. Well, only if consumers of the class play nice and don't change anything they shouldn't.</p> - -<p>Creating an instance and using it is simple enough:</p> - -<div class="code panel" style="border-width: 1px;"> -<div class="codeContent panelContent"> -<pre class="brush: js">let user = new <span class="namespace-name" style="color: gray;">〈ModuleNamespace〉</span>.User("Pete", "<a class="external" href="http://example.com/pete" rel="freelink">http://example.com/pete</a>"); - -window.alert(user.name); -</pre> -</div> -</div> - -<p>This is something you can do with JS in general. You can use it in JSM, chrome, even on regular web pages. Since entities tend to be used all throughout an application, we think that having those classes defined at the module level is the best approach.</p> - -<p>JSM is the best solution to handle objects that are window-independent. In the following section we'll discuss XPCOM, which is an older alternative to JSM and one of the foundations of Mozilla applications. You shouldn't skip that section because there are many common situations in extension development where you'll <em>have</em> to use XPCOM, maybe even implement XPCOM components of your own.</p> - -<p>{{ PreviousNext("Escuela_XUL/Agregar_barras_laterales", "Escuela_XUL/Objetos_XPCOM") }}</p> - -<p><span style="font-size: small;">This tutorial was kindly donated to Mozilla by Appcoast.</span></p> |