<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sentido Web &#187; How to</title>
	<atom:link href="http://sentidoweb.com/category/how-to/feed" rel="self" type="application/rss+xml" />
	<link>http://sentidoweb.com</link>
	<description>Desarrollo web, HTML, CSS, Javascript, PHP, MySQL</description>
	<lastBuildDate>Mon, 16 Jan 2012 10:16:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>W3C: fallos de accesibilidad (II)</title>
		<link>http://sentidoweb.com/2007/05/29/w3c-fallos-de-accesibilidad-ii.php</link>
		<comments>http://sentidoweb.com/2007/05/29/w3c-fallos-de-accesibilidad-ii.php#comments</comments>
		<pubDate>Tue, 29 May 2007 23:00:00 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[Accesibilidad]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[w3c]]></category>
		<category><![CDATA[accesibilidad fallos]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2007/05/29/w3c-fallos-de-accesibilidad-ii.php</guid>
		<description><![CDATA[Seguimos con los fallos de accesibilidad que se suelen cometer en el desarrollo web, que nos ofrece la W3C y que empezamos a tratar hace unos días. Mostrar imágenes con información importante mediante estilos Se trata de usar una imagen que contiene información (por ejemplo para los enlaces del menú) y mostrarla como fondo de [...]]]></description>
			<content:encoded><![CDATA[<p>Seguimos con los fallos de accesibilidad que se suelen cometer en el desarrollo web, que nos ofrece la W3C y que <a href="http://sentidoweb.com/2007/05/23/w3c-fallos-de-accesibilidad-i.php">empezamos</a> a tratar hace unos días.</p>
<h3>Mostrar imágenes con información importante mediante estilos</h3>
<p>Se trata de usar una imagen que contiene información (por ejemplo para los enlaces del menú) y mostrarla como fondo de un elemento y que no haya un texto que indique el contenido de la imagen.</p>
<p>Una solución es escribir el texto pero no hacerlo visible, para ello usaremos la propiedad <em>text-ident</em>, si le damos un valor negativo elevado el texto desaparecerá por la izquierda. Por ejemplo, tenemos una imagen <em>titulo.png</em> que tiene el título del blog con un diseño especial, lógicamente queremos que se vea así por temas de diseño e imagen. Ahora bien, si solo mostramos la imagen, no somos capaces de leer el contenido de esta. Por ello tendremos que hacer lo siguiente para que el texto aparezca sin que haya estilos y con estilos solo aparezca la imagen:</p>
<pre><code>h1 {
background: url(titulo.png);
width: 200px;
height: 100px;
text-indent: -10000px;
}</code></pre>
<pre><code>&lt;h1&gt;Título&lt;/h1&gt;</code></pre>
<h3>Usar el estilo <em>blink</em> sin el mecanismo para parar el parpadeo</h3>
<p>Esta es corta, no uses jamás <em>text-decoration: blink</em>. Y si por un casual no te queda otra posibilidad que usarlo, crea un script que pare el parpadeo a los 3 segundos.</p>
<h3>Usar un applet o un flash que parpadee sin el mecanismo para pararlos</h3>
<p>Lo mismo que el punto anterior, pero enfocado a applets y a animaciones Flash.</p>
<h3>Usar subtítulos que omiten parte del diálogo o sonidos importantes</h3>
<p>Si vas a ofrecer un sonido, una conversación y no muestras los subtítulos con todo el contenido (conversación y sonidos destacados), no se trata de un buen subtítulo y puede haber información importante que se escape.</p>
<h3>Más información</h3>
<ul><li class="related"><a href="http://www.w3.org/TR/2007/WD-WCAG20-TECHS-20070517/Overview.html#F3">F3: Failure of SC 1.1.1 due to using CSS to include images that convey important information</a></li><li class="related"><a href="http://www.w3.org/TR/2007/WD-WCAG20-TECHS-20070517/Overview.html#F4">F4: Failure of SC 2.2.2 due to using text-decoration:blink without a mechanism to stop it in less than three seconds</a></li><li class="related"><a href="http://www.w3.org/TR/2007/WD-WCAG20-TECHS-20070517/Overview.html#F7">F7: Failure of SC 2.2.2 due to an object or applet, such as Java or Flash, that has blinking content without a mechanism to pause the content that blinks for more than three seconds</a></li><li class="related"><a href="http://www.w3.org/TR/2007/WD-WCAG20-TECHS-20070517/Overview.html#F8">F8: Failure of SC 1.2.1 due to captions omitting some dialogue or important sound effects</a></li></ul>
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2007/05/29/w3c-fallos-de-accesibilidad-ii.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>W3C: fallos de accesibilidad (I)</title>
		<link>http://sentidoweb.com/2007/05/23/w3c-fallos-de-accesibilidad-i.php</link>
		<comments>http://sentidoweb.com/2007/05/23/w3c-fallos-de-accesibilidad-i.php#comments</comments>
		<pubDate>Wed, 23 May 2007 23:00:00 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[Accesibilidad]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[w3c]]></category>
		<category><![CDATA[accesibilidad trucos]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2007/05/23/w3c-fallos-de-accesibilidad-i.php</guid>
		<description><![CDATA[Hoy vamos a empezar una serie de artículos en los que pretendemos explicar los fallos que se cometen en accesibilidad cuando se realizan aplicaciones web y las técnicas que debemos usar para evitar estos fallos. Para ello nos basamos en lo que especifica la W3C en su WCAG 2.0 (aún en estado borrador). Error 1: [...]]]></description>
			<content:encoded><![CDATA[<p>Hoy vamos a empezar una serie de artículos en los que pretendemos explicar los fallos que se cometen en accesibilidad cuando se realizan aplicaciones web y las técnicas que debemos usar para evitar estos fallos. Para ello nos basamos en lo que especifica la W3C en su <a href="http://www.w3.org/TR/2007/WD-WCAG20-TECHS-20070517/Overview.html">WCAG 2.0</a> (aún en estado borrador).</p>
<h3>Error 1: modificar el significado del contenido debido al posicionamiento mediante CSS</h3>
<p>Se trata de cambiar el significado semántico de una etiqueta, modificando su posicionamiento mediante CSS. Por ejemplo, si queremos crearnos una lista de elementos:</p>
<ul><li style="display: inline; width: 150px; float: left;">Elemento 1<ul><li>Elemento 1.1</li><li>Elemento 1.2</li><li>Elemento 1.3</li></ul></li><li style="display: inline; width: 150px; float: left;">Elemento 2<ul><li>Elemento 2.1</li><li>Elemento 2.2</li></ul></li></ul>
<br style="clear: both" />
<p>El fallo consiste en usar etiquetas no destinadas a ese sentido, cambiarle los estilos y representarlas como queremos. Por ejemplo podemos usar <em>span</em> para representar cada elemento y disponerlos en la posición que nos conviene:</p>
<pre><code>&lt;span class="cab1"&gt;Elemento 1&lt;/span&gt;
&lt;span class="cab2"&gt;Elemento 2&lt;/span&gt;
&lt;span class="ele1"&gt;Elemento 1.1&lt;/span&gt;
&lt;span class="ele2"&gt;Elemento 2.1&lt;/span&gt;
&lt;span class="ele3"&gt;Elemento 1.2&lt;/span&gt;
&lt;span class="ele4"&gt;Elemento 2.3&lt;/span&gt;</code></pre>
<p>Y con los estilos siguientes:</p>
<pre><code>.cab1 {
position: absolute;
top: 0px;
left: 0px;
}
.cab2 {
position: absolute;
top: 0px;
left: 200px;
}
.ele1 {
position: absolute;
top: 20px;
left: 0px;
}
.ele2 {
position: absolute;
top: 20px;
left: 200px;
}
.ele3 {
position: absolute;
top: 40px;
left: 0px;
}
.ele4 {
position: absolute;
top: 40px;
left: 200px;
}</code></pre>
<p>obtendríamos el mismo resultado visual, pero si quitaramos los estilos obtendríamos lo siguiente:</p>
<pre>Elemento 1 Elemento 2 Elemento 1.1 Elemento 2.1 Elemento 1.2 Elemento 2.3</pre>
<p>lo cual no tendría mucho sentido.</p>
<h3>Error 2: modificar el aspecto del texto para mostrar algo que ya representa una etiqueta</h3>
<p>Existen varias etiquetas de texto que tiene diferentes funcionalidades, pero aún así es típico encontrarse textos con sus estilos modificados para mostrar el resultado de una etiqueta ya existente. Un ejemplo muy común es este:</p>
<pre>&lt;span class="negrita"&gt;Título&lt;/span&gt;</pre>
<pre>.negrita {
font-weight: bold;
}</pre>
<p>Lo correcto sería usar la etiqueta <em>strong</em>.</p>
<h3>Más información</h3>
<ul><li class="related"><a href="http://www.w3.org/TR/2007/WD-WCAG20-TECHS-20070517/Overview.html#F1">F1: Failure of SC 1.3.2 due to changing the meaning of content by positioning information with CSS</a></li><li class="related"><a href="http://www.w3.org/TR/2007/WD-WCAG20-TECHS-20070517/Overview.html#F2">F2: Failure of SC 1.3.1 due to using CSS to create variations in presentation of text that conveys information without also using the appropriate markup or text</a></li></ul>
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2007/05/23/w3c-fallos-de-accesibilidad-i.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>10 consejos para mejorar tus queries MySQL</title>
		<link>http://sentidoweb.com/2007/04/11/10-consejos-para-mejorar-tus-queries-mysql.php</link>
		<comments>http://sentidoweb.com/2007/04/11/10-consejos-para-mejorar-tus-queries-mysql.php#comments</comments>
		<pubDate>Wed, 11 Apr 2007 17:45:00 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[How to]]></category>
		<category><![CDATA[MYSQL]]></category>
		<category><![CDATA[mysql optimizacion]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2007/04/11/10-consejos-para-mejorar-tus-queries-mysql.php</guid>
		<description><![CDATA[10 interesantes consejos a seguir para mejorar nuestras sentencias en MySQL, algunas de ellas para poder optimizar las ya creadas. Usa el comando explain: el comando explain te puede ayudar a identificar los índices que se usan y además te proporciona más información útil. Usa permisos menos complejos: usar permisos más sencillos evita que se [...]]]></description>
			<content:encoded><![CDATA[<p>10 interesantes consejos a seguir para mejorar nuestras sentencias en MySQL, algunas de ellas para poder optimizar las ya creadas.</p>
<ul><li><strong>Usa el comando <em>explain</em></strong>: el comando <em>explain</em> te puede ayudar a identificar los índices que se usan y además te proporciona más información útil.</li>
<li><strong>Usa permisos menos complejos</strong>: usar permisos más sencillos evita que se comprueben muchas condiciones en cada ejecución de una sentencia.</li>
<li><strong>Comando <em>benchmark</em></strong>: este comando nos permite saber cuánto tiempo tarda en ejecutarse una expresión.</li>
<li><strong>Optimiza tus cláusulas</strong>: ya sea quitando paréntesis innecesarios, usando <em>count(*)</em> sin condiciones en el <em>where</em> ya que tira de tablas internas de MyQSL o usando la opción <em>SQL_SMALL_RESULT</em> para usar tablas temporales en memoria.</li>
<li><strong>Ejecuta <em>optimize table</em></strong>: defragmenta una tabla después de varios borrados, el acceso a disco es algo importante a tener en cuenta.</li>
<li><strong>Evita campos de longitud variable</strong>: en tablas de frecuente actualización evita campos como <em>VARCHAR</em>, <em>BLOB</em> o <em>TEXT</em>.</li>
<li><strong>Usa <em>insert delayed</em></strong>: solo cuando sea no importe cuando se inserten los datos.</li>
<li><strong>Prioridades en las sentencias</strong>: usa <em>INSERT LOW_PRIORITY</em> para darle a las consultas mayor prioridad, o usa <em>SELECT HIGH_PRIORITY</em> para ejecutar una consulta aunque haya otros clientes esperando.</li>
<li><strong>Haz múltiples inserciones en una única sentencia:</strong> en vez de varias sentencias de una única inserción.</li>
<li><strong>Sincroniza tipos de datos</strong>: mismos datos en tablas diferentes deben ser del mismo tipo de datos.</li></ul>
<p>Yo siempre he tenido una duda, que no he resuelto por pereza, sobre el caso de ejecutar <em>count(*)</em> o <em>count(1)</em>. La leyenda urbana dice que es mejor <em>count(1)</em>, ya que de la otra forma obtienes que enviar todas las columnas, al igual que haces en un <em>select *</em>. Un consultor en Oracle nos dijo que era falsa esa afirmación porque tardaba lo mismo, yo creo que también, entre otras cosas porque seguro que ese punto está optimizado, pero claro, que sea consultor o que sea de Oracle no quiere decir nada, y menos aún si hablamos de otras bases de datos.</p>
<p><a href="http://www.whenpenguinsattack.com/2007/04/09/10-tips-for-optimizing-mysql-queries/">10 tips for optimizing mysql queries</a></p>
<p>Vía / <a href="http://alexsancho.name">Alex Sancho</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2007/04/11/10-consejos-para-mejorar-tus-queries-mysql.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Consejos para configuraciones SSH</title>
		<link>http://sentidoweb.com/2007/04/03/consejos-para-configuraciones-ssh.php</link>
		<comments>http://sentidoweb.com/2007/04/03/consejos-para-configuraciones-ssh.php#comments</comments>
		<pubDate>Tue, 03 Apr 2007 23:00:00 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[How to]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[ssh consejos]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2007/04/03/consejos-para-configuraciones-ssh.php</guid>
		<description><![CDATA[Aunque yo, la verdad, he tratado las conexiones SSH de resfilón, nunca está mal conocer algunos trucos para cuando tengamos que configurar nuestras conexiones SSH. Cambia el puerto: por defecto el puerto de escucha es el 22, cámbialo para que dificultar los ataques, sobre todo si es mayor a 1024, ya que la mayoría de [...]]]></description>
			<content:encoded><![CDATA[<p>Aunque yo, la verdad, he tratado las conexiones <a href="http://es.wikipedia.org/wiki/SSH">SSH</a> de resfilón, nunca está mal conocer algunos trucos para cuando tengamos que configurar nuestras conexiones SSH.</p>
<ul><li><strong>Cambia el puerto</strong>: por defecto el puerto de escucha es el 22, cámbialo para que dificultar los ataques, sobre todo si es mayor a 1024, ya que la mayoría de los scanners no admite valores tan altos.</li>
<li><strong>Admite solo el protocolo 2</strong>: SSH admite dos protocolos, permite tan solo el 2 ya que es más seguro.</li>
<li><strong>Permite solo usuarios específicos</strong>: no admitas al usuario <em>root</em> ya que es aumentar los riegos de ataque.</li>
<li><strong>Especifica tu propio aviso</strong>: si quieres que cualquier usuario pueda ver un aviso de acceso denegado crea tu propio fichero de texto que muestre el mensaje. Este punto no lo comprendo muy bien, está claro que me tengo que meter más a fondo con el SSH.</li>
<li><strong>Usa clave pública DSA</strong>: puedes usar para la autenticación claves públicas DSA en vez de usuario y contraseña.</li>
<li><strong>Usa TCP wrappers</strong>: permitiendo así conectarse solo a ciertos hosts.</li>
<li><strong>Usa iptables para permitir acceso a hosts</strong>: como alternativa a los TCP wrappers.</li>
<li><strong>Limita el acceso a periodos de tiempo</strong></li></ul>
<p><a href="http://enterprise.linux.com/enterprise/07/03/26/1423232.shtml?tid=129&#038;tid=100&#038;tid=35">Advanced SSH security tips and tricks</a></p>
<p>Vía / <a href="http://www.dzone.com/rsslinks/advanced_ssh_security_tips_and_tricks.html">dzone</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2007/04/03/consejos-para-configuraciones-ssh.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FireMarker: cómo crear una extensión para Firefox</title>
		<link>http://sentidoweb.com/2007/03/02/firemarker-como-crear-una-extension-para-firefox.php</link>
		<comments>http://sentidoweb.com/2007/03/02/firemarker-como-crear-una-extension-para-firefox.php#comments</comments>
		<pubDate>Fri, 02 Mar 2007 23:25:00 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[Firefox]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[firemarker]]></category>
		<category><![CDATA[firemarker howto xul]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2007/03/02/firemarker-como-crear-una-extension-para-firefox.php</guid>
		<description><![CDATA[Si 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 [...]]]></description>
			<content:encoded><![CDATA[<p><img alt="firemarker.png" src="http://sentidoweb.com/img/2007/02/firemarker.png" class="right" height="48" width="150" />Si el otro día os hablaba de <a href="http://sentidoweb.com/2007/02/26/firemarker-marca-los-textos-mediante-firefox.php">FireMarker</a>, 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.</p>
<p>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.</p>

<span id="more-916"></span>
<h3>Estructura de directorios</h3>
<p>Lo primero es mostrar la estructura de directorios y los ficheros que se encuentran en estos directorios:</p>
<p><img alt="firemarker4.png" src="http://sentidoweb.com/img/2007/03/firemarker4.png" width="171" height="171" class="center"/></p>
<ul><li><strong>raíz</strong>: contiene ficheros de instalación y de configuración del contenido y el resto de directorios.</li>
<li><strong>chrome</strong>: contiene toda la información de la extensión organizada en subdirectorios.</li>
<li><strong>firemarker</strong>: congrega contenido y estética.</li>
<li><strong>content</strong>: información sobre el contenido de la extensión.</li>
<li><strong>firemarker</strong> (dentro de <em>content</em>): contenido de la extensión.</li>
<li><strong>locale</strong>: información para el multilingüismo de la extensión.</li>
<li><strong>en-US</strong>: 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.</li>
<li><strong>es-ES</strong>: 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, &#8230;).</li>
<li><strong>skin</strong>: contiene la información necesaria para la estética de la página.</li>
<li><strong>classic</strong>: el theme de firefox por defecto, si se quiere modificar para otro theme se debería crear una estructura paralela a esta.</li>
<li><strong>firemarker</strong> (dentro de <em>classic</em>): información para esta extensión.</li>
</ul>
<h3>Ficheros</h3>
<p>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.</p>
<h4>Directorio raíz</h4>
<ul><li><strong>chrome.manifest</strong>: se especifica los distintos contenidos de la extensión: <em>overlay</em> (interfaces de usuario que se añaden a Firefox), <em>content</em> (contenido), <em>skin</em> y <em>locale</em> (ficheros para la internacionalización).</li></ul>
<pre>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/</pre>
<ul><li><strong>install.rdf</strong>: xml (<acronym title="Resource Description Framework">RDF</acronym>) 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>em:id</em> indentifica a la extensión y debe ser un código UUID único, para generarlo puedes usar esta <a href="http://www.famkruithof.net/uuid/uuidgen">aplicación</a>.</li></ul>
<pre>&lt;?xml version="1.0"?&gt;
&lt;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#"&gt;
&lt;RDF:Description RDF:about="rdf:#$F5NsG1"
em:id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
em:minVersion="0.9"
em:maxVersion="2.*" /&gt;
&lt;RDF:Description RDF:about="urn:mozilla:extension:file:firemarker.jar"
em:package="content/firemarker/"
em:skin="skin/classic/firemarker/"&gt;
&lt;em:locale&gt;locale/en-US/&lt;/em:locale&gt;
&lt;em:locale&gt;locale/es-ES/&lt;/em:locale&gt;
&lt;/RDF:Description&gt;
&lt;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"&gt;
&lt;em:targetApplication RDF:resource="rdf:#$F5NsG1"/&gt;
&lt;em:file RDF:resource="urn:mozilla:extension:file:firemarker.jar"/&gt;
&lt;/RDF:Description&gt;
&lt;/RDF:RDF&gt;</pre>
<h4>en-US</h4>
<p>Sirve igual para <em>es-ES</em> o cualquier otro idioma. Hay un fichero de configuración de contenido (<em>contents.rdf</em>) y otro que es una DTD que luego se usará para las traducciones (<em>firemarker.dtd</em>).</p>
<ul><li><strong>contents.rdf</strong>: contenido del directorio, hacer copy/paste y modificar de otra extensión.</li>
<li><strong>firemarker.dtd</strong>: DTD con las traducciones, a las que se podrá acceder desde los ficheros XUL:</li></ul>
<pre>&lt;!ENTITY SW_FM_ACERCADE.acerca.de "About" &gt;
&lt;!ENTITY SW_FM_ACERCADE.autor "Author" &gt;
&lt;!ENTITY SW_FM_ACERCADE.pagina.de.inicio "Home page" &gt;
&lt;!ENTITY SW_FM_OPCIONES.borrar.selecciones "Clean selections" &gt;
&lt;!ENTITY SW_FM_OPCIONES.borrar.selecciones.pagina "Clean page selections" &gt;
&lt;!ENTITY SW_FM_OPCIONES.copiar.selecciones.pagina "Copy page selected text" &gt;
&lt;!ENTITY SW_FM_OPCIONES.color.letra "Text color" &gt;
&lt;!ENTITY SW_FM_OPCIONES.color.fondo "Background color" &gt;</pre>
<h4>firemarker (dentro de classic)</h4>
<p>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 <em>contents.rdf</em> correspondiente.</p>
<h4>firemarker (dentro de content)</h4>
<p>Contiene los scripts y los layouts de la extensión, en nuestro caso tenemos tres archivos (sin incluir el contents.rdf):</p>
<ul><li><strong>acercade.xul</strong>: muestra la ventana de información de &#8220;Acerca de&#8230;&#8221;.</li>
<li><strong>firemarkerOverlay.xul</strong>: 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.</li>
<li><strong>firemarkerOverlay.js</strong>: scripts necesarios para la ejecución de la extensión.</li></ul>
<p>El único fichero que vamos a comentar, que es el que más dificultad puede tener es <strong>firemarkerOverlay.js</strong> 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.</p>
<p>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:</p>
<p>Tenemos el siguiente código HTML:</p>
<pre><code>&lt;h1&gt;Cabecera&lt;/h1&gt;
&lt;p&gt;Texto&lt;/p&gt;
&lt;div&gt;Footer&lt;/div&gt;</code></pre>
<p>Si seleccionamos de izquierda a derecha el siguiente texto: &#8220;<em>era Texto Foo</em>&#8220;, obtenemos los siguientes datos:</p>
<ul><li>Texto seleccionado: <em>era Texto Foo</em></li>
<li>Nodo inicial: <em>h1</em></li>
<li>Nodo final: <em>div</em></li>
<li>Offset inicial: 6 (el texto seleccionado empieza en la 6 posición)</li>
<li>Offset final: 3 (el texto seleccionado acaba en la 3 posición)</li></ul>
<p>Si la selección se realiza de derecha a izquierda los datos que obtengo son distintos:</p>
<ul><li>Texto seleccionado: <em>era Texto Foo</em></li>
<li>Nodo inicial: <em>div</em></li>
<li>Nodo final: <em>h1</em></li>
<li>Offset inicial: 6 (el texto seleccionado empieza en la 6 posición)</li>
<li>Offset final: 3 (el texto seleccionado acaba en la 3 posición)</li></ul>
<p>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.</p>
<p>Lo que debemos hacer en este instante es modificar los objetos HTML para añadirles un SPAN que tiene el estilo de marcado.</p>
<p>El resto del código creo que se puede entender con los comentarios:</p>
<pre><code>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&lt;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&lt;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 &amp;&amp;
__SW_FIREMARKER_FIREFOX__.lista_textos[doc.location] &amp;&amp;
__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&lt;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 &amp;&amp; __SW_FIREMARKER_FIREFOX__.nodoIni == __SW_FIREMARKER_FIREFOX__.nodoFin &amp;&amp;
__SW_FIREMARKER_FIREFOX__.offsetFin &lt; __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&lt;nodo.childNodes.length; i++) {
hijos[i] = nodo.childNodes[i];
}
for (var i=0; i&lt;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 &gt; 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 &lt; 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&lt;__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 &lt; 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&gt;=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&lt;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();
},
}</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2007/03/02/firemarker-como-crear-una-extension-para-firefox.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cómo decir a Google que vuelva por nuestra página más tarde</title>
		<link>http://sentidoweb.com/2007/02/28/como-decir-a-google-que-vuelva-por-nuestra-pagina-mas-tarde.php</link>
		<comments>http://sentidoweb.com/2007/02/28/como-decir-a-google-que-vuelva-por-nuestra-pagina-mas-tarde.php#comments</comments>
		<pubDate>Wed, 28 Feb 2007 23:11:00 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[apache googlebot]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2007/02/28/como-decir-a-google-que-vuelva-por-nuestra-pagina-mas-tarde.php</guid>
		<description><![CDATA[Cuando tenemos nuestra página en mantenimiento y el motor de Google (Googlebot) u otro motor de búsqueda, se pasa por nuestra página para indexarla, no es correcto que obtenga una página no encontrada (404) o un error del servidor (500). Según dicen en Google Webmaster Central lo correcto es mandar un código de red no [...]]]></description>
			<content:encoded><![CDATA[Cuando tenemos nuestra página en mantenimiento y el motor de Google (Googlebot) u otro motor de búsqueda, se pasa por nuestra página para indexarla, no es correcto que obtenga una página no encontrada (404) o un error del servidor (500).
Según dicen en <a href="http://googlewebmastercentral.blogspot.com/2006/08/all-about-googlebot.html">Google Webmaster Central</a> lo correcto es <strong>mandar un código de red no disponible (503)</strong>, pero el autor de este post recomienda también <strong>enviar un Retry-After</strong> para que vuelva a pasarse más tarde. También recomienda que a los motores de búsqueda se les envie a una página 503 y a los visitantes (menos a él) a una página 404 (página no encontrada).
<a href="http://www.askapache.com/2007/htaccess/instruct-search-engines-to-come-back-to-site-after-you-finish-working-on-it.html">Instruct Search Engines to come back to site after you finish working on it</a>
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2007/02/28/como-decir-a-google-que-vuelva-por-nuestra-pagina-mas-tarde.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Instala cualquier cosa en Ubuntu</title>
		<link>http://sentidoweb.com/2007/01/24/instala-cualquier-cosa-en-ubuntu.php</link>
		<comments>http://sentidoweb.com/2007/01/24/instala-cualquier-cosa-en-ubuntu.php#comments</comments>
		<pubDate>Wed, 24 Jan 2007 18:30:00 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[How to]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[ubuntu instalacion guia]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2007/01/24/instala-cualquier-cosa-en-ubuntu.php</guid>
		<description><![CDATA[Para los que no somos usuarios habituales de Linux, en este caso de Ubuntu, la siguiente guía nos puede ser de mucha utilidad para saber cómo instalar aplicaciones en esta distribución. Parece más enfocada a aquellos que van a pasar de Windows a Ubuntu, por lo que gracias a sus pantallazos y animaciones (¡dios mio, [...]]]></description>
			<content:encoded><![CDATA[<img alt="ubuntu.png" src="http://sentidoweb.com/img/2007/01/ubuntu.png" width="81" height="72" class="right"/>Para los que no somos usuarios habituales de Linux, en este caso de Ubuntu, la siguiente guía nos puede ser de mucha utilidad para saber cómo instalar aplicaciones en esta distribución.
Parece más enfocada a aquellos que van a pasar de Windows a Ubuntu, por lo que gracias a sus pantallazos y animaciones (¡dios mio, son GIFs animados) nos explica paso a paso lo necesario para realizar estas acciones y no perdernos.
Empieza a <strong>explicarnos el package manager</strong> y sobre todo las diferencias con Windows, lo cual es algo muy importante si nuestro caso es el de pasarnos de un sistema a otro. Después se centra en la <strong>instalación mediante Synaptic</strong>, después mediante el terminal y por último manualmente.
<a href="http://cutlersoftware.com/ubuntuinstall/">How to install ANYTHING in Ubuntu</a>
Vía / <a href="http://digg.com/linux_unix/How_to_install_ANYTHING_in_Ubuntu_3">Digg</a>
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2007/01/24/instala-cualquier-cosa-en-ubuntu.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Convirtiendo XML a JSON con PHP5 DOM y XSL</title>
		<link>http://sentidoweb.com/2007/01/17/convirtiendo-xml-a-json-con-php5-dom-y-xsl.php</link>
		<comments>http://sentidoweb.com/2007/01/17/convirtiendo-xml-a-json-con-php5-dom-y-xsl.php#comments</comments>
		<pubDate>Thu, 18 Jan 2007 01:22:07 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[API]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[json xml]]></category>
		<category><![CDATA[json xml php]]></category>
		<category><![CDATA[transform xml json]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2007/01/17/convirtiendo-xml-a-json-con-php5-dom-y-xsl.php</guid>
		<description><![CDATA[JSON es un formato de datos de intercambio de Javascript que el auge de AJAX ha hecho muy popular. En javascript es mucho más cómodo trabajar con JSON frente a XML ya que podemos analizarlo rápidamente utilizando eval(). Cuando queremos trabajar con API´s como las de Amazon, Technorati, del.icio.us o Ficrk v&#237;a REST nos encontramos [...]]]></description>
			<content:encoded><![CDATA[<p><abbr title="JavaScript Object Notation">JSON</abbr> es un formato de datos de intercambio de Javascript que el auge de <abbr title="Asynchronous JavaScript And XML">AJAX</abbr> ha hecho muy popular. En javascript es mucho más cómodo trabajar con JSON frente a XML ya que podemos analizarlo rápidamente utilizando <code>eval()<code>. </p>
<p>Cuando queremos trabajar con API´s como las de <a href="http://www.amazon.com/E-Commerce-Service-AWS-home-page/b/ref=sc_fe_l_2/104-9139505-4630348?ie=UTF8&amp;node=12738641&amp;no=3435361&amp;me=A36L942TSJ2AJA">Amazon</a>, <a href="http;://www.technorati.com/developers/api">Technorati</a>, <a href="http://del.icio.us/help/api">del.icio.us</a> o <a href="http://www.flickr.com/services/api/">Ficrk</a> v&iacute;a REST nos encontramos con que todas ellas devuelven los datos en XML. Gracias a <a href="http://www.php.net">PHP5</a> y utilizando sus extensiones DOM y XSL podemos transformar un documento XML en JSON de forma muy sencilla.
<h3>Veamos un ejemplo de cómo hacer esto con una consulta a la API de Technorati:</h3>
<p>En primer lugar vamos a componer la URL con la que haremos nuestra consulta:
<pre><code>
$technoratiApiKey = "introduceTuAPIdeTechnorati";
$url = "http://api.technorati.com/tag";
$tag = "usabilidad";
$request=$url."?key=".$technoratiApiKey."&#038;tag=".urlencode($tag);
</code></pre>
<p>Y ahora creamos un nuevo objeto DOM y cargamos nuestro el fichero XML que nos devuelve la consulta:
<pre><code>
$inputdom = new DomDocument();
$inputdom->load($request);
</code></pre>
<p>Para transformar los datos utilizaremos un xml2json.xsl, un fichero XSLT que tiene las instrucciones para transformar XML en JSON. Lo cargamos en un nuevo objeto DOM:
<pre><code>
$xslt = "xml2json.xsl";
$xsl = new DomDocument();
$xsl->load($xslt);
</code></pre>
<p>¿Qué nos falta? pues: crear un procesador de XSLT en PHP, cargar nuestra xslt, realizar la transformación y generar el documento:
<pre><code>
$proc = new XsltProcessor();
$xsl = $proc->importStylesheet($xsl);
$newdom = $proc->transformToDoc($inputdom);
print $newdom->saveHTML();
</code></pre>
<p>Próximamente veremos cómo utilizar esta técnica para procesar información de diversas API´s REST mediante AJAX.
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2007/01/17/convirtiendo-xml-a-json-con-php5-dom-y-xsl.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cómo destacar en el menú de navegación el acceso en que nos encontramos</title>
		<link>http://sentidoweb.com/2006/12/19/como-destacar-en-el-menu-de-navegacion-el-acceso-en-que-nos-encontramos.php</link>
		<comments>http://sentidoweb.com/2006/12/19/como-destacar-en-el-menu-de-navegacion-el-acceso-en-que-nos-encontramos.php#comments</comments>
		<pubDate>Wed, 20 Dec 2006 00:00:00 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[AI/Usabilidad]]></category>
		<category><![CDATA[Desarrollo web]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[navegacion]]></category>
		<category><![CDATA[php navegacion]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2006/12/19/como-destacar-en-el-menu-de-navegacion-el-acceso-en-que-nos-encontramos.php</guid>
		<description><![CDATA[Imaginemos que tenemos un menú de navegación y queremos diferenciar la opción de Home, el About, el Contacto&#8230; ya que en esos momentos estamos en uno de ellos. ¿Cómo hacerlo? En Babblative nos enlazan algunos métodos para hacerlo: Method 1 – WordPress: WordPress actually has this feature built-in. WP-List-Pages Method 2 – PHP: Jem&#8217;s Trendy [...]]]></description>
			<content:encoded><![CDATA[<p>Imaginemos que tenemos un menú de navegación y queremos diferenciar la opción de Home, el About, el Contacto&#8230; ya que en esos momentos estamos en uno de ellos. </p>
<p>¿Cómo hacerlo? En <a href="http://babblative.com/article/current-navigation">Babblative</a> nos enlazan algunos métodos para hacerlo:</p>
<blockquote>
<p><strong>Method 1 – WordPress:</strong> WordPress actually has this feature built-in. <a href="http://codex.wordpress.org/Template_Tags/wp_list_pages">WP-List-Pages</a></p>
<p><strong>Method 2 – PHP:</strong> <a href="http://jemjabella.co.uk/post.php?title=20060426_trendy_active_css_tabs">Jem&#8217;s Trendy Active <acronym title="Cascading Style Sheets">CSS</acronym> Tabs</a> or <a href="http://photomatt.net/scripts/intellimenu/">Matt&#8217;s Intelligent Menu&#8217;s</a>. I&#8217;ve personally had middling success with <acronym title="Hypertext PreProcessing">PHP</acronym> on a manually maintained site and little success with it on Textpattern.</p>
<p><strong>Method 3 – Textpattern:</strong> You can either muck around with multiple templates, which is bloated and unnecessary, or you can use <a href="http://sonspring.com/journal/txp-current-navigation">this method</a>. If you choose to use the multiple templates then you&#8217;ll need to read <a href="http://textpattern.com/faq/23/how-do-i-use-a-different-page-layout-for-each-section">how do I use a different page layout for each section</a>? </p>
<p><strong>Method 4 – Manually Maintained Sites:</strong> Use <a href="http://www.hicksdesign.co.uk/">Hicksdesigns</a> method to <a href="http://www.hicksdesign.co.uk/journal/highlighting-current-page-with-css">highlighting current page with <acronym title="Cascading Style Sheets">CSS</acronym></a></p>
<p>Keep Reading: <a href="http://archivist.incutio.com/viewlist/css-discuss/42076">Keeping a &#8216;current state&#8217; on navigation</a>, <a href="http://www.dassnagar.net/website_design_articles/navigation_with_PHP.htm">Keeping Navigation Current With <acronym title="Hypertext PreProcessing">PHP</acronym></a>, <a href="http://www.onlinetools.org/tools/easynav/">EasyNav</a>, <a href="http://www.456bereastreet.com/archive/200503/setting_the_current_menu_state_with_css/">Setting the Current Menu State with <acronym title="Cascading Style Sheets">CSS</acronym></a></p></blockquote>
<p>Vía / <a href="http://babblative.com/article/current-navigation">Babblative</a></p>
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2006/12/19/como-destacar-en-el-menu-de-navegacion-el-acceso-en-que-nos-encontramos.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Incluye tus vídeos en tu web</title>
		<link>http://sentidoweb.com/2006/11/29/incluye-tus-videos-en-tu-web.php</link>
		<comments>http://sentidoweb.com/2006/11/29/incluye-tus-videos-en-tu-web.php#comments</comments>
		<pubDate>Wed, 29 Nov 2006 23:10:00 +0000</pubDate>
		<dc:creator>displaynone</dc:creator>
				<category><![CDATA[Flash]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[encoding]]></category>
		<category><![CDATA[flv]]></category>
		<category><![CDATA[flv video flash encoding]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://sentidoweb.com/2006/11/29/incluye-tus-videos-en-tu-web.php</guid>
		<description><![CDATA[si ya hace tiempo explicábamos cómo subir un vídeo en formato FLV a tu web y verlo mediante un visor incluido en la página web, ahora se trata de un artículo donde explican cómo hacer, de forma muy detallada, para casi todos los formatos de vídeo más comerciales, mostrar el vídeo en formato Flash (FLV). [...]]]></description>
			<content:encoded><![CDATA[si ya hace tiempo explicábamos <a href="http://sentidoweb.com/2006/09/15/incluye-tu-propio-youtube-en-tu-blog.php">cómo subir un vídeo en formato FLV a tu web</a> y verlo mediante un visor incluido en la página web, ahora se trata de un artículo donde explican cómo hacer, de forma muy detallada, para casi todos los formatos de vídeo más comerciales, mostrar el vídeo en formato Flash (FLV).
En este caso se centran en los formatos de QuickTime, Windows Media y Abode Flash (aunque usando herramientas comerciales y no opensource como indicamos en el artículo anterior). Primero nos indican que debemos obtener la información del vídeo, luego codificarla y por último mostrarla.
Yo me sigo quedando con la alternativa opensource, pero es indiscutible que la explicación que nos ofrecen es de lo más completa.
<a href="http://www.digital-web.com/articles/the_rise_of_flash_video_part_3/">The Rise of Flash Video, Part 3: Tackle your own project with this step-by-step primer</a>
]]></content:encoded>
			<wfw:commentRss>http://sentidoweb.com/2006/11/29/incluye-tus-videos-en-tu-web.php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

