elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Usando Git para manipular el directorio de trabajo, el índice y commits (segunda parte)


+  Foro de elhacker.net
|-+  Informática
| |-+  Tutoriales - Documentación (Moderadores: r32, ehn@)
| | |-+  introduccion a la creacion de extensiones para el firefox
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: introduccion a la creacion de extensiones para el firefox  (Leído 5,776 veces)
vacio
Visitante


Email
introduccion a la creacion de extensiones para el firefox
« en: 23 Marzo 2007, 21:09 pm »

una pequeña traduccion de 2 capitlos del libro “Hacking Firefox More Than 150 Hacks Mods and Customizations”, espero que le sirva a alguien, cualquier correccion, comentario sera bienvenido.

http://myfreefilehosting.com/f/10615c45db_0.06MB


Primero deseo dejar  claro que la mayor parte del contenido de este texto no es mio, gran parte es un defectuosa traducción de 2 capítulos del “Hacking Firefox More Than 150 Hacks Mods and Customizations” omitiendo muchas partes importante en ellos, consultas en Wikipedia, copias directas de otros escritos, etc. he decidido hacer esta “traducción” primero porque mi ingles es pésimo y así aprendo un poco y segundo porque deseaba aprender un poco acerca del tema y los tutos acerca de la creación de extensiones normalmente son demasiado cortos y no abarcan muchos temas.

Este texto esta plagado de errores conceptuales y de traducción de los cuales no me voy a excusar, si a alguien no le gusta pues que se ahorre criticas y mejor dedique ese tiempo a hacer las correcciones correspondientes.
 
Antes de comenzar seria bueno conseguir una extensión que son facilitara mucho nuestra tarea la Extension Developer's Extension la cual podemos descargar de: http://ted.mielczarek.org/code/mozilla/extensiondev/index.html
así que la mayoría de ejemplos dados en la introducción a XUL y otras secciones se podrán probar, después de instalarla solo debemos ir e utilizar la herramienta correspondiente en Herramientas-> Extension Developer->....
no es mala idea darle una mirada a las herramientas disponibles y jugar un poco con ellas antes de pasar a estudiarlas. Además se deberí tener tener el DOM Inspector al cual puedes acceder si usas Debian con:
 aptitude search mozilla-firefox-dom-inspector

Creo que eso es todo lo que se necesita para empezar así que:

Introducción al CSS, javascript, XUL y demás.

Introducción a XUL

Qué es XUL: http://es.wikipedia.org/wiki/XUL

El elemento básico de un documento XUL es el widget (http://es.wikipedia.org/wiki/Widget). Botones, cajas de texto, menu de items, etc son creados al insertar los elementos apropiados dentro de un documento XUL. Los atributos de este elemento determinan varias propiedades de tu widget. Por ejemplo, lo siguiente define un botón simple:

<button label=”textooo” />

el atributo label determina que texto aparece en el botón. Una caja de texto se podría definir así:

<textbox value="escriba su texto aquí" />




estos elementos tienen atributos adicionales como lo son:

maxlength: máximo numero de caracteres que pueden meter en en un text box
readonly:  pone cajas de entrada para solo entrada
type:   se pueden crear cajas de entrada para propósitos especiales.
   por ejemplo poniendo este valor a "password" crea un caja de
   entrada de password.

XUL usa un esquema llamado box model para especificar como están orientados los
elementos, alineados, y posicionados. la interfaz de usuario esta dividida en dos "cajas".
una caja puede contener elementos UI  o otras cajas. cada caja especifica si sus elementos
hijos esta alineados horizontalmente o verticalmente.

por ejemplo, lo siguiente especifica que deseamos tres botones arreglados en una fila:

<hbox>
   <button label="rojo"/>
   <button label="verde"/>
   <button label="azul"/>
</hbox>

similarmente para crear botones arreglados de forma vertical:

<vbox>
   <button label="rojo"/>
   <button label="verde"/>
   <button label="azul"/>
</vbox>

un ejemplo de un documento XUL completo seria:

<?xml version="1.0" ?>
<window orient="horizontal"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <textbox value="entra tu texto aqui"/>
   <button label="Ir"/>
</window>
 
Copia el texto anterior en el XUL Editor yendo a Herramientas->Extension Developer->XUL Editor y allí tendrías una vista previa de lo que se obtendría.

Un espacio de nombres indica los elementos que se reconocen como válidos a la hora de interpretar el fichero; en este caso en concreto solo se reconocerán los elementos definidos en XUL, eso es lo que hace la URL http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul (notar el there is only xul).
Mas informacion sobre otros elementos XUL se puede obtener en:
http://www.xulplanet.com/references/elemref/
Insisto: juega con ultimo ejemplo mezclándolo con los demás.

RDF

Resource Description Framework (plataforma de descripción de recursos) es una tecnología para describir recursos de Internet. es típicamente implementado como un archivo XML que tiene una sintaxis especial. RDF es complejo y este tema esta fuera del alcance de este libro.

la especificación del RDF  es mantenida por W3C. para mas información acerca de esta tecnología visite:
http://www.mozilla.org/rdf/doc

Sabemos que es el XUL y también que se puede usar para crear interfaces de usuario. pero el XUL por
si mismo no es muy útil. necesitamos una forma de agregar funcionalidad a nuestra interfaz de usuario.
esto es usualmente hecho con javascript.

vamos a crear una simple interfaz de usuario con XUL, dos cajas y un botón:

<hbox>
   <textbox id="primera"/>
   <textbox id="segunda"/>
   <button label="agregar" oncommand="calcularSuma()"/>
</hbox>

cada vez que el botón "agregar es presionado se hace una llamada a la función calcular
suma, la cual podría ser implementada así:

fuction calcularSuma()
{
   var valor1=document.getElementById("first-box");
   var valor2=document.getElementById("second-box");
   var entero1=parseInt(valor1.value);
   var entero2=parseInt(valor2.value);
   alert(entero1+entero2);
}

finalmente se puede crear el siguiente archivo XUL:

<?xml version="1.0"?>
<window align="start"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script type="application/x-javascript">
   <![CDATA[
   function calculateSum() {
   var firstBox = document.getElementById("first-box");
   var secondBox = document.getElementById("second-box");
   var a = parseInt(firstBox.value);
   var b = parseInt(secondBox.value);
   alert(a + b);
   }
   ]]>
</script>
<hbox>
   <textbox id="first-box"/>
   <textbox id="second-box"/>
   <button label="Add" oncommand="calculateSum()"/>
</hbox>
</window>

Cascading Style Sheets, CSS

Las hojas de estilo en cascada es un mecanismo para especificar la apariencia del HTML,XML,XUL
y otros documentos. con CSS, puedes especificar colores, fuentes, tamaños y otros elementos.

CSS te permite separar el contenido de un documento con su presentación. por ejemplo, tu documento
XUL puede especificar que tu interfaz de usuario contiene una caja de entrada y dos botones.
entonces una hoja de estilo puede ser usada para especificar el tamaño de campo de entrada, el color
de los botones y la fuente de las etiquetas. hay muchas ventajas de separar el estilo del documento
y su contenido. la primera y posiblemente el beneficio mas importante es la flexibilidad. si defines
toda la información relacionada con la presentación en una hoja de estilo separada, te sera mas fácil
modificar el estilo de la interfaz de usuario sin la necesidad de ajustar el contenido del documento.
tus archivos HTML o XUL serán mas legibles y limpios.

una típica definición CSS es una lista de reglas. las reglas tiene un selector que especifican los elementos a los que la regla aplica y una lista de declaraciones de estilo. por ejemplo, una regla para cambiar la apariencia de todas los elementos "label" debería lucir como esto:

label
{
   font-family: arial;
   font-weight: bold;
   color: blue;
}

en esta regla, label es el selector; esto especifica que la regla aplica a todos los elementos label.
cada elemento en nuestro documentos HTML o XUL puede tener una atributo class que puede ser usado para especificar que muchos elementos están relacionados uno a toro de alguna manera. los elementos también pueden tener un atributo id.  a diferencia de class, el atributo id debe ser único en el documento. vamos a mirar un fragmento de un documento XUL para clarificar las cosas un poco:

<button id="boton-play" class="control" label="play"/>
<button id="boton-stop" class="control" label="stop"/>

así se pueden aplicar estilos a todos los elementos con el atributo class="control" o a un solo elemento individual. el atributo id sera también practico si desea encontrar un elemento usando javascript.

miremos unos pocos ejemplo de varias declaración de estilos que podemos aplicar a nuestros documentos y específicamente a los dos botones del ejemplo anterior.

para especificar un estilo para todos los botones en su documento, puede usar lo siguiente regla:

button {border:1px solid red;}

también le puede dar un estilo a los elementos button de una clase especifica:

button.control { color:blue}

además si desea aplicar un estilo a todos los elementos de una clase sin importar el tipo:

.control {color:blue;}

y finalmente para cambiar un solo elemento, se especifica su id y se le aplica el estilo así:

#stop-button {font-weight:bold;}

THE DOCUMENT OBJECT MODEL

el DOM es una colección de interfaces para trabajar con documentos HTML y XML. estos documentos están representados por un árbol de elementos. el DOM define métodos para navegar y buscar este árbol, recuperar información acerca de varios elementos, modificar la estructura de árbol removiendo e insertando elementos, manipular elementos individuales,etc.

Cross Platform Component Object Model

Los componentes son módulos de software con una funcionalidad bien definida. ellos son los bloques que construyen la aplicación y pueden ser combinados en un programa en tiempo de ejecución.

hay mucho beneficios al desarrollar software que emplee componentes. dos de esos beneficios son:

* usar componentes nos permite ignorar la implementación; en efecto, no necesitamos saber nada
acerca de la implementación. todo lo que necesitamos para conocer es los componentes de la interfaz,
sus métodos y propiedades. el autor de la componente puede cambiar la forma como la componente lleva a cabo una acción, o solucionar un bug, y proveer una nueva version de el componente. mientras la interfaz sea la misma, nuestro programa no tiene porque acomodarse a la nueva implementación.

* el mismo componente puede user usado en diferentes ambientes de software. la interfaz del
componente no asume nada acerca del sistema operativo, lenguaje de programación, o programa que
usara la componente.

Cuando estas escribiendo una programa en Mozilla tienes acceso a un amplio rango de componentes
e interfaces. en efecto, casi cualquier funcionalidad que usted podría necesitar estará disponible
como un componente XPCOM. algunas categorías de los componentes son las siguientes:

Browser: estas interfaces te permiten acceder al historia de navegación, auto completar, descargas, y
otras funcionalidades.

Clipboard: estas interfaces te permiten modificar el contenido del portapapeles.

File: un conjunto de componentes e interfaces que pueden ser usados para acceder, listar, modificar
archivos y directorios.

DOM: la mayoría de estas interfaces corresponder a las definiciones del W3C DOM .

Network: interfaces que te permiten abrir conexiones de red, transferir información y mas.

Preferences: estas interfaces pueden ser usadas para recuperar y modificar preferencias de usuario.

lo siguiente es un ejemplo para usar XPCOM de javascript. usaremos la interfaz de preferencias para determinar el color de texto predeterminado por el usuario. primero, necesitamos obtener las preferencias del servicio del objeto XPCOM:

var prefs=Components.classes["@mozilla.org/preferences-service,1*];
prefs= prefs.getService(Components.interfaces.nsIPrefBranch);

primero usamos una arreglo de clases que es parte del componente de objetos para encontrar el componente XPCOM especifico. los elementos de este arreglo son indexados por la contracción del id, una cadena única que identifica cada componente. en nuestro caso,@mozilla.org/preferences-service;1 identifica el servicio preferencias, el componente usado para acceder a las preferencias de usuario. después de encontrar el componente deseado, podemos obtener el objeto del componente especifico usando el método getService y especificando la interfaz deseado, en nuestro caso nsIPrefBranch.

algunas componentes son definidos como servicios, esto significa que solo una instancia de el componente existe en la aplicación. esos componentes son obtenidos usando el método getService. los componentes que no son servicios pueden tener diferentes instancias. para crear una nueva instancias de un componente, usa el método createInstance. la documentación de la componente debería indicar cuando un componerte es un servicio.

después de obtener la interfaz deseado, llamamos a una de sus funciones. por ejemplo, nosotros podemos usar el método getCharPref de la interfaz nsPrefBranch para obtener el valor de la preferencia del usuario:

var color=prefs.getCharPref("browser.display.foreground_color!);

así se obtendría el dato en cuestión.

recursos adicionales sobre XPCOM

* www.mozilla.org/projects/xpcom
* www.xulplanet.com/references/xpcomref




Antes de comenzar a hacer una extensión más seria primero procederemos a fabricar algunas que aunque no tendrán utilidad nos permitirán tener una visión general acerca de la estructura de una extensión y una idea intuitiva de su funcionamiento.

las extensiones se encuentran en un archivo .xpi que no es mas que un archivo .zip renombrado, el cual tendrá la siguiente estructura:

miextension.xpi
   chrome.manifest
   install.rdf
   chrome/
      miextension.jar
y el archivo miextension.jar también es un .zip renombrado, el cual tiene la siguiente estructura:

miextension.jar
   content/
      miextension/
      miextensionOverlay.xul
      miextensionOverlay.js
   skin/
   locale/

el archivo miextensionOverlay.xul tiene como nombre parte de su nombre overlay ya que su contenido se “insertará” en ejecución en el archivo browser.xul, bueno pero que demonios es browser.xul y donde lo localizo??, este archivo se puede localizar  en ~/.mozilla/firefox/chrome/ donde se encontrara el archivo browser.jar (Importante: hasle una copia de respaldo) , dentro de este hay un directorio llamado content y dentro de este hay dos mas, entra al llamado browser y encontraras el browser.xul, este es muy importante ya que define la interfaz de usuario de nuestro navegador. pero antes de definir el contenido del archivo miextensionOverlay.xul por que no jugamos un poco con el browser.xul??? , entonces abramoslo con un editor de texto y busquemos la cadena:
<menu id="edit-menu" me imagino que ya deben suponer a que se refiere, pero como todavía no sabemos mucho simplemente pongamos <menuitem label="hola" /> de forma que el archivo quede así:

<menu id="edit-menu" label="&editMenu.label;"
                  accesskey="&editMenu.accesskey;">
              <menupopup id="menu_EditPopup">
              <menuitem label="hola_mundo" />
   .......

si se guardan cambios, se comprime el archivo, se le cambia la extensión a .jar y se reemplaza por el original y reiniciamos el Firefox y vamos a Editar podremos ver los resultados. Ahora comentemos un poco que algunas cosas que se pasan a primera vista, en nuestra etiqueta ponemos hola_mundo en y no se encuentra el & que sí está en la definición de la etiqueta del menu, por qué??  imaginen que en algún momento alguien desea traducir la extension, no seria muy engorroso ir por el código cambiando cadenas de texto, para solucionar esto se creo un archivo .dtd el cual contendrá la cadenas y en nuestro archivo .xul solo tendremos que incluir el archivo en cuestión y hacer referencia al identificador de la cadena. Esto se puede ver al inicio del browser.xul:

<!DOCTYPE window [
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd" >
%browserDTD;
.....
]>

estos archivos normalmente se encuentran dentro de un subdirectorio de locale, el cual contendrá la iniciales correspondientes a nuestro idioma, por ejemplo  en_US.

otra vez insisto, jueguen con el documento (para esos tenemos una copia de respaldo del browser.xul), por ejemplo basándome en la estructura de la definición del menu que puedo encontrar aquí: http://www.xulplanet.com/references/elemref/  como ya antes había dicho podemos poner nuestro propio menu, pero primero lo probaremos en el XUL Editor que trae la extensión que descargamos, sería algo como:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="yourwindow" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<menu id="mi_menu" label="Final Fantasy">
      <menupopup id="Final-Fantasy-popup">
        <menuitem label="Final Fantasy VII"/>
        <menuseparator/>
        <menuitem label="Final Fantasy VIII"/>
        <menuitem label="Final Fantasy IX"/>
        <menuseparator/>
      </menupopup>
</menu>
</window>

obviamente solo copiaremos la parte subrayada en el browser.xul ya que el resto se vera mas adelante, el texto se debería insertar antes o después de la definición de un menu, pongamoslo antes del menu Editar, y agreguemosle algo de “funcionalidad” con javascript:

<menu id="mi_menu" label="Final Fantasy">
          <menupopup id="Final-Fantasy-popup">
           <menuitem label="Final Fantasy VII" oncommand="alert('si, esta es la mejor')"/>
           <menuseparator/>
           <menuitem label="Final Fantasy VIII" oncommand="alert('la VIII??')"/>
           <menuitem label="Final Fantasy IX" oncommand="alert('la IX??')" />
           <menuseparator/>
          </menupopup>
</menu>
 
            <menu id="edit-menu" label="&editMenu.label;"
                  accesskey="&editMenu.accesskey;">
              <menupopup id="menu_EditPopup">
      <menuitem label="hola" />
   ......

si pueden cambiar los alert() por otras funciones como window.minimize() u otros, para eso es fundamental estudiar un poco mas a fundo javascript, con el código anterior obtendremos algo como:





a alguien le gustaría poner su propia barra de menus?? no es muy complicado solo consulten un poco sobre menubar y miren la forma como se utiliza en browser.xul hacen los cambios correspondientes, comprimen, renombran, reemplazan el browser.jar y eso es todo. Que tal si le ponemos una nueva barra de estado con texto?? bueno yo buscaría sobre algo como statusbar  y después de consultar llego a algo como:

   <statusbar id="barra_de_estado">
      <statusbarpanel id="mipanel" label="texto1"/>
      <statusbarpanel id="mipanel2" label="texto2"/>
   </statusbar>
si no deseamos una barra nueva sino añadirle el texto a la existente pues omitimos la definición de la barra de estado e insertamos los statuspanel dentro de la barra ya definida.
 La idea era dar un vision mas o menos de como las extensiones modifican la interfaz de usuario y dar así una aplicación a los fundamentos aprendidos en la primera parte de este texto, así la siguiente sección será más suave.
Nota: recordemos reemplazar el browser.jar original por el modificado antes de continuar.




Introducción a la Programación de Extensiones para el Firefox


que pueden hacer las extensiones???

* extender la funcionalidad existente
* asistir a los desarrolladores de web
* hacer la edición de formularios mas conveniente
* mejorar la navegación y la accesibilidad
* modificar el aspecto de las paginas
* búsqueda e integración con las webs.



Creando tu Primera Extensión

la extensión que se creara en esta sección sera llamada SiteLeds. la idea es tener un icono, o un led de estado,  en la barra de estado del Firefox que muestre el estado de una pagina web dada -- si esta disponible o no, y si si fue recientemente cambiada.

Introducción A Chrome

Crear aplicaciones con Mozilla es muy similar a crear paginas web dinámicas. los documentos XUL definen la interfaz de usuario, javascript la hace dinámica, y las hojas de estilo especifican su presentación. para especificar aplicaciones de recursos (documentos XUL, cascadas de estilos CSS, y muchos otros componentes de nuestra aplicación), usaras un URL chrome. la Web es el lugar donde todas las paginas web se encuentran. similarmente, el chrome contiene todos los elementos de la interfaz de usuario de nuestra aplicación.

para que el navegador encuentre una pagina web usando su URL, el dominio de la pagina debe ser registrado en un registro de dominio. similarmente, para Mozilla localizar los archivos que definen una aplicación XUL, los paquetes que contienen esos archivos primero deben estar registrados en en registro chrome. cuando el navegador recibe una URL chrome, este mira en el registro chrome obteniendo la localización de los archivos de instalación necesitados, entonces carga el documento de esa localización. usando este método para acceder a los recursos de nuestra aplicación nos permite ser independientes de la localización física de los archivos, si el registro chrome tiene la información correcta.
una típica URL chrome se vera como la siguiente:

chromre:// <nombre del paquete> / <tipo de recurso> / <nombre del archivo>

esta URL tiene diferentes partes

chrome: esto indica que se utilizara un recurso chrome

nombre del paquete: no creo que haya mucho que decir

tipo de recurso: pueden ser tres tipos:

content:  contiene la definición de la interfaz de usuario y su comportamiento. los archivos XUL y  javascript se encuentran en esta parte del paquete.
locale: aquí se deberían poner los documentos que contienen todas las cadenas utilizadas en la interfaz de usuario, ya que así se facilita la tarea de traducción de los paquetes. normalmente estos se encuentran en un XML Document Type Definition (DTD).
skin: esta parte contiene los archivos que definen la interfaz de usuario, entre ellos hojas de estilo en cascada.

Creando la extensión SiteLeds

Creando la interfaz de usuario

es muy simple ay que solo consta de un icono en la barra de estado, como se desea agregar un icono a l barra de estado nuestra interfaz de usuario consta solo de un elemento del tipo statusbarpanel:

<statusbarpanel class=”statubarpanel-iconc”
id=”SiteLed” />
tooltiptext=”SiteLed icono de estado”
sitestate=”unknow”/>

se uso la clase estatusbarpanel-iconc para especificar que se se mostrara el icono en la barra de estado. es importante darle una id única a nuestro elemento para así poder hacer referencia a él en un futuro.

el atributo tooltiptext  especifica que texto aparecerá en el panel tooltip.

ahora que se ha creado la interfaz de usuario, como se le dice al Mozilla que este existe y debe aparecer en la barra de estado?? para esto existe un mecanismo llamado dynamic overlay (recubrimiento dinámico) que permite cambiar la interfaz de usuario sin cambiar el archivo que lo define. en este caso en particular deseamos modificar la barra de estado sin modificar el archivo browser.xul.

para definir nuestro nuevo documento como un recubrimiento se debe darle otra id que lo identifique como tal, y además donde se debe “insertar en el documento” y queremos que sea antes de mostrarlo, por tanto se obtiene el siguiente código:

<overlay id=”siteleds-overlay”
xmlns=”http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul”>
<statusbar id=”status-bar”>
<statusbarpanel class=”statusbarpanel-iconic”
   id=”siteleds-statusbar-panel”
   tooltiptext=”SiteLeds Status Icon”
   sitestate=”unknown”
   insertbefore=”statusbar-display”/>
</statusbar>
</overlay>

ahora, deseamos que el icono mostrado cambie según el estado de la pagina, por tanto se utilizaran diferentes iconos:

falta: insertar iconos correspondientes a cada cosa

El documento de estilo de holas se llamara siteledsOverlay.css, este podría lucir como el siguiente:

#siteleds-statusbar-panel[sitestate="unknown"] {
    list-style-image: url("chrome://siteleds/skin/state-unknown.png");
}
#siteleds-statusbar-panel[sitestate="ok"] {
    list-style-image: url("chrome://siteleds/skin/state-ok.png");
}
#siteleds-statusbar-panel[sitestate="error"] {
    list-style-image: url("chrome://siteleds/skin/state-error.png");
}
#siteleds-statusbar-panel[sitestate="modified"] {
    list-style-image: url("chrome://siteleds/skin/state-modified.png");
}

como se puede ver se esta seleccionando la barra de estado por su atributo id (siteleds-status-bar-panel), y especificando que icono mostrar definiendo las diferentes reglas para diferentes valores del atributos sitestate. el icono que deseamos que aparezca es especificado usando el atributo de CSS list-style-image.

Agregando Funcionalidad

la pregunta seria entonces como saber que la pagina se encuentra en linea, se ha modificado, etc. pues esto se obtiene con javascript y este mismo cambia el atributo stiestate del el panel dependiendo del caso.

el archivo a creare sera llamado siteledsOverlay.js


var gSiteLedsLastRequest = null;
var gSiteLedsLastContent = null;

function siteLedsCheckPage() {
var pageURL = ‘http://www.iosart.com/Firefox/siteleds/index.html’;
gSiteLedsLastRequest = new XMLHttpRequest();
gSiteLedsLastRequest.onload = siteLedsPageLoaded;
gSiteLedsLastRequest.onerror = siteLedsPageError;
gSiteLedsLastRequest.open(‘GET’, pageURL);
gSiteLedsLastRequest.send(null);
}

la función hace lo siguiente:
se cre un nuevo objeto XMLHttpRequest. Este objeto es usado para realizar pedidos HTTP.
se agregan dos manejadores de eventos. la función siteLedsPageLoaded es llamada cuendo nuestro servidor responde a nuestra pregunta, y la función siteLedsPageError es ejecutado en caso de ocurrir un error  durante el pedido HTTP.
se inizializa y envia un HTTP GET repuest para la web especifica.

nuestra función manejadora de errores se vería como esto:

function siteLedsPageError() {
var ledElement = document.getElementById(‘siteleds-statusbar-panel’);
ledElement.setAttribute(‘sitestate’, ‘error’);
setTimeout(siteLedsCheckPage, 900000);
}

esta función es llamada si hay un error durante el intento de cargar la pagina monitoreada. primero se pone el valor del atributo sitestate como error. este a traves de las definiciones en nuestras cascadas de estilos, hará que el icono de error aparezca en la barra de estado. finalmente, se puede llamar a la función setTimeout para intentar realizar la misma prueba después de 900,000 milisegunds (15 minutos).

Si el servidor responder a nuestra petición HTTP, la función siteLedsPageLoaded es llamada:

function siteLedsPageLoaded() {
var ledElement = document.getElementById(‘siteleds-statusbar-panel’);
if (gSiteLedsLastRequest.status == 200) {
var prevContent = gSiteLedsLastContent;
gSiteLedsLastContent = gSiteLedsLastRequest.responseText;
if ((prevContent != null) && (prevContent != gSiteLedsLastContent)) {
ledElement.setAttribute(‘sitestate’, ‘modified’);
} else {
ledElement.setAttribute(‘sitestate’, ‘ok’);
setTimeout(siteLedsCheckPage, 900000);
}
} else {
ledElement.setAttribute(‘sitestate’, ‘error’);
setTimeout(siteLedsCheckPage, 900000);
}
}

Primero, se revisa si el servidor regreso un un código de estado HTTP 200 (OK). si es así, la pagina sera cargado correctamente, y podemos mirar si fue cambiada desde la ultima vez que la pagina fue cargada y dependiendo de la respuesta, el estado sera ok o modified. si el servidor regreso un código de estado diferente a 200, se pondrá en nuestro panel el estado error. si la pagina no fue modificada, se programa una nueva prueba en 15 minutos donde se llamara al función setTimeout.

Después de definir todas las funciones necesitadas, debemos decirle al Firefox que comience el ciclo de revisión cuando este se carga agregando la siguiente linea en la parte inferior de nuestro documento javascript.

window.addEventListener(“load”,siteLedsCheckPage,false);

Esto agrega un nuevo manejador de eventos para la ventana load event, significando que nuestra función siteLedsCheckPage será llamada después de que la ventan principal de Firefox es abierta e inicializada por primera vez.

Las funciones en javascript y las variables globales que hemos definido son evaluadas en nombres de espacio globales con el otro código de javascript del Firefox. esto significa que is en una de nuestras funciones o variables tiene el mismo nombre que un identificador existente, tendremos una colisión de nombres. para evitar esta situación, siempre debemos crear una cadena única (en nuestro caso “siteLeds”) y usarla como un prefijo para todos nuestros identificadores globales. la siguiente sección describe otra técnica para evitar tales conflictos:

el archivo final siteledsOverlay.js quedaria así:

var gSiteLedsLastRequest = null;
var gSiteLedsLastContent = null;
function siteLedsCheckPage() {
var pageURL = ‘http://www.iosart.com/Firefox/siteleds/index.html’;
gSiteLedsLastRequest = new XMLHttpRequest();
gSiteLedsLastRequest.onload = siteLedsPageLoaded;
gSiteLedsLastRequest.onerror = siteLedsPageError;
gSiteLedsLastRequest.open(‘GET’, pageURL);
gSiteLedsLastRequest.send(null);
}
function siteLedsPageError() {
var ledElement = document.getElementById(‘siteleds-statusbar-panel’);
ledElement.setAttribute(‘sitestate’, ‘error’);
setTimeout(siteLedsCheckPage, 900000);
}

function siteLedsPageLoaded() {
var ledElement = document.getElementById(‘siteleds-statusbar-panel’);
if (gSiteLedsLastRequest.status == 200) {
var prevContent = gSiteLedsLastContent;
gSiteLedsLastContent = gSiteLedsLastRequest.responseText;
if ((prevContent != null) && (prevContent != gSiteLedsLastContent)) {
ledElement.setAttribute(‘sitestate’, ‘modified’);
} else {
ledElement.setAttribute(‘sitestate’, ‘ok’);
setTimeout(siteLedsCheckPage, 900000);
}
} else {
ledElement.setAttribute(‘sitestate’, ‘error’);
setTimeout(siteLedsCheckPage, 900000);
}
}
window.addEventListener(“load”, siteLedsCheckPage, false);

Haciendo nuestra extensión localizable

como se menciono en el capitulo anterior, los documentos XUL no deberían contener cadenas literales que sean presentadas al usuario. en vez de eso, se debería definir todas estas cadenas en un archivo separado y hacer  en el archivo XUL referencia a ellas. esto permite a las extensiones ser fácilmente traducidas a diferentes lenguajes. todo lo que necesitamos es proveer un archivo adicional con las cadenas traducidas.

actualmente nuestros elementos XUL se ven así:

<statusbarpanel class=”statusbarpanel-iconic”
id=”siteleds-statusbar-panel”/>
tooltiptext=”SiteLeds Status Icon”
sitestate=”unknown”
insertbefore=”statusbar-display”/>

como se puede ver, la cadena “SiteLeds Status Icon” esta en ingles. si deseamos traducir nuestra extensión a un lenguaje diferente, necesitaremos modificar el archivo XUL y proveer do versiones diferentes de nuestra extension. y si la extensión es traducida a una docena de lenguajes???

afortunadamente, hay una mejor forma. primero definiremos todas las cadenas en separado en un archivo DTD. los archivos DTD son usualmente usados para definir la estructuras de los elementos de XML, pero ellos también pueden contener entities (entidades), la cuales son variable de XML que definen cadenas comunes para permitir reusarlas. definamos nuestra cadena como una entidad de XML en el archivo siteledOverlay.dtd:

<!ENTITY siteLeds.tooltip “SiteLeds Status Icon”>

por tanto debemos cambiar nuestro elemento de XML así:

statusbarpanel class=”statusbarpanel-iconic”
id=”siteleds-statusbar-panel”/>
tooltiptext=”&siteLeds.tooltip;”
sitestate=”unknown”
insertbefore=”statusbar-display”/>

se ha reemplazado la cadena literal “SiteLeds Status Icon” con una referencia a la entidad de XML “&siteLeds.tooltip;”.

El archivo final XUL

hemos creado las hojas de estilo CSS , las funciones necesitadas en javascript, y la tabla de cadenas en el archivo DTD. como podemos especificar a nuestro archivo XUL que debería usar esos archivos?? miremos la version final de nuestro documento siteledsOverlay.xul:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://siteleds/skin/siteledsOverlay.css"
type="text/css"?>
<!DOCTYPE overlay SYSTEM “chrome://siteleds/locale/siteledsOverlay.dtd">
<overlay id="siteleds-overlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript"
src="chrome://siteleds/content/siteledsOverlay.js"/>
<statusbar id="status-bar">
<statusbarpanel class="statusbarpanel-iconic"
id="siteleds-statusbar-panel"
tooltiptext="&siteLeds.tooltip;"
sitestate="unknown"
insertbefore="statusbar-display"/>
</statusbar>
</overlay>

Una explicación de lo que ha sido agregado:

1.la instrucción de XML xml-stylesheet asocia la hoja de estilos siteledsOverlay.css con nuestro documento XUL. por favor dese cuenta que se están usando un URL chrome, esto significa que el paquete de la extensión necesitas estar apropiadamente instalado y registrado antes de poder probar nuestra extensión. esto se hará en las siguientes secciones.
2.la declaración DOCTYPE asocia un archivo externo DTD llamado siteledsOverlay.dtd con nuestro documento XUL.
3.el elemento script especifica que el documento debería e importar el archivo de javascript siteledsOverlay.js.

Empaquetando la Extension

Esta sección explica donde poner los archivos creados en las secciones previas y como deberían ser empaquetados para crear una extensión estable.

Hay que agregar unos archivos mas a los creados, entre los que se encuentra el chrome.manifest y varios archivos de configuración para el correcto registro de nuestra extensión en el registro chrome.

Estructura de los directorio de la extension

en la sección “introduction to chrome”, se vio que un paquete chrome tiene tres partes lógicas: content, skin, and locale. durante el proceso de desarrollo. durante el proceso de desarrollo, la estructura del directorio físico de nuestra extensión seguirá este modelo. el directorio en la parte mas alta en la extensión tendrá el archivo del manifiesto de instalación llamado install.rdf y un directorio llamado chrome. el directorio chrome contendrá los siguientes tres subdirectorios:

content: contiene los documentos XUL y  los archivos de javascript.
skin: contiene una o mas conjunto de skins, cara una separada en un subdirectorio. una skin es cualquier número de archivos de estilos de hojas de CSS e imágenes. nuestra extensión tiene solo una skin localizada en el directorio classic.
locale: contiene uno o mas conjunto de localizaciones, cada una contiene una traducción diferente de la interfaz de usuario y están localizadas cada una en un subdirectorio por separado. la tabla de cadenas esta localizada en archivos DTD (para cadenas localizadas en documentos XML) y archivos de características (property) (para cadenas usadas in programas de javascript). nuestra extensión inicialmente contendrá cadenas en ingles localizadas en un subdirectorio llamado en-US.

por tanto la estructura de los directorio quedara así:

siteleds/
          install.rdf
          chrome.manifest
           chrome/
                      content/
                      siteledsOverlay.js
                      siteledsOverlay.xul
                      locale/
                                 en-US/
                                 siteledsOverlay.dtd
                      skin/
                                 classic/
                                  siteledsOverlay.css
                                  state-error.png
                                  state-ok.png
                                  state-modified.png
                                  state-unknown.png

la estructura mostrada es solo una recomendación, puedes poner la jerarquía de los directorios como quieras, como te darás cuenta en las siguientes secciones, el mecanismo de la extensiones no asume nada acerca de la localización de tu directorios chrome. puedes cambiar las localizaciones, nombre siempre y cuando se hagan los ajustes correspondientes al archivo del manifiesto.

Si empaquetamos simplemente juntos todos los archivos que hemos creado, Firefox no tendrá idea de como registrarlos en el registro chrome. nosotros necesitamos proveer archivos adicionales llamados manifiesto de chrome (chorme manifests) que describen los contenidos del paquete. hay dos estilos de manifiesto de (chrome manifest). El  estilo viejo, usado en versiones previas a la 1.1, consta de archivos RDF llamados contents.rdf. El estilo nuevo creado para versiones posteriores al Firefox 1.1 simplifica el proceso requiriendo la creación de un simple archivo de texto plano llamado chrome.manifest.

Solo tomare en cuenta el nuevo estilo por sus ventajas y por pereza.

Creando el archivo chrome manifest con el nuevo estilo

Este estilo empezó a ser usado desde el Firefox 1.1, es mucho mas simple el mecanismo del “chrome manifes”.  toda la información necesitada para describir el chrome contenida en el paquete de una extensión es especificar un un simple texto plano llamado chrome.manifest y ubicarlo en la raíz del árbol de directorios de la extension. cuando usamos el nuevo manifest, no necesitaras crear los archivos contents.rdf o especificar la propiedad em:file en el install.rdf manifest.

el archivo de SiteLeds chrome.manifest contiene solo cuatro lineas:

     content siteleds jar:chrome/siteleds.jar!/content/
     locale siteleds en-US jar:chrome/siteleds.jar!/locale/en-US/
     skin siteleds classic/1.0 jar:chrome/siteleds.jar!/skin/classic/
     overlay chrome://browser/content/browser.xul
     chrome://siteleds/content/siteledsOverlay.xul

la estructura del archivo es muy simple y directa:

paquete de contenido:
content  <nombre del paquete>  <ruta a los archivos>
paquete locale:
locale  <nombre del paquete>  <ruta a los archivos>
paquete skin:
locale  <nombre del paquete>  <ruta a los archivos>
XUL de recubrimiento:
overlay  <chrome:// archivo a recubrir> <chrome:// archivo de recubrimiento>

Creando el install manifest
el install manifest es un archivo que contiene información general acerca de la extensión – su nombre, autor, version, que Firefox es compatible con ella, y similares. este archivo es llamado install.rdf, y esta localizado en el directorio raíz del árbol de la extension.

el siguiente codigo muestra el archivo el archivo de instalaciónde SiteLedsinstall.rdf:

<?xml version=”1.0”?>
<RDF xmlns=”http://www.w3.org/1999/02/22-rdf-syntax-ns#”
   xmlns:em=”http://www.mozilla.org/2004/em-rdf#”>
<Description about=”urn:mozilla:install-manifest”>
   <em:id>{E1B2492D-E6AC-4221-A433-C143E3A1C71E}</em:id>
   <em:version>0.1</em:version>
   <em:name>SiteLeds</em:name>
   <em:description>Site Status Monitor</em:description>
   <em:creator>Alex Sirota</em:creator>
   <em:homepageURL>http://www.iosart.com/Firefox/siteleds</em:homepageURL>
   <em:targetApplication>
<Description>
   <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
   <em:minVersion>1.1</em:minVersion>
   <em:maxVersion>2.0.0.1</em:maxVersion>
</Description>
</em:targetApplication>
<em:file>
<Description about=”urn:mozilla:extension:file:siteleds.jar”>
   <em:package>content/</em:package>
   <em:skin>skin/classic/</em:skin>
   <em:locale>locale/en-US/</em:locale>
</Description>
</em:file>
</Description>
</RDF>

ahora demosle una mirada a algunas partes de este archivo:

la propiedad em:id que especifica el GUID (Global Unique Identifier). el GUID es un numero de 128 bits que identifica de manera única a una extension. deberías generar un numero para cada extensión que crees. hay muchas utilidades para crear el GUID en Unix hay una llamada uuidgen. si tienen un cliente IRC instalado, se puede generar un GUID visitando el canal #botbot en el servidor irc.mozilla.org y escribiendo botbot uuid:
<em:id>{E1B2492D-E6AC-4221-A433-C143E3A1C71E}</em:id>

la propiedad em:versionespecifica la version de la extension. la version debería esta en el FVF (Firefox Version Format): major.minor.reseales.buid
  • .

<em:version>0.1</em:version>

el em:name especifica el nombre de la extensión que sera mostrado en la interfaz de usuario.

    <em:name>SiteLeds</em:name>

la propiedades em:description, em:creator, y em:homepageURL son opcionales y especifican la descripción de la extension, su autor, y pagina correspondiente. esta información será desplegada en el dialogo del Manejador de Extensiones después de que la extensión sea instalada:

     <em:description>Site Status Monitor</em:description>
     <em:creator>Alex Sirota</em:creator>
     <em:homepageURL>http://www.iosart.com/Firefox/siteleds</em:homepageURL>

la propiedad em:targetApplication especifica el rango de las versiones del Firefox para la cual la extensión es compatible

    <em:targetApplication>
        <Description>
   <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
   <em:minVersion>1.1</em:minVersion>
   <em:maxVersion>2.0.0.1</em:maxVersion>
        </Description>
    </em:targetApplication>

la propiedad em:file especifica el archivo jar que contiene los archivos chrome de la extensión y parias partes del paquete chrome (content/skin/locale). por ejemplo, los archivos chrome del SiteLeds están empaquetados dentro del archivo siteleds.jar, el cual contiene los subdirectorios skin/classic, y locate/en-Us.

<em:file>
<Description about=”urn:mozilla:extension:file:siteleds.jar”>
   <em:package>content/</em:package>
   <em:skin>skin/classic/</em:skin>
   <em:locale>locale/en-US/</em:locale>
</Description>
</em:file>

Nota: esta ultima propiedad em:file no es necesitada cuando se usa el nuevo estilo de text plano chrome.


Creando el paquete de instalación de la extensión

Después de crear el archivo chrome compreso (.zip) y el archivo de instalación install.rdf manifes, se puede finalmente crear el paquete de la extensión que es instalado por el Firefox. este paquete tiene una extensión XPI, pero como el archivo chrome JAR, es un archivo ZIP tradicional.
crea un archivo ZIP que contenga el archivo install.rdf y el directorio chrome así cono su raíz, y dale una extensión XPI. el subdirectorio chrome contiene un archivo JAR. si esta usando el nuevo estilo chrome manifest, debería haber también un archivo chrome.manifest en el nivel mas alto del archivo XPI.

preferiblemente, dale un nombre con significado al archivo XPI, el cual incluya nombre, extensión y su version. el árbol quedaría algo como




SiteLeds_0.1xpi
   install.rdf
   chrome.manifest
   chrome/
      siteleds.jar

en resumen si tiene todos los archivos listos para empaquetar la extensión siga estos pasos:

1.cree un directorio con el nombre de la extensión en algún lugar del disco duro
2.copie el archivo install.rdf en ese directorio
3.si esta usando en nuevo estilo de chrome manifest, copie el archivo chrome.manifest en ese directorio.
4.cree un subdirectorio llamado chrome el directorio inicialmente construido.
5.copie el archivo siteleds.jar dentro del directorio chrome creado en el paso anterior
6.comprima cl contenido del directorio que tiene el nombre del paquete con el nombre SiteLeds_0.1xpi.

finalmente la extensión esta lista para ser instalada en nuestro Firefox.

el código organizado y la extensión final pueden ser obtenidos en la pagina del coautor:

http://www.iosart.com/firefox/siteleds/main.html

pero se debe tener en cuenta que toca modificar el install.rdf ya que según este, el siteleds solo es compatible con versiones nuevas del Firefox (mira cuales), modifícalo para poder probarlo. En la extensión presentada allí se utiliza el archivo chrome.manifest con el viejo estilo, con el código presente usted mismo puede empaquetar los archivos para que la extensión utilice el nuevo estilo. Los archivos tienen la estructura de la página 17 usted puede poner el siguiente codigo en un archivo llamado empaquetar, darle permisos de ejecución y proceder o obtendrá el .xpi

rm *~
cd chrome
rm *~
rm content/*~
rm locale/en-US/*~
rm skin/classic/*~
zip -r siteleds.jar *
mv siteleds.jar ..
rm -r *
mv ../siteleds.jar .
cd ..
rm *~
rm empaquetar
zip -r extension.xpi *
mv extension.xpi ..

Probando y depurando extensiones

como con cualquier otro programa, existe la posibilidad de que inicialmente entrara en problemas con algunas extensiones. cosas como trabajar de forma diferente a como se esperaba o no trabajar. hay muchos mecanismos que se pueden usar para localizar averías en la extensión y ayudar a encontrar y solucionar esos molestos errores.

algunos errores en la extension, empaquetamiento, o su registro chrome podrían dañar el navegador y hacerlo parcialmente o completamente inusable. usted puede solamente solucionar esos problema ejecutando el Firefox en modo seguro (usando el parámetro -safe-come en la linea de comando por ejemplo) y desinstalando la extension, o creando un nuevo perfil de usuario.

Configuración de preferencias

muchas configuraciones en las preferencias pueden ayudarte con el proceso de depuración:

javascript.options.showInConsole: poner esta preferencia en true indica al Firefox para mostrar errores que originar los archivos chrome en la consola de javascript. por ejemplo, una función de javascript podría estar silenciosamente fallando dentro de tu extension, y , sin ver el mensaje de error, podría ser muy difícil darle al problema.
javascript.options.strict: cuando esta preferencia es puesta en true, Firefox muestra las advertencias de javascript en la consola de javascript. una advertencia usualmente significa que estas haciendo algo ilegal o no estándar en yo código, y que esto podría causar comportamientos inesperados u otros problemas. habilitando esta preferencia que todas las advertencias, no solo las originadas por tu extension, sean reportadas en consola de javascript.
browser.dom.window.dump.enabled: deberías poner esta preferencia en true si deseas usar la funcióndump() para imprimir mensajes a la consola estándar. mas información aparecerá después en este mismo capitulo.
como con la configuración de otras preferencias, puedes copiar about:config en la barra de dirección del Firefox y usar la ventana de preferencias para crear nuevas preferencias y modificar existentes. otros  métodos para configurar las preferencias, tales como modificar el archivo prefs.js también funcionan.

Logging

Logging es un simple pero muy eficiente método para depurar tu código. imprimiendo los valores de tus variables, los mensajes recibidos, códigos de retorno, y así puede ayudar a date una idea de donde se encuentra el problema y como solucionarlo. Logging puede también ser usado para reportar eventos mayores y errores en tu aplicación, y mirando esos mensajes puede ayudarte a estar seguro que la aplicación esta actualmente haciendo lo que esperas.

hay varios mecanismos para el registro en Mozilla:

consola estándar: puedes usar la función dump() para imprimir mensajes a la consola estándar. similar a la función alert(), dump() espera una simple cadena de texto como argumento. por defecto, la consola estándar viene deshabilitada en el Firefox. para habilitarla, por el valor de la preferencia browser.dom.window.dump.enabled a true y comienza el Firefox en la linea de comandos con la bandera -console.
consola de javascript: esta consola puede ser abierta usando Herramientas-> Consola de javascript. para imprimir una linea en esta consola, primero debes obtener la interfz nsIConsoleService y llamar a su método logStringMessage:

var consoleService = Components.classes[‘@mozilla.org/consoleservice;1’]
   .getService(Components.interfaces.nsIConsoleService);
      consoleService.logStringMessage(“Testing 1 2 3”);

para evitar alboroto puedes crear tu propia envoltura para la función que determine si el mensaje de depurado debería ser mostrado:

function myPrintDebugMessage(message) {
if (gMyDebugging) {
dump(message);
}
}

si usas la función anterior para imprimir todos tus mensaje de depurado, al acciona el valor de la bandera global gMyDebuggin pone todos los mensajes on y off.

Extensiones para desarrolladores

DOM Inspector
Venkman es un avanzado depurador de javascript baso en el de Mozilla
Extension developer's extension puede se usado rápidamente para correr javascript code snippets, editar XUL, HTML, y mucho mas.
ColorZilla puede ser usado para obtener rápidamente varias piezas de información acerca de elementos XUL, incluyendo sus colores, ids, nombres de clases, y mucho mas. también puede usar ColorZilla para lanzar rápidamente el DOM Inspector en el elementos seleccionado.

TÉCNICAS DE PROGRAMACIÓN DE EXTENSIONES

en secciones previas se ha visto como puede crear una simple extension. este sección le introducirá en técnicas adicionales que pueden ser útil para crear extensiones mas elaboradas.

Entendiendo el Browser chrome

has visto que para extender una interfaz de usuario XUL usted necesita conocer su estructura: los elementos que quiere superponer, su jerarquía, ids, y demás. si usted desea extender en navegador, es importante tener un entendimiento básico del browser chrome: sus XUL de las ventanas y dialogo, hojas de estilo y código de javascript. hay varias manera de aprender acerca de esos componentes:

el DOM Inspector puede ayudarte a navegar a través de la jerarquía del documento y examinar los elementos de la interfaz de usuario, sus propiedades y estilos.
puedes aprender mucho mirando el código del navegador; así como tu extension, el navegador esta compuesto de archivos XUL, CSS, y javascript que puede examinar.
la Web ofrece un montón de información valiosa, incluyendo documentación, referencias, y demás. mira la sección “recursos en linea”, mas adelante en este capitulo, para algunos enlaces de interés.
finalmente puede utilizar los foros de discusión y el IRC para pedir ayuda a tu comunidad de miembros.


Recursos en linea

http://www.xulplanet.com/
http://www.mozilla.org/docs/
http://kb.mozillazine.org
http://forums.mozillazine.org/
http://www.mozilla.org/community/developer-forums.html
Mozilla.org IRC server.

Por: vacio


« Última modificación: 27 Marzo 2007, 19:24 pm por vacio » En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Que extensiones de Firefox utilizáis para una navegación segura?
Seguridad
chocola 3 3,313 Último mensaje 29 Enero 2012, 14:23 pm
por ‭lipman
Alternativas de extensiones para Firefox 57 / WebExtensions ???
Foro Libre
Eleкtro 5 6,078 Último mensaje 1 Julio 2018, 11:17 am
por Songoku
Firefox 59 incluirá extensiones para descentralizar la web
Noticias
wolfbcn 0 1,392 Último mensaje 30 Enero 2018, 21:02 pm
por wolfbcn
Introduccion a la creacion de GUI en c++
Programación C/C++
Kenji-chan 0 2,610 Último mensaje 25 Junio 2018, 01:05 am
por Kenji-chan
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines