User:Ciencia Al Poder-fduser/CharInsert

'''An English translated version of this text is avaliable. Note that may be outdated'''.

Esta es una extensión para MediaWiki que permite una personalización casi total de los caracteres que se colocan debajo del formulario de edición para insertar en el mismo.

Funcionalidades

 * Funcional en Mozilla Firefox, Opera e Internet Explorer. En general, con cualquier explorador que soporte el estándar DOM Level 1 y DOM Level 2 Events.
 * Pueden definirse grupos de caracteres tanto en el propio HTML de la página como por javascript de forma sencilla.
 * Los diferentes grupos de caracteres se muestran ocultos, y se selecciona uno u otro a través de un cuadro de selección (select). La caja de selección sólo se muestra si hay más de un grupo definido.
 * Al seleccionar otro grupo de caracteres, el grupo seleccionado se guarda en una cookie de sesión de forma que al volver a cargar la página en modo edición el grupo que aparecerá será el último que se seleccionó.
 * Carga modular: Los grupos de caracteres definidos por javascript (no en el propio HTML) se cargan en el documento en el momento que se seleccionan en la caja de selección, no antes. De esta forma se reduce el tiempo de carga de la página.
 * El diseño de la interfaz es personalizable por CSS.
 * Programación orientada a objetos: Diseñada como una clase, para evitar interferencias con otras funciones.

Licencia
http://www.gnu.org/copyleft/gpl.html GNU General Public Licence 2.0 o posterior.

Pre-requisitos
Para insertar el texto en el cuadro de edición se utiliza la función insertTags definida en el archivo wikibits.js

JavaScript
Antes de que se pueda procesar código de esta utilidad, se debe declarar la única variable global de esta utilidad (en el MediaWiki:Common.js, Special:Mypage/monobook.js de usuario o similar), de esta forma:

var charInsert = {groups: {}};

A partir de aquí se pueden insertar o cargar las definiciones de las funciones de la utilidad, o los grupos predeterminados de caracteres (tal como se describe en Personalizaciones básicas), en cualquier orden, aunque lo ideal es que se carguen los grupos de caracteres antes de que se cargue cualquier archivo JavaScript de usuario, para que el usuario pueda sobrescribir los grupos de caracteres que se definan para el sitio. Por ejemplo (esto es sólo un ejemplo):

 charInsert.groups["MediaWiki"] = [ '~', [], [,], [], ['#REDIRECT ',], [' '], ' ', [' ',' '], [' ',' '], ['&lt;nowiki>','&lt;/nowiki>'], [], ['',''], ''];

También se debe indicar el ID del elemento dentro del cual se inicializará esta utilidad, insertando los grupos de caracteres definidos y hacer que los caracteres ya insertados en el HTML se activen.

A partir de aquí, se deben declarar todas las funciones necesarias parea el funcionamiento de la utilidad:

// Autor: Jesús Martínez Novo (Ciencia Al Poder) // Licencia/License: http://www.gnu.org/copyleft/gpl.html GNU General Public Licence 2.0 or later // Para agregar conjuntos de caracteres especiales, agregar nuevos identificadores a charInsert.groups como elementos de arrays. Si el elemento es otro array, será un "elemento doble" // ejemplo: charInsert.groups["Nombre del grupo"] = ['a','b','c', ['d','e'], ['f','g'] ]; // Para deshabilitar cookie al cambiar grupo de caracteres: // charInsert.disableCookie = true;

charInsert.version = '1.1';

charInsert.bindId = 'charinsert-blocks'; // ID del elemento donde se insertará la utilidad. Cambiar si es necesario

charInsert.activaCaracteresEspeciales = function { if (!document.createTextNode) return; // No es DOM compatible var divSC = document.getElementById(charInsert.bindId); if (!divSC) return; // 1. Añadimos una caja de selección segn los conjuntos de caracteres que hay var select = document.createElement('select'); select.id = 'chargroup-select'; // 1.1 Conjuntos de caracteres que ya haya en el código var listaCharGrp = divSC.getElementsByTagName('div'); for (var i = 0; i < listaCharGrp.length; i++){ var p = listaCharGrp[i]; if ((' chargroup ').indexOf(' '+p.className+' ') != -1){ var option = document.createElement('option'); option.value = p.title; option.groupRef = p;     option.appendChild(document.createTextNode(p.title)); select.appendChild(option); p.title = ''; // Borramos el título para que no aparezca al pasar el mouse por encima // IE Fix: la selección actual en el textarea se pierde si se hace clic en un elemento que no sea un 'a' o un elemento de formulario ('input', etc) if (document.selection && !is_gecko){ var el = p.firstChild; if (el) { do { if (el.nodeType == 1 && el.tagName.toLowerCase == 'span') { var inel = el.firstChild; if (!inel) continue; var a = document.createElement('a'); a.href = '#'; do { var refinel = inel; inel = inel.nextSibling a.appendChild(refinel); } while (inel); el.appendChild(a); }         } while (el = el.nextSibling); }     }      // Fin IE Fix } }  // 1.2 Conjuntos de caracteres definidos en charInsert.groups (custom) if (typeof charInsert.groups == typeof {}){ for (grupo in charInsert.groups){ var option = document.createElement('option'); option.value = grupo; option.groupRef = null; option.groupArray = charInsert.groups[grupo]; option.appendChild(document.createTextNode(grupo)); select.appendChild(option); } }

if (select.options.length > 1){ divSC.insertBefore(select, divSC.firstChild); // 2. Capturamos el evento de cambio charInsert.addEvent(select, 'change', charInsert.eSelectChanged); // 3. Seleccionamos grupo por defecto var selectedGrp = select.options[0].value; if (charInsert.disableCookie == undefined || charInsert.disableCookie != true){ var cookie = document.cookie; var cookiePos = cookie.indexOf('chargroup='); if (cookiePos > -1) { cookiePos += 10; var endPos = cookie.substring(cookiePos,cookie.length).indexOf(';'); if (endPos == -1) endPos = cookie.length; selectedGrp = decodeURIComponent(document.cookie.substr(cookiePos,endPos)); }   }    select.value = selectedGrp; charInsert.selectChargroup(select.options[select.selectedIndex]); }else{ delete select; }

// 4. Asignamos un evento para todo el area charInsert.addEvent(divSC, 'click', charInsert.specialCharClick); };

charInsert.eSelectChanged = function(event){ var targetElement = charInsert.eventTargetElement(event); charInsert.selectChargroup(targetElement.options[targetElement.selectedIndex]); if (charInsert.disableCookie == undefined || charInsert.disableCookie != true) document.cookie = 'chargroup='+encodeURIComponent(targetElement.options[targetElement.selectedIndex].value); };

charInsert.selectChargroup = function(item){ var divSC = document.getElementById(charInsert.bindId); if (!divSC) return;

var listaCharGrp = divSC.getElementsByTagName('div'); for (var i = 0; i < listaCharGrp.length; i++){ var p = listaCharGrp[i]; if ((' '+p.className+' ').indexOf(' chargroup ') != -1){ if ((p.isSameNode && p.isSameNode(item.groupRef)) || p == item.groupRef){ //DOM || IE       p.style.display = 'inline'; }else{ p.style.display = 'none'; }   }  }  if (!item.groupRef && item.groupArray){ var p = charInsert.addGroup(item.groupArray); item.groupRef = p;   p.style.display = 'inline'; } };

charInsert.addGroup = function(group){ var divSC = document.getElementById(charInsert.bindId); if (!divSC) return; var bloque = document.createElement('div'); bloque.className = 'chargroup'; for (var i = 0; i < group.length; i++){ // IE Patch if (document.selection && !is_gecko){ var car = document.createElement('a'); car.href = "#"; } else // END IE Patch var car = document.createElement('span'); if (typeof group[i] == typeof ''){ car.appendChild(document.createTextNode(group[i])); }else if(typeof group[i] == typeof [] && group[i].length == 2){ var c1 = document.createElement('span'); c1.appendChild(document.createTextNode(group[i][0])); car.appendChild(c1); var c2 = document.createElement('span'); c2.appendChild(document.createTextNode(group[i][1])); car.appendChild(c2); }   // IE Patch if (document.selection && !is_gecko){ var ospan = document.createElement('span'); ospan.appendChild(car); bloque.appendChild(ospan); } else // END IE Patch bloque.appendChild(car); bloque.appendChild(document.createTextNode(' ')); } divSC.appendChild(bloque); return bloque; };

charInsert.specialCharClick = function(event){ var charEl = charInsert.eventTargetElement(event); // Obtenemos el span más externo posible, pero que descienda directamente del div de class 'chargroup' // Si lo capta un textNode (no debería), buscamos su span. if (charEl.nodeType == 3){ // text node. if (charEl.parentNode.nodeType == 1 && charEl.parentNode.tagName.toLowerCase == 'span') charEl = charEl.parentNode; else return; } // For IE patch if (charEl.parentNode.tagName.toLowerCase == 'a') charEl = charEl.parentNode; if (charEl.tagName.toLowerCase == 'a'){ charEl = charEl.parentNode; event.returnValue = false; } // End IE  if (charEl.nodeType != 1 || charEl.tagName.toLowerCase != 'span') return;

if ((' '+charEl.parentNode.className+' ').indexOf(' chargroup ') == -1){ // span interno? if ((' '+charEl.parentNode.parentNode.className+' ').indexOf(' chargroup ') == -1) return; else charEl = charEl.parentNode; }

var spans = charEl.getElementsByTagName('span'); if (spans.length < 2) insertTags(charInsert.getElementText(charEl), , ); else insertTags(charInsert.getElementText(spans[0]), charInsert.getElementText(spans[1]), ''); };

charInsert.getElementText = function(element){ if (element.textContent) return element.textContent; else if (element.innerText) return element.innerText; };

charInsert.eventTargetElement = function(event){ if (event.target) return event.target; else if(event.srcElement) //IE return event.srcElement; else // ?? return null; }

charInsert.addEvent = function(element, hookName, hookFunct) { if (element.addEventListener) element.addEventListener(hookName, hookFunct, false); else if (element.attachEvent) element.attachEvent('on' + hookName, hookFunct); }

Para iniciar la utilidad, se debe ejecutar la función charInsert.activaCaracteresEspeciales. Es necesario que todas las funciones hayan sido declaradas antes de ejecutar esta función, o se producirá un error. En el momento de ejecutarse buscará un elemento cuyo atributo id sea el definido en charInsert.bindId (se puede cambiar) para inicializarlo.

En una wiki que utilize el software MediaWiki se puede hacer situando al final de todas las funciones:

addOnloadHook(charInsert.activaCaracteresEspeciales);

CSS
La apariencia de la interfaz es personalizable mediante hojas de estilo en cascada (CSS). Para dar una apariencia de teclas a las zonas activas se puede usar el siguiente código, para incluir en MediaWiki:Common.js, Special:Mypage/monobook.css o similar:

En caso de cambiar la variable charInsert.bindId se debe cambiar el identificador asociado a las siguientes reglas de estilo CSS (en este caso "#charinsert-block")

padding: 2px; border: 1px solid #dfe6ff; background: #efefef; color: #000000; line-height: 1.8em; }
 * 1) charinsert-block {


 * 1) charinsert-block select { margin-right: 0.5em; }

padding: 0 2px; border: 1px solid #afafaf; background: #dddddd; cursor: pointer; white-space: nowrap; }
 * 1) charinsert-block .chargroup span {


 * 1) charinsert-block .chargroup > span:hover { background: #ffffff; }

background: transparent; border: none; }
 * 1) charinsert-block .chargroup span span {

text-decoration: none; color: black; }
 * 1) charinsert-block .chargroup span a {

Páginas
La utilidad aparecerá en la página donde haya un div con el atributo id</tt> definido en la variable charInsert.bindId</tt>.

Técnicamente, en su interior no es necesario que haya nada (puede ser un elemento sin contenido), y se recomienda que no haya nada en su interior, excepto si quiere definir en el propio código un conjunto de caracteres a mostrar. El lugar donde insertarlo en una wiki debería ser en MediaWiki:Edittools.

De aquí en adelante, el atributo id</tt> asociado al elemento div</tt>, se usará con valor charinsert-block</tt> como ejemplo, y debe estar definido en charInsert.bindId</tt>. Para usar otro valor debe cambiarse en ambos lados, y también en las reglas de estilo CSS que se puedan haber definido para ese ID

Sin ningún caracter, sólo para que se carguen los caracteres que se hayan definido en charInsert.groups</tt> (véase Personalizaciones básicas para saber cómo usarlo):

Para precargar una serie de caracteres en el propio HTML de la página, que estarán disponibles aunque el JavaScript esté deshabilitado (en este caso aparecerán pero no se producirá ninguna acción al hacer clic sobre ellos):

<pre style="overflow:auto"> ~ –  —  …   «  »

El funcionamiento es el siguiente: Cada elemento div</tt> de clase chargroup</tt> dentro del div</tt> de id definido en charInsert.groups</tt> será un "grupo" de caracteres. El nombre de cada grupo estará definido por su atributo title</tt>. En caso de haber más de un grupo entre el propio HTML y/o los que se definan por JavaScript aparecerá un cuadro de selección para mostrar únicamente uno de ellos, y el nombre del grupo vendrá dado por el atributo title</tt> del div</tt>.

Cada elemento span</tt> que haya en su interior será un elemento que, al hacer clic sobre él, se insertará su contenido en texto en el cuadro de edición. Si hay dos elementos span</tt> anidados dentro de un elemento span</tt>, el contenido del primer elemento se insertará antes de la posición del cursor o selección en el cuadro de edición, y el contenido del segundo después de la selección o cursor.

Instalación por usuario
El código funciona también si se instala a nivel de usuario, es decir, no disponible para toda la wiki sino sólo para el usuario que se lo quiera instalar en su Monobook.js (o similar).

Para ello el código será el mismo, pero no se tiene acceso a MediaWiki:Edittools por lo que, o existe ya en esa página un div con el id definido en <tt>charInsert.groups</tt>, o habrá que agregarlo por JavaScript antes de que se cargue la utilidad. Si es el caso, habrá que poner esto en el código antes del <tt>addOnloadHook(charInsert.activaCaracteresEspeciales);</tt>, o adaptarlo según gustos:

Para agregarlo justo debajo de cualquier textarea:

addOnloadHook(function{ var txts = document.getElementsByTagName('textarea');  if (txts.length < 1) return;  var div = document.createElement('div');  div.id = charInsert.bindId; // Especificamos el mismo id definido en charInsert.bindId  txts[0].parentNode.insertBefore(div, txts); });

Ejemplo de código personalizado por usuario: User:Ciencia Al Poder/monobook.js

Presentación
La presentación de los caracteres se puede personalizar usando reglas de estilo CSS. Sólo se fuerza por JavaScript la visibilidad de los grupos, permitiendo una gran personalización.

Si se utilizan grupos en el propio HTML, se pueden establecer propiedades de estilos en línea. Por ejemplo, ocultar los grupos de caracteres, para que no aparezcan hasta que se activen por JavaScript, o evitará que se muestren si el JavaScript no está activado.

Texto personalizado
Para agregar grupos de caracteres personalizados por JavaScript (nótese que no solo se pueden agregar caracteres, sino cualquier pedazo de texto) hay que agregar al objeto <tt>charInsert.groups</tt> nuevas propiedades. El nombre de la propiedad será el nombre del grupo de caracteres que aparecerá en el cuadro de selección (visible sólo si hay más de un grupo definido). El valor de la propiedad deberá ser un Array de strings. Cada elemento de convertirá en un elemento sobre el que se podrá hacer clic en él.

Los elementos del array que a su vez también sean otro array convertirán el elemento en complejo, y se insertará el primer elemento del array anidado antes de la posición del cursor, mientras que el segundo elemento del array anidado después del cursor o selección.

charInsert.groups[ "Nombre del grupo" ] = [ 'as', 'df' , [ '«' , '»' ] ];


 * Se pueden insertar tantos grupos como se quieran.
 * El nombre del grupo es el que aparecerá en el cuadro de selección de grupos (si hay más de uno disponible). Puede contener espacios. Si se definen más de uno con el mismo nombre, el último definido sobrescribirá al anterior.
 * Los elementos simples del array serán cadenas de texto que se insertarán en la posición del cursor.
 * Los elementos complejos del array (otro array dentro del array principal) formarán una única región de texto sobre la que interactuar, pero se insertará la primera parte del texto antes de la posición del cursor y la segunda después. Si hay más elementos en el sub-array serán ignorados.

De la misma forma se pueden agregar elementos en el propio HTML de la página, insertando en el elemento <tt>div</tt> de propiedad <tt>id</tt> definida en la variable <tt>charInsert.bindId</tt> uno o más elementos <tt>div</tt> de propiedad <tt>class</tt> <tt>chargroup</tt>. En su interior debe haber un elemento <tt>span</tt> que será cada región de texto que se insertará. Si en su interior hay dos elementos <tt>span</tt>, éstos se insertarán a ambos lados de la selección, o del cursor si no hay nada seleccionado:

<div class="chargroup" title=" Nombre del grupo "> as    df        «  »


 * <tt>  </tt>: (El id especificado también en la variable <tt>charInsert.bindId</tt>) Lugar donde aparecerán la selección de caracteres de esta utilidad. Sólo puede haber uno en la página. Si no existe este elemento, no aparecerá la utilidad.
 * <tt> <div class="chargroup" title=" Nombre del grupo ">  </tt>: Grupos de caracteres. Tal como ya se ha explicado, sólo aparecerá el grupo seleccionado. El resto permanecerá oculto. Se podrá seleccionar uno u otro a través de un cuadro de selección. El título de cada selección vendrá definido por el atributo <tt>title</tt> de cada <tt>div</tt>. Puede haber más de un grupo.
 * Los elementos <tt>    </tt> que contengan sólo texto en su interior será el texto que se insertará en la posición del cursor. Nota: Para insertar como texto elementos reconocibles por el software de MediaWiki sin que sean interpretados como tal, usa el elemento <tt>&lt;nowiki&gt;</tt> o utiliza referencias de carácter (como <tt>&amp;lt;</tt> para el carácter &lt;, etc).
 * Si dentro de un elemento <tt>span</tt> hay dos elementos <tt> span </tt>, el elemento será único pero al pulsar sobre él se insertará el contenido del primer <tt>span</tt> antes de la selección y el contenido del segundo después.

Nota importante: Al insertar los elementos <tt>   </tt> en el HTML hay que hacerlo todo en una única línea, sin saltos de línea, ya que por alguna razón el software MediaWiki insertará automáticamente el contenido dentro de un elemento <tt>    </tt> y causará un funcionamiento incorrecto.

Por ejemplo:

<pre style="overflow:auto;"> charInsert.groups["MediaWiki"] = [ '~', [], [,], ['#REDIRECT ',], [' '], ' ', ''];

equivaldría a colocar en MediaWiki:Edittools lo siguiente:

<pre style="overflow:auto;"> ~            #REDIRECT

Nótese que es mucho más sencillo agregar grupos por JavaScript que por HTML, además de incluir menos código. Además, el código en MediaWiki:Edittools se carga cada vez que se edita una página, mientras que el código JavaScript hace uso de la caché del navegador y se carga sólo una vez hasta que se refresca o vacía la caché.

Deshabilitar cookies
En el caso de que haya más de un grupo, aparecerá un cuadro de selección para seleccionar uno de ellos, ocultando el resto. Al seleccionar uno de ellos se guardará en una cookie de sesión el valor del grupo seleccionado, para que al recargar la página se cargue el último grupo seleccionado. Esto ocurrirá sólo si las cookies están habilitadas en el navegador. La cookie se borrará al cerrar la ventana del navegador.

Si tiene configurado el navegador para que le pregunte si quiere guardar cada cookie y/o quiere deshabilitar este comportamiento, puede colocar lo siguiente en el código JavaScript:

charInsert.disableCookie = true;

De esta forma no se escribirán cookies en el navegador al seleccionar un grupo, pero tampoco se leerán al cargar la utilidad.

Usar funciones propias
Es posible que hayas personalizado tu JavaScript o el de la Wiki que administres. Si en la wiki ya hay funciones que realizan lo mismo, puedes sustituir las que aquí se incluyen por una referencia a las que ya haya definidas. Por ejemplo, es posible que hayas definido funciones para que te devuelvan el texto de un elemento, o que devuelvan el elemento que inició un evento. En ese caso sólo tienes que reemplazar las funciones repetidas asignando una referencia a la función:

charInsert.eventTargetElement = window.eventTargetElement;

charInsert.addEvent = window.addEvent;

Comprobar esta utilidad
WikiDex tiene instalada esta utilidad para toda la wiki. Puedes probar su funcionamiento editando la Zona de pruebas.

El código está dividido en varias partes: w:c:es.pokemon:MediaWiki:Edittools, w:c:es.pokemon:MediaWiki:Common.js, w:c:es.pokemon:MediaWiki:Edit.js, w:c:es.pokemon:MediaWiki:Common.css.

Regstro de cambios

 * Versión 1.0
 * Primera versión


 * Versión 1.1
 * Arreglado bug al obtener el grupo guardado en la cookie
 * Nueva variable <tt>charInsert.bindId</tt> donde poder especificar de forma centralizada el ID donde activar la uilidad.

en:User:Ciencia Al Poder/CharInsert/en