|

FireMarker: cómo crear una extensión para Firefox

firemarker.pngSi el otro día os hablaba de FireMarker, la extensión de Firefox para marcar texto en una página, hoy voy a intentar explicar cómo la desarrollé y así conseguir que otras personas no se encuentren con las mismas dificultades que yo.

Vamos a ir paso a paso, explicando la estructura, los distintos ficheros y sus contenidos, siempre dentro de mi limitado conocimiento, ya que lo que he aprendido ha sido destripando otras extensiones y mirando la documentación que hay sobre XUL.

Estructura de directorios

Lo primero es mostrar la estructura de directorios y los ficheros que se encuentran en estos directorios:

firemarker4.png

  • raíz: contiene ficheros de instalación y de configuración del contenido y el resto de directorios.
  • chrome: contiene toda la información de la extensión organizada en subdirectorios.
  • firemarker: congrega contenido y estética.
  • content: información sobre el contenido de la extensión.
  • firemarker (dentro de content): contenido de la extensión.
  • locale: información para el multilingüismo de la extensión.
  • en-US: para cuando el navegador es la versión en inglés de Estados Unidos, creo que si el navegador es de una versión de idioma diferente, al estar indicada en el fichero de configuración en primer término, es la que se coge por defecto.
  • es-ES: para cuando el navegador es la versión en español de España. Creo que también es la usada para otras versiones de navegadores en español (es-AR, …).
  • skin: contiene la información necesaria para la estética de la página.
  • classic: el theme de firefox por defecto, si se quiere modificar para otro theme se debería crear una estructura paralela a esta.
  • firemarker (dentro de classic): información para esta extensión.

Ficheros

Dentro de una extensión de Firefox hay una serie de ficheros que son necesarios y otros que son creados por el desarrollador. Según la versión de Firefox, estos ficheros sufren distintas modificaciones. Lo mejor para crearte tu propia extensión es descomprimir una extensión ya creada y modificar estos ficheros según tus necesidades.

Directorio raíz

  • chrome.manifest: se especifica los distintos contenidos de la extensión: overlay (interfaces de usuario que se añaden a Firefox), content (contenido), skin y locale (ficheros para la internacionalización).
overlay	chrome://browser/content/browser.xul	chrome://firemarker/content/firemarkerOverlay.xul
overlay	chrome://navigator/content/navigator.xul	chrome://firemarker/content/firemarkerOverlay.xul
content	firemarker	chrome/firemarker/content/firemarker/
skin	firemarker	classic/1.0	chrome/firemarker/skin/classic/firemarker/
locale	firemarker	en-US	chrome/firemarker/content/locale/en-US/
locale	firemarker	es-ES	chrome/firemarker/content/locale/es-ES/
  • install.rdf: xml (RDF) que contiene la información necesaria para la instalación de la extensión, en este caso si que copié directamente de otra extensión y lo modifiqué según mis necesidades. El em:id indentifica a la extensión y debe ser un código UUID único, para generarlo puedes usar esta aplicación.
<?xml version="1.0"?>
<RDF:RDF xmlns:em="http://www.mozilla.org/2004/em-rdf#"
xmlns:NC="http://home.netscape.com/NC-rdf#"
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<RDF:Description RDF:about="rdf:#$F5NsG1"
em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
em:minVersion="0.9"
em:maxVersion="2.*" />
<RDF:Description RDF:about="urn:mozilla:extension:file:firemarker.jar"
em:package="content/firemarker/"
em:skin="skin/classic/firemarker/">
<em:locale>locale/en-US/</em:locale>
<em:locale>locale/es-ES/</em:locale>
</RDF:Description>
<RDF:Description RDF:about="urn:mozilla:install-manifest"
em:id="{E639146C-1D29-4182-833F-C65B044CAF07}"
em:name="firemarker"
em:version="0.1"
em:creator="Luis Sacristán Pascual"
em:description="Marks text in the page."
em:homepageURL="http://sentidoweb.com"
em:updateURL="..."
em:iconURL="chrome://firemarker/skin/icono_32x32.png"
em:aboutURL="chrome://firemarker/content/acercade.xul">
<em:targetApplication RDF:resource="rdf:#$F5NsG1"/>
<em:file RDF:resource="urn:mozilla:extension:file:firemarker.jar"/>
</RDF:Description>
</RDF:RDF>

en-US

Sirve igual para es-ES o cualquier otro idioma. Hay un fichero de configuración de contenido (contents.rdf) y otro que es una DTD que luego se usará para las traducciones (firemarker.dtd).

  • contents.rdf: contenido del directorio, hacer copy/paste y modificar de otra extensión.
  • firemarker.dtd: DTD con las traducciones, a las que se podrá acceder desde los ficheros XUL:
<!ENTITY SW_FM_ACERCADE.acerca.de "About" >
<!ENTITY SW_FM_ACERCADE.autor "Author" >
<!ENTITY SW_FM_ACERCADE.pagina.de.inicio "Home page" >
<!ENTITY SW_FM_OPCIONES.borrar.selecciones "Clean selections" >
<!ENTITY SW_FM_OPCIONES.borrar.selecciones.pagina "Clean page selections" >
<!ENTITY SW_FM_OPCIONES.copiar.selecciones.pagina "Copy page selected text" >
<!ENTITY SW_FM_OPCIONES.color.letra "Text color" >
<!ENTITY SW_FM_OPCIONES.color.fondo "Background color" >

firemarker (dentro de classic)

En este directorio se guardan las imágenes que vayamos a usar, como por ejemplo iconos y los ficheros de estilos, todo configurado por el fichero contents.rdf correspondiente.

firemarker (dentro de content)

Contiene los scripts y los layouts de la extensión, en nuestro caso tenemos tres archivos (sin incluir el contents.rdf):

  • acercade.xul: muestra la ventana de información de “Acerca de…”.
  • firemarkerOverlay.xul: muestra el menú contextual de la extensión cuando se pulsa con el botón derecho del ratón en el icono y el propio icono en la barra de estado.
  • firemarkerOverlay.js: scripts necesarios para la ejecución de la extensión.

El único fichero que vamos a comentar, que es el que más dificultad puede tener es firemarkerOverlay.js ya que es el que se encarga de toda la funcionalidad de la extensión. El script contiene un objeto JSON que tiene toda la funcionalidad.

Cuando se selecciona un texto podemos obtener tres cosas, el texto seleccionado, el nodo origen y el nodo fin desde los que hemos realizado la selección y los desplazamientos de los textos donde empiezan los textos de los nodos seleccionados. Veamos un ejemplo para comprenderlo mejor:

Tenemos el siguiente código HTML:

<h1>Cabecera</h1>
<p>Texto</p>
<div>Footer</div>

Si seleccionamos de izquierda a derecha el siguiente texto: “era Texto Foo“, obtenemos los siguientes datos:

  • Texto seleccionado: era Texto Foo
  • Nodo inicial: h1
  • Nodo final: div
  • Offset inicial: 6 (el texto seleccionado empieza en la 6 posición)
  • Offset final: 3 (el texto seleccionado acaba en la 3 posición)

Si la selección se realiza de derecha a izquierda los datos que obtengo son distintos:

  • Texto seleccionado: era Texto Foo
  • Nodo inicial: div
  • Nodo final: h1
  • Offset inicial: 6 (el texto seleccionado empieza en la 6 posición)
  • Offset final: 3 (el texto seleccionado acaba en la 3 posición)

En este instante se puede acceder directamente a los nodos, pero como se tiene que localizar los nodos (inicial y final) cuando se recarga la página, y no tenemos un puntero al nodo, lo que hago es obtener el texto que contiene el nodo y buscarlo en todo el documento, así puedo guardar los textos de los nodos en las propiedades del Firefox, para poder acceder a los nodos siempre que quiero.

Lo que debemos hacer en este instante es modificar los objetos HTML para añadirles un SPAN que tiene el estilo de marcado.

El resto del código creo que se puede entender con los comentarios:

window.addEventListener(
"load",
function () {
gBrowser.addEventListener("load", __SW_FIREMARKER_FIREFOX__.marcarPagina, true);
},
false
);
var __SW_FIREMARKER_FIREFOX__ = {
"nodoIni" : null, // El nodo inicial desde el que se empieza la selección de texto
"nodoFin" : null, // El nodo final de la selección de texto
"offsetIni" : 0,  // Dónde empieza la selección del texto en el nodo inicial
"offsetFin" : 0,  // Dónde acaba la selección del texto
"lista_textos" : null,  // Un array con todos los textos seleccionados ordenados por página
"lista_offsets" : null, // Un array con las posiciones inicio-fin de los textos seleccionados ordenados por página
"lista_nodos" : null,   // Un array con los textos de los nodos inicio-fin de los textos seleccionados ordenados por página
"selectedText" : "",    // El texto seleccionado actualmente
"colorfondo" : null,    // El color de fondo que se usa para marcar el texto
"colorletra" : null,    // El color de letra que se usa para marcar el texto
// Muestra la ventana Acerca de...
"mostrarAcercaDe" : function() {
window.open('chrome://firemarker/content/acercade.xul','','chrome,centerscreen');
},
// Carga las preferencias guardadas como un texto formateado en los distintos arrays
"cargarPrefs" : function() {
/*
* Estructura
*   {{*}}URL1{{**}}offsetIni{{,}}offsetFin{{,}}Texto1{{**}}offsetIni{{,}}offsetFin{{,}}Texto2{{**}}...
*            {{**}}offsetIni{{,}}offsetFin{{,}}TextoN
*   {{*}}URL2{{**}}offsetIni{{,}}offsetFin{{,}}Texto1{{**}}....
*/
try {
// Se inicializa y recupera las preferencias
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
var Branch = prefs.getBranch("extensions.swfiremarker.");
// Se recupera la lista codificada
var lista_codificada;
try {
lista_codificada = Branch.getCharPref("sw_listatextos");
} catch (e) {
Branch.setCharPref("sw_listatextos", "");
lista_codificada = "";
}
// Se inicializan los arrays de datos
__SW_FIREMARKER_FIREFOX__.lista_textos = new Array();
__SW_FIREMARKER_FIREFOX__.lista_offsets = new Array();
__SW_FIREMARKER_FIREFOX__.lista_nodos = new Array();
// Se guardan los datos recuperados en los arrays
if (lista_codificada != "") {
// Se divide la lista codificada en URLs
var lista_aux = lista_codificada.split("{{*}}");
for (var i=0; i<lista_aux.length; i++) {
// Cada URL se divide en textos seleccionados
var elems = lista_aux[i].split("{{**}}");
__SW_FIREMARKER_FIREFOX__.lista_textos[elems[0]] = new Array();
__SW_FIREMARKER_FIREFOX__.lista_offsets[elems[0]] = new Array();
__SW_FIREMARKER_FIREFOX__.lista_nodos[elems[0]] = new Array();
for (var j=1; j<elems.length; j++) {
// Se obtienen los distintos arrays
var partes = elems[j].split('{{,}}');
if (partes.length == 5) {
__SW_FIREMARKER_FIREFOX__.lista_offsets[elems[0]][j-1] = new Array(partes[0], partes[1]);
__SW_FIREMARKER_FIREFOX__.lista_nodos[elems[0]][j-1] = new Array(partes[2], partes[3]);
__SW_FIREMARKER_FIREFOX__.lista_textos[elems[0]][j-1] = partes[4];
}
}
}
}
// Se cargan los colores (letra y fondo)
__SW_FIREMARKER_FIREFOX__.colorfondo = Branch.getCharPref("sw_colorfondo");
__SW_FIREMARKER_FIREFOX__.colorletra = Branch.getCharPref("sw_colorletra");
} catch (e) {/*alert('Problems getting preferences...'+e);*/}
},
// Marca el texto seleccionado
"marcar" : function(evt) {
// Se recupera el texto seleccionado
var sel = content.getSelection();
// Si se ha seleccionado texto
if (sel.anchorNode) {
// Guardo los datos de los nodos y los offsets y el texto
__SW_FIREMARKER_FIREFOX__.nodoIni = sel.anchorNode.nodeValue;
__SW_FIREMARKER_FIREFOX__.nodoFin = sel.focusNode.nodeValue;
__SW_FIREMARKER_FIREFOX__.offsetIni = sel.anchorOffset;
__SW_FIREMARKER_FIREFOX__.offsetFin = sel.focusOffset;
__SW_FIREMARKER_FIREFOX__.selectedText = sel.toString();
// Resalto el texto
__SW_FIREMARKER_FIREFOX__.resaltarNodos(sel.anchorNode.ownerDocument.body, {"encontrado" : false, "fin" : false}, 1);
// Guardo las preferencias con el nuevo texto seleccionado
__SW_FIREMARKER_FIREFOX__.setPref(__SW_FIREMARKER_FIREFOX__.selectedText);
}
},
// Marca una pagina con la información anterior almacenada
"marcarPagina" : function(evt) {
if (evt.originalTarget instanceof HTMLDocument) {
// Página actual
var doc = evt.originalTarget;
// Recupero las listas anteriores si no se ha recuperado ya
if (!__SW_FIREMARKER_FIREFOX__.lista_textos || __SW_FIREMARKER_FIREFOX__.lista_textos.lenght == 0) {
__SW_FIREMARKER_FIREFOX__.cargarPrefs();
}
// Si hay texto para la página actual lo muestro
if (__SW_FIREMARKER_FIREFOX__.lista_textos &&
__SW_FIREMARKER_FIREFOX__.lista_textos[doc.location] &&
__SW_FIREMARKER_FIREFOX__.lista_textos[doc.location] != "" ) {
var textos = __SW_FIREMARKER_FIREFOX__.lista_textos[doc.location];
// Muestro cada uno de los textos
for (var i=0; i<textos.length; i++) {
__SW_FIREMARKER_FIREFOX__.offsetIni = __SW_FIREMARKER_FIREFOX__.lista_offsets[doc.location][i][0];
__SW_FIREMARKER_FIREFOX__.offsetFin = __SW_FIREMARKER_FIREFOX__.lista_offsets[doc.location][i][1];
__SW_FIREMARKER_FIREFOX__.nodoIni = __SW_FIREMARKER_FIREFOX__.lista_nodos[doc.location][i][0];
__SW_FIREMARKER_FIREFOX__.nodoFin = __SW_FIREMARKER_FIREFOX__.lista_nodos[doc.location][i][1];
__SW_FIREMARKER_FIREFOX__.selectedText = textos[i];
__SW_FIREMARKER_FIREFOX__.resaltarNodos(doc.body, {"encontrado" : false, "fin" : false}, 1);
}
}
}
},
// Busca los nodos implicados y los resalta
"resaltarNodos" : function(nodo, flags, n) {
if (!flags.fin) {
// Si no se ha encontrado, primero se busca
if (!flags.encontrado) {
if (nodo.nodeType == 3) { // text node
if (nodo.nodeValue == __SW_FIREMARKER_FIREFOX__.nodoIni) {
flags.encontrado = true;
} else if (nodo.nodeValue == __SW_FIREMARKER_FIREFOX__.nodoFin) {
flags.encontrado = true;
// intercambiamos el primero y el ultimo porque se selecciono al revés
var _aux = __SW_FIREMARKER_FIREFOX__.nodoFin;
__SW_FIREMARKER_FIREFOX__.nodoFin = __SW_FIREMARKER_FIREFOX__.nodoIni;
__SW_FIREMARKER_FIREFOX__.nodoIni = _aux;
_aux = __SW_FIREMARKER_FIREFOX__.offsetFin;
__SW_FIREMARKER_FIREFOX__.offsetFin = __SW_FIREMARKER_FIREFOX__.offsetIni;
__SW_FIREMARKER_FIREFOX__.offsetIni = _aux;
}
// Si se ha encontrado y es un único nodo, ordeno los offsets de menor a mayor, por si el texto que se ha seleccionado se ha realizado de derecha a izquierda
if (flags.encontrado && __SW_FIREMARKER_FIREFOX__.nodoIni == __SW_FIREMARKER_FIREFOX__.nodoFin &&
__SW_FIREMARKER_FIREFOX__.offsetFin < __SW_FIREMARKER_FIREFOX__.offsetIni) {
_aux = __SW_FIREMARKER_FIREFOX__.offsetFin;
__SW_FIREMARKER_FIREFOX__.offsetFin = __SW_FIREMARKER_FIREFOX__.offsetIni;
__SW_FIREMARKER_FIREFOX__.offsetIni = _aux;
}
}
}
// Si he encontrado anteriormente el nodo inicial, voy resaltando los nodos en los que me encuentro
if (flags.encontrado) {
if (nodo.nodeType == 3) { // text node
var ini = (nodo.nodeValue == __SW_FIREMARKER_FIREFOX__.nodoIni)? __SW_FIREMARKER_FIREFOX__.offsetIni : 0;
var fin = (nodo.nodeValue == __SW_FIREMARKER_FIREFOX__.nodoFin)? __SW_FIREMARKER_FIREFOX__.offsetFin : nodo.nodeValue.length;
__SW_FIREMARKER_FIREFOX__.resaltar(nodo, ini, fin);
}
}
// Si es un nodo elemento, busco/resalto en los nodos hijos
if (nodo.nodeType == 1) { // Es element node
var hijos = new Array();
for (var i=0; i<nodo.childNodes.length; i++) {
hijos[i] = nodo.childNodes[i];
}
for (var i=0; i<hijos.length; i++) {
if (hijos[i]) { // Algunos hijos me dan como undefined ??!!
flags = __SW_FIREMARKER_FIREFOX__.resaltarNodos(hijos[i], flags, n+1);
}
}
}
// Si es el nodo fin, paro la marcación de texto
if (flags.encontrado) {
if (nodo.nodeValue == __SW_FIREMARKER_FIREFOX__.nodoFin) {
flags.fin = true;
}
}
}
return flags;
},
// Resalta un nodo
"resaltar" : function(obj, inicio, fin) {
var txtIni = "";
var txtSel = "";
var txtFin = "";
// Cojo el texto desde el inicio de texto hasta el inicio de selección
if (inicio > 0) {
txtIni = obj.nodeValue.substring(0, inicio);
}
// Cojo el texto seleccionado
txtSel = obj.nodeValue.substring(inicio, fin);
// Cojo el texto desde el fin de selección hasta el fin de texto
if (fin < obj.nodeValue.length) {
txtFin = obj.nodeValue.substring(fin);
}
var nuevo = null;
// Inserto la parte anterior a la seleccionada
if (txtIni != "") {
nuevo = obj.ownerDocument.createTextNode(txtIni);
obj.parentNode.insertBefore(nuevo, obj);
}
// Inserto la parte seleccionada como un span
nuevo = obj.ownerDocument.createTextNode(txtSel);
var span = obj.ownerDocument.createElement('SPAN');
span.rel = "SW_FIREMARKER";
span.style.backgroundColor = __SW_FIREMARKER_FIREFOX__.colorfondo;
span.style.color = __SW_FIREMARKER_FIREFOX__.colorletra;
span.appendChild(nuevo);
if (txtFin != "") {
obj.parentNode.insertBefore(span, obj);
} else {
obj.parentNode.replaceChild(span, obj);
}
// Inserto la parte posterior a la seleccionada
if (txtFin != "") {
nuevo = obj.ownerDocument.createTextNode(txtFin);
obj.parentNode.replaceChild(nuevo, obj);
}
},
// Guardo dentro de las preferencias los textos seleccionados para las urls en un formato
"setPref" : function(pref) {
/*
* Estructura
*   {{*}}URL1{{**}}Texto1{{**}}Texto2{{**}}...{{**}}TextoN{{*}}URL2{{**}}Texto1{{**}}....
*/
// Recupero las listas anteriores si no se ha recuperado ya
if (!__SW_FIREMARKER_FIREFOX__.lista_textos || !__SW_FIREMARKER_FIREFOX__.lista_textos.lenght == 0) {
__SW_FIREMARKER_FIREFOX__.cargarPrefs();
}
// Obtengo la URL
var url = content.document.location;
// Actualizo la url actual
if (!__SW_FIREMARKER_FIREFOX__.lista_textos[url]) {
__SW_FIREMARKER_FIREFOX__.lista_textos[url] = new Array();
__SW_FIREMARKER_FIREFOX__.lista_nodos[url] = new Array();
__SW_FIREMARKER_FIREFOX__.lista_offsets[url] = new Array();
}
var len = __SW_FIREMARKER_FIREFOX__.lista_textos[url].length;
__SW_FIREMARKER_FIREFOX__.lista_textos[url][len] = __SW_FIREMARKER_FIREFOX__.selectedText;
__SW_FIREMARKER_FIREFOX__.lista_nodos[url][len] = new Array(__SW_FIREMARKER_FIREFOX__.nodoIni, __SW_FIREMARKER_FIREFOX__.nodoFin);
__SW_FIREMARKER_FIREFOX__.lista_offsets[url][len] = new Array(__SW_FIREMARKER_FIREFOX__.offsetIni, __SW_FIREMARKER_FIREFOX__.offsetFin);
// Guardo todos los datos
__SW_FIREMARKER_FIREFOX__.guardarDatos();
},
// Guarda los datos en las preferencias
"guardarDatos" : function() {
var res = "";
// Por cada URL dentro de la lista de textos, formateo los datos
for (var _url in __SW_FIREMARKER_FIREFOX__.lista_textos) {
try {
res += '{{*}}'+_url;
for (var i=0; i<__SW_FIREMARKER_FIREFOX__.lista_textos[_url].length; i++) {
var textos_aux = __SW_FIREMARKER_FIREFOX__.lista_textos[_url][i];
var offsets_aux = __SW_FIREMARKER_FIREFOX__.lista_offsets[_url][i];
var nodos_aux = __SW_FIREMARKER_FIREFOX__.lista_nodos[_url][i];
res += '{{**}}'+offsets_aux[0]+'{{,}}'+offsets_aux[1]+'{{,}}';
res += nodos_aux[0]+'{{,}}'+nodos_aux[1]+'{{,}}';
res += textos_aux;
}
} catch (e) {}
}
// Guardo en las preferencias
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
var Branch = prefs.getBranch("extensions.swfiremarker.");
Branch.setCharPref("sw_listatextos", res);
},
// Limpio todas las preferencias, por lo que borro todos los textos seleccionados
"limpiarPrefs" : function() {
// Borro los datos de la preferencia
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
prefs.deleteBranch("extensions.swfiremarker.");
// Vacio los arrays
__SW_FIREMARKER_FIREFOX__.lista_textos = new Array();
__SW_FIREMARKER_FIREFOX__.lista_nodos = new Array();
__SW_FIREMARKER_FIREFOX__.lista_offsets = new Array();
// Quito spans marcados
var num = gBrowser.mPanelContainer.childNodes.length;
for (var i = 0; i < num; i++) {
var doc = gBrowser.getBrowserAtIndex(i);
__SW_FIREMARKER_FIREFOX__.limpiarSpan(doc.contentDocument);
}
},
// Limpio el texto seleccionado de la página actual
"limpiarPrefsPagina" : function() {
// Recupero el documento actual
var doc = content.document;
// Borro los arrays para la url actual
__SW_FIREMARKER_FIREFOX__.lista_textos[doc.location] = new Array();
__SW_FIREMARKER_FIREFOX__.lista_nodos[doc.location] = new Array();
__SW_FIREMARKER_FIREFOX__.lista_offsets[doc.location] = new Array();
// Quito spans marcados
__SW_FIREMARKER_FIREFOX__.limpiarSpan(doc);
// Guardo todos los datos, con lo que borro la url actual
__SW_FIREMARKER_FIREFOX__.guardarDatos();
},
// Quito los span que representan el texto marcado y dejo el texto limpio
"limpiarSpan" : function(doc) {
if (doc) {
var spans = doc.getElementsByTagName("SPAN");
for (var i=spans.length-1; i>=0; i--) {
if (spans[i].rel == "SW_FIREMARKER") {
var txt = doc.createTextNode(spans[i].firstChild.nodeValue);
spans[i].parentNode.replaceChild(txt, spans[i]);
}
}
}
},
// Copia al portapapeles el contenido de todos los textos seleccionados de la página actual
"copiarTextoPlano" : function() {
var copytext="";
var textos = __SW_FIREMARKER_FIREFOX__.lista_textos[content.document.location];
// Recupero los te
if (textos) {
for (var i=0; i<textos.length; i++) {
copytext += textos[i]+"\n";
}
}
// Guardo en el portapapeles, esto esta copiado directamente de un ejemplo
var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
if (!str) {
return false;
}
str.data = copytext;
var trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
if (!trans) {
return false;
}
trans.addDataFlavor("text/unicode");
trans.setTransferData("text/unicode",str,copytext.length * 2);
var clipid = Components.interfaces.nsIClipboard;
var clip = Components.classes["@mozilla.org/widget/clipboard;1"].getService(clipid);
if (!clip) {
return false;
}
clip.setData(trans,null,clipid.kGlobalClipboard);
},
// Cargo los colores de las preferencias y los muestro en los botones del menu contextual
"cargarColores" : function(popup) {
// Recupero los elementos del menu contextual que tratan los colores
var colores = popup.getElementsByTagName("colorpicker");
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
var Branch = prefs.getBranch("extensions.swfiremarker.");
try {
// Cargo el color de fondo
__SW_FIREMARKER_FIREFOX__.colorfondo = Branch.getCharPref("sw_colorfondo");
if (!__SW_FIREMARKER_FIREFOX__.colorfondo || __SW_FIREMARKER_FIREFOX__.colorfondo == "") {
__SW_FIREMARKER_FIREFOX__.colorfondo = "#FFFF00";
__SW_FIREMARKER_FIREFOX__.colorfondo = Branch.setCharPref("sw_colorfondo", __SW_FIREMARKER_FIREFOX__.colorfondo);
}
__SW_FIREMARKER_FIREFOX__.colorletra = Branch.getCharPref("sw_colorletra");
if (!__SW_FIREMARKER_FIREFOX__.colorletra || __SW_FIREMARKER_FIREFOX__.colorletra == "") {
__SW_FIREMARKER_FIREFOX__.colorletra = "#000000";
__SW_FIREMARKER_FIREFOX__.colorletra = Branch.setCharPref("sw_colorletra", __SW_FIREMARKER_FIREFOX__.colorletra);
}
colores[0].color = __SW_FIREMARKER_FIREFOX__.colorletra;
colores[1].color = __SW_FIREMARKER_FIREFOX__.colorfondo;
} catch (e) {
colores[0].color = "#000000";
colores[1].color = "#FFFF00";
__SW_FIREMARKER_FIREFOX__.colorfondo = "#FFFF00";
__SW_FIREMARKER_FIREFOX__.colorletra = "#000000";
Branch.setCharPref("sw_colorletra", __SW_FIREMARKER_FIREFOX__.colorletra);
Branch.setCharPref("sw_colorfondo", __SW_FIREMARKER_FIREFOX__.colorfondo);
}
},
// Se guardan los colores en las preferencias
"guardarColor" : function(picker) {
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
var Branch = prefs.getBranch("extensions.swfiremarker.");
Branch.setCharPref("sw_"+picker.id, picker.color);
eval('__SW_FIREMARKER_FIREFOX__.'+picker.id+' = "#FFFF00"');
},
// Log para debug
"log" : function(content) {
var savefile = "c:\\firemarker.log.txt";
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
} catch (e) {
alert("Permission to save file was denied.");
}
var file = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath( savefile );
if ( file.exists() == false ) {
alert( "Creating file... " );
file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420 );
}
var outputStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance( Components.interfaces.nsIFileOutputStream );
/* Open flags
#define PR_RDONLY       0x01
#define PR_WRONLY       0x02
#define PR_RDWR         0x04
#define PR_CREATE_FILE  0x08
#define PR_APPEND      0x10
#define PR_TRUNCATE     0x20
#define PR_SYNC         0x40
#define PR_EXCL         0x80
*/
/*
** File modes ....
**
** CAVEAT: 'mode' is currently only applicable on UNIX platforms.
** The 'mode' argument may be ignored by PR_Open on other platforms.
**
**   00400   Read by owner.
**   00200   Write by owner.
**   00100   Execute (search if a directory) by owner.
**   00040   Read by group.
**   00020   Write by group.
**   00010   Execute by group.
**   00004   Read by others.
**   00002   Write by others
**   00001   Execute by others.
**
*/
if (!content.match(/\n$/)) {
content += '\n';
}
outputStream.init( file, 0x04 | 0x10, 420, 0 );
var result = outputStream.write( content, content.length );
outputStream.close();
},
}

Similar Posts