Código de general.js
Índice de funciones:
El código expuesto en esta página es el que inicialmente desarrollé y ha sufrido muchas modificaciones.Aquí encontrará el código actualizado de general.js.
- Funciones para controles de formularios
- Funciones de cadenas de texto
- Funciones para unificar comportamiento de navegadores
- Funciones para estilo CSS no estándar
- Funciones genéricas para el sitio
Código de general.js
/*
=========================================================================
Software: general.js
Description: Módulo que contiene funciones para uso general en el sitio.
Contact: http://www.wextensible.com
Copyright (c) 2010, Andrés de la Paz
Este archivo contiene funciones de uso general que podrían ser utilizadas
en cualquier documento del sitio.
Las abreviaturas para navegadores son:
IE: Internet Explorer
FF: Firefox
OP: Opera
SA: Safari
==========================================================================
*//* FUNCIONES PARA CONTROLES DE FORMULARIOS ---------------------------- * En esta sección se incluye funciones para gestionar los controles de * formularios, especialmente con eventos onkeypress sobre los de tipo * texto. */
/* Limita el número máximo de caracteres en un textarea. * Se limita al parámetro 'maximoTamanyo', el resto se corta y devuelve * false para no permitir más entrada de caracteres * - elemento: textarea donde se va a tratar * - eventoEntrante: el evento onkeypress * - maximoTamanyo: número de caracteres máximo que permite */
function controlaTextarea(elemento, eventoEntrante, maximoTamanyo){
try {
var texto = elemento.value;
var longitud = texto.length;
texto = texto.substring(0, maximoTamanyo-1);
elemento.value = texto;
//no permite entrar más caracteres
if (longitud > maximoTamanyo) {
var evento = eventoEntrante || window.event;
var codigoAscii = evento.charCode || evento.keyCode;
var teclas = [8, 37, 38, 39, 40, 46];
for (i in teclas){
if (codigoAscii == teclas[i]) {
return true;
}
}
return false;
} else {
return true;
}
} catch (e) {
return false;
}
}/* Evalúa número real. * Esta función se usa con el evento keypress de tal forma * que si la tecla pulsada no está en los caracteres dados * retorna falso y no admite el caracter en el control. */
function evaluaNumero(eventoEntrante){
try {
var evento = eventoEntrante || window.event;
var codigoAscii = evento.charCode || evento.keyCode;
var caracter = String.fromCharCode(codigoAscii);
var numeros = "-.0123456789";
return numeros.indexOf(caracter) != -1;
} catch (e) {
return false;
}
}/* Evalúa número entero. * Esta función se usa con el evento keypress de tal forma * que si la tecla pulsada no está en los caracteres dados * retorna falso y no admite el caracter en el control. */
function evaluaNumeroEntero(eventoEntrante){
try {
var evento = eventoEntrante || window.event;
var codigoAscii = evento.charCode || evento.keyCode;
var caracter = String.fromCharCode(codigoAscii);
var numeros = "0123456789";
return numeros.indexOf(caracter) != -1;
} catch (e) {
return false;
}
}/* Con un control de texto podemos arreglar una entrada * para que sea un número real. * - numero es un elemento con propiedad value, normalmente * un input. */
function arreglaNumero(numero) {
try {
var num = numero.value;
if (num == "") num = 0;
var numFloat = parseFloat(num);
if (isNaN(numFloat)) {
numero.value = 0;
} else {
numero.value = numFloat;
}
} catch (e) {}
}/* Con un control de texto podemos arreglar una entrada * para que sea un número entero. - numero es un elemento con propiedad value, normalmente * un input. */
function arreglaNumeroEntero(numero) {
try {
var num = numero.value;
if (num == "") num = 0;
var numInt = parseInt(num);
if (isNaN(numInt)) {
numero.value = 0;
} else {
numero.value = numInt;
}
} catch (e) {}
}/* Con un control de texto podemos arreglar una entrada * para que sea un número real o entero y limitarlo a * un rango dado. * - numero: un control con propiedad value, normalmente un * elemento input. * - tipo: "entero" o "real" * - desde: un número entero o real mínimo * - hasta: un número entero o real máximo */
function limitaValor(numero, tipo, desde, hasta) {
try {
var val = 0;
if (isNaN(numero.value)) numero.value = 0;
if (tipo == "entero") {
val = parseInt(numero.value);
} else {
val = parseFloat(numero.value);
}
if (val < desde) {
numero.value = desde;
} else if (val > hasta) {
numero.value = hasta;
} else {
numero.value = val;
}
} catch (e) {}
}/* FUNCIONES PARA CADENAS DE TEXTO ---------------------------- * Funciones genéricas para manejo de texto. */
/* Quita espacios antes y después de una cadena y convierte * más de un espacio en uno solo */
function quitaEspacios(cadena) {
try{
if (cadena != "") {
cadena = cadena.replace(/[ \s]+/g, " ");
cadena = cadena.replace(/^[ \s]+(.+)$/, "$1");
cadena = cadena.replace(/^(.+)[ \s]+$/, "$1");
}
} catch (e) {}
return cadena;
}/* Quita todos los espacios de una cadena */
function anulaEspacios(cadena){
try{
if (cadena != "") cadena = cadena.replace( /[ \s]+/g, "");
} catch(e) {}
return cadena;
}/* Sustituye barras invertidas por barras normales */
function escapaBarraUri(uri) {
try {
return uri.replace(/\\+/g, "/");
} catch (e) {
return uri;
}
}/* Agrega una segunda barra invertida para escaparlas */
function agregaEscapeRegExp(cadena) {
try{
cadena = cadena.replace(/\(/g, "\\(");
cadena = cadena.replace(/\)/g, "\\)");
} catch (e) {}
return cadena;
}/* Escapa caracteres reservados HTML devolviendo * las entidades de esos caracteres */
function escapaHtml(cadena) {
try{
cadena = cadena.replace(/&/g, "&");
cadena = cadena.replace(/</g, "<");
cadena = cadena.replace(/>/g, ">");
cadena = cadena.replace(/"/g, """);
cadena = cadena.replace(/'/g, "'");
} catch (e) {}
return cadena;
}/* Escapa caracteres reservados HTML devolviendo * los literales de texto de las entidades de esos * caracteres */
function escapaHtmlLiteral(cadena) {
try{
cadena = cadena.replace(/&/g, "&amp;");
cadena = cadena.replace(/</g, "&lt;");
cadena = cadena.replace(/>/g, "&gt;");
cadena = cadena.replace(/"/g, "&quot;");
cadena = cadena.replace(/'/g, "&#39;");
} catch (e) {}
return cadena;
}/* FUNCIONES PARA UNIFICAR COMPORTAMIENTO NAVEGADORES ------------------ * Funciones que unifican el comportamiento distinto de los * navegadores con Javascript o con gestión del DOM por ejemplo. */
/* En la medida de lo posible hay que hacer la diferenciación sin * usar que tipo de navegador es, pues así no tenemos que estar * rehaciendo las funciones de adecuación. Pero cuando no hay otra * forma podemos consultar que navegador es y nos devuelve una palabra * de las claves señaladas en el array. */
function queNavegador(){
try {
var arr = new Array("msie", "firefox", "opera", "safari");
for (var clave in arr){
if (navigator.userAgent.toLowerCase().indexOf(arr[clave]) > -1)
return arr[clave];
}
} catch(e){}
return "";
}/* Esta es la operación inversa, pasando una clave, la busca en el * userAgent devolviendo cierto o falso en su caso. Es recomendable usar * las claves anteriores pero no imprescindible, cualquier palabra en * el userAgent que sepamos que es exclusiva de ese navegador. */
function esNavegador(clave){
try {
return (navigator.userAgent.toLowerCase().indexOf(clave) > -1);
} catch(e){
return false;
}
}/* ENCIENDE UN EVENTO. * Con Explorer se enciende un evento con fireEvent de tal forma que el * objeto evento viene con 4 propiedades con los siguientes valores * predeterminados: * - cancelBubble = false (impide que el evento se propage por el DOM) * - returnValue = true (en los casos en que el evento retorne algún valor) * - srcElement = elemento donde se encendió el evento * - type = el nombre del evento (blur, click, etc) * El cancelBubble viene false, pero lo ponemos a true para impedir posibles * burbujeos. Mientras que con Mozilla el encendido del evento se define así: * event.initEvent(type, bubbles, cancelable). El argumento bubbles es true por * defecto, lo que hará que el evento "burbujee" por todo el DOM (para aquellos * eventos que burbujean como, por ejemplo "onmousedown"), es decir, sigue * aplicándose a los nodos hijos, por ejemplo. Cómo no queremos este efecto, * lo pasamos false. El argumento cancelable si lo pasamos true por si se * necesita cancelarlo. */
function enciendeEvento(elemento, evento) {
try {
if ((elemento != null)&&(evento != "")){
if (elemento.fireEvent) {//para Explorer
//Impide burbujeo
window.event.cancelBubble = true;
elemento.fireEvent(evento);
} else if (document.createEvent) {//para Firefox
var evt = document.createEvent("HTMLEvents")
evento = evento.substring(2, evento.length)
//Se cancela el burbujeo
evt.initEvent(evento, false, true)
elemento.dispatchEvent(evt)
} else {
alert("Error, no se pudo encender un evento en 'general.js'")
}
}
} catch (e) {
alert("Error en enciendeEvento de 'general.js'");
}
}/* Obtiene el texto interior de un elemento. * Tiene uso en DOM HTML y también para DOM XML con elemento.text o * bien con elemento.selectSingleNode */
function getInnerText(elemento) {
try {
if (elemento == null) {
return "";
} else if (elemento.childNodes.length > 0) {
//si tiene hijos buscamos una forma de sacar
//el texto
if (elemento.innerText) {//IE,OP,SA
return elemento.innerText;
} else if (elemento.textContent) {//FF
return elemento.textContent;
} else if (elemento.text) {
return elemento.text;
} else {
var nodoTexto = elemento.selectSingleNode("text()");
if (nodoTexto != null) {
return nodoTexto.nodeValue;
} else {
return "";
}
}
} else {//TODOS
//si no tiene hijos no tiene texto
return "";
}
} catch(e) {
return "";
}
}/* Retorna el elemento o nulo si se pone o no el texto * Hay que observar que si es un elemento vacío no podrá * ponerse texto como en un <input />. * Tiene uso en DOM HTML y también para DOM XML con elemento.text o * bien con elemento.selectSingleNode. */
function setInnerText(elemento, texto) {
try{
if (elemento != null){
if (elemento.innerText) {//IE,OP,SA
elemento.innerText = texto;
} else if (elemento.textContent) {//FF
elemento.textContent = texto;
} else if (elemento.innerHTML) {
//si no hay otra posibilidad lo ponemos con
//innerHTML que si lo ejecutan IE, OP, SA y FF
elemento.innerHTML = texto;
} else if (elemento.text) {
elemento.text = texto;
} else {
var nodoTexto = elemento.selectSingleNode("text()");
if (nodoTexto != null) {
nodoTexto.nodeValue = texto;
} else {
return null;
}
}
}
return elemento;
} catch(e){
return null;
}
}/* Para obtener el innerHTML y también el propio literal * HTML del elemento. Es lo que hace IE con outerHTML que * no la hace FF. */
function getOuterHTML(elemento) {
try{
if (elemento == null) {
return "";
} else if (elemento.outerHTML) {//IE
return elemento.outerHTML;
} else {//FF
var tag = elemento.tagName.toLowerCase();
var outer = "<" + tag;
var atributos = elemento.attributes;
var cadenaAtributos = "";
for (var i=0; i<atributos.length; i++) {
cadenaAtributos += " " + atributos[i].nodeName + "=\"" +
atributos[i].nodeValue + "\"";
}
outer += cadenaAtributos;
var conten = "";
//La función contenido necesita del dtdar.js para saber
// si es un elemento vacío. Si no está el dtdar.js entonces
//lo ignora al captar el error
try {
conten = contenido("ELEMENT", tag);
if (conten == "EMPTY") {
outer += " />";
} else {
outer += ">";
}
} catch (e){
outer += ">";
}
outer += elemento.innerHTML;
if (conten != "EMPTY") {
outer += "</" + tag + ">";
}
return outer;
}
} catch(e) {
return "";
}
}/* Lo mismo pero para poner el outerHTML que FF no * lo hace */
function setOuterHTML(elemento, cadenaHtml) {
try {
if (elemento != null) {
if (elemento.outerHTML) {//IE
elemento.outerHTML = cadenaHtml;
} else {//FF
var frag = rango.createContextualFragment(cadenaHtml);
elemento.parentNode.replaceChild(frag, elemento);
}
}
} catch(e) {}
}/* Para obtener el nodo padre. */
function nodoPadre(nodo) {
try {
if (nodo == null) {
return null;
} else if (nodo.parentElement) {//IE
return nodo.parentElement;
} else {//FF
return nodo.parentNode;
}
} catch(e){
return null;
}
}/* Para eliminar un nodo devolviendo el * nodo eliminado. */
function eliminaNodo(nodo, eliminaContenido) {
try {
if (nodo == null) {
return null;
} else if (nodo.removeNode) {//IE
return nodo.removeNode(eliminaContenido);
} else {//FF
return nodoPadre(nodo).removeChild(nodo);
}
} catch(e){
return null;
}
}/* Para obtener el atributo colspan de una celda */
function getColspan(celda) {
try {
if (celda == null) {
return 0;
} else {
var colspanStr = celda.getAttribute("colspan")
if (colspanStr == null) {//FF
return 1;
} else {//IE
return parseInt(colspanStr);
}
}
} catch(e){
return 0;
}
}/* Para obtener el atributo rowspan de una celda */
function getRowspan(celda) {
try {
if (celda == null) {
return 0;
} else {
var rowspanStr = celda.getAttribute("rowspan")
if (rowspanStr == null) {//FF
return 1;
} else {//IE
return parseInt(rowspanStr);
}
}
} catch(e){
return 0;
}
}/* Para obtener el texto de un rango * Sólo para IE y FF */
function rangoText(rango) {
try {
if (rango == null) {
return "";
} else if (rango.text) {
return rango.text;
} else if (rango.toString) {
return rango.toString();
} else {
return "";
}
} catch(e){
return "";
}
}
/* Devuelve un objeto CSSStyleDeclaration que contiene las propiedades
* de estilo y valores actuales o computados, usando las externas de
* los archivos CSS y las internas declaradas en el elemento <style>.
* Con Firefox puede usarse window o document.defaultView
* Al objeto devuelto puede accederse con objeto[i] o bien con un bucle
* for(var nombrePropiedad in objeto){...}
* obteniendo los string de los nombres de la propiedad como "fontSize"
* (sin guiones). Luego podemos consultar el valor con
* propiedadEstiloActual(objeto, nombrePropiedad).
* Probado para IE8, FF3.6, OP10.6
*/
function objetoEstiloActual(elemento){
try {
if (elemento != null) {
if (elemento.currentStyle) {//IE
return elemento.currentStyle;
} else if (document.defaultView.getComputedStyle) {//FF, OP
return document.defaultView.getComputedStyle(elemento, null);
} else {
return null;
}
} else {
return null;
}
} catch(e){
return null;
}
}/* Con el objetoEstiloActual() anterior podemos obtener el valor de una * propiedad, que debe venir sin guiones como "fontSize". Para Firefox es * necesaria con guiones, lo que se consigue con descambiaGuiones(). * Funciona con IE8, FF3.6, OP10.6 pero no funciona con SA4.0 */
function propiedadEstiloActual(objetoEstilo, propiedad){
try {
if ((objetoEstilo != null)&&(propiedad != "")) {
if (objetoEstilo.getAttribute) {//IE
//necesita "fontSize"
return "" + objetoEstilo.getAttribute(propiedad);
} else if (objetoEstilo.getPropertyValue) {//FF, OP
//necesita "font-size"
var propConGuiones = descambiaGuiones(propiedad);
var valor = "" +
objetoEstilo.getPropertyValue(propConGuiones);
//Con Safari no funciona pues extrae cosas con
//valores nulos
if (valor != null) {
return valor;
} else {
//Por si alguno necesita sin guiones "fontSize"
valor = objetoEstilo.getPropertyValue(propiedad);
if (valor != null) {
return valor;
} else {
return "";
}
}
} else {
return "";
}
} else {
return "";
}
} catch(e){
return "";
}
}/* Obtiene el estilo actual de una propiedad de un elemento consultando * directamente al objeto CSSStyleDeclaration. La propiedad debe venir con * guiones como "font-size". Para IE se le quitan los guiones con * cambiaGuiones(). */
function estiloActual(elemento, propiedad){
try {
if (window.getComputedStyle){//FF, Opera (con guiones)
//también puede ser window.getComputedStyle...
return document.defaultView.getComputedStyle(elemento,null).getPropertyValue(propiedad);
} else if (elemento.currentStyle){//IE (sin guiones)
var propSinGuiones = cambiaGuiones(propiedad);
if (elemento.currentStyle.getAttribute) {//IE
return elemento.currentStyle.getAttribute(propSinGuiones);
} else {//
return elemento.currentStyle[propSinGuiones];
}
} else {
return "";
}
} catch(e) {
return "";
}
}/* Cambia "font-size" a "fontSize" para usar en las funciones * anteriores y obtener el estilo actual */
function cambiaGuiones(cadena){
try {
var temp = "";
if (cadena.indexOf("-")>-1){
for (var i=0; i<cadena.length; i++) {
var car = cadena.substring(i,i+1);
if (car == "-"){
var carSgte = cadena.substring(i+1,i+2)
temp += carSgte.toUpperCase();
i++;
} else {
temp += car;
}
}
temp = temp.replace(/\-/g, "");
} else {
temp = cadena;
}
return temp;
} catch (e) {
return cadena;
}
}/* Cambia "fontSize" a "font-size" para usar en las funciones * anteriores y obtener el estilo actual */
function descambiaGuiones(cadena){
try {
var mayus = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var temp = "";
for (var i=0; i<cadena.length; i++) {
var car = cadena.substring(i,i+1);
if (mayus.indexOf(car) > -1){
temp += "-" + car.toLowerCase();
} else {
temp += car;
}
}
return temp;
} catch (e) {
return cadena;
}
}/* aplica getElementsByClassName para IE que no lo * ejecuta y FF sí. */
function arrayClassName(nombreClase, elemento){
try {
function recorreDom(el, arr){
if (el.className == nombreClase) arr.push(el);
var hijos = el.childNodes;
for (var i=0; i<hijos.length; i++){
recorreDom(hijos[i], arr);
}
return arr;
}
var nodo = document.body;
if (elemento != null) nodo = elemento;
if (document.getElementsByClassName){ //FF
return nodo.getElementsByClassName(nombreClase);
} else { //IE
var arr = new Array;
return recorreDom(nodo, arr);
}
} catch (e) {
return null;
}
}
/* Esto recoge un objeto window.event y devuelve * un Object con las propiedades: * - Object.event: el propio objeto evento del argumento * - Object.element: el elemento que lo causó * Coordenadas respecto al elemento * - Object.x * - Object.y * Coordenadas respecto a la página (a la ventana) * - Object.pagx * - Object.pagy * El código ASCII de la tecla pulsada * - Object.keyAscii = evt.charCode || evt.keyCode; */
function recogeEvento(evento){
try {
var evt = event || window.event;
var X = 0;
var Y = 0;
var pagX = 0;
var pagY = 0;
var elemento = null;
if (evt.srcElement) {//IE,SA,CH,OP
elemento = evt.srcElement;
} else {//FF
elemento = evt.target;
}
if (evt.x != undefined){//IE,SA,CH,OP
pagX = evt.x;
pagY = evt.y;
} else {//FF
pagX = evt.clientX;
pagY = evt.clientY;
}
if (window.scrollX != undefined){//FF,OP,SA,CH
pagX += window.scrollX;
pagY += window.scrollY;
} else {//IE
pagX += document.body.scrollLeft;
pagY += document.body.scrollTop;
}
X = pagX - elemento.offsetLeft;
Y = pagY - elemento.offsetTop;
var objeto = new Object;
objeto.event = evt;
objeto.element = elemento;
objeto.x = X;
objeto.y = Y;
objeto.pagx = pagX;
objeto.pagy = pagY;
objeto.keyAscii = evt.charCode || evt.keyCode;
return objeto;
} catch (e){
return null;
}
}/* FUNCIONES PARA ADECUAR ESTILO CSS NO ESTANDAR ------------------ * Las propiedades de estilo que aún están en fase de borrador se * incluyen dinámicamente y así podemos validar los documentos. */
/* Devuelve una cadena "propiedad: valor" según los argumentos * pasados. Para evitar que ciertos navegadores como Opera * detecten la adjudicación dinámica de una propiedad no * esperada, hemos también de filtrarlas por navegador. * - propiedad: string con el nombre de la propiedad * - valor: el valor de la propiedad * Se puede incorporar a un elemento con: * elemento.style.cssText += ";" + estiloNoCss(propiedad, valor) */
function estiloNoCss(propiedad, valor) {
var estilo = "";
switch (propiedad){
case "opacity": {//según CSS3 opacity
if (esNavegador("msie")){//IE
estilo = "filter: alpha(opacity=" + (valor * 100) + ")";
} else {//FF, OP, SA?
estilo = "opacity: " + valor;
}
break;
}
case "user-select": {//CSS3 user-select
if (esNavegador("firefox")){//Sólo FF
estilo = "-moz-user-select: " + valor;
}
break;
}
}
return estilo;
}/* FUNCIONES GENÉRICAS DEL SITIO WEB ------------------ * Funciones varias que se usan en muchas páginas del sitio */
/* Función para cambiar el tamaño de fuente de toda la página.
* Para que funcione establecemos en estilo externo en "cabeza_pie.css"
* body{font-size: 1em} y también div#total{font-size: 1em} que es
* el tamaño de la fuente de partida. Luego con este script le cambiamos
* el tamaño al <div id="total"> que es quién contiene toda la página.
* Sin embargo para acceder al estilo declarado externo necesitamos
* usar elemento.currentStyle.fontSize en IE mientras que en FF se usa
* otra cosa (getComputedStyle). Por lo tanto para evitar estas diferencias
* ponemos en el HTML el elemento <div id="total" style="font-size: 1em">
* volviendo a repetir el estilo. Así en todos los navegadores accedemos
* con elemento.style.fontSize al valor del tamaño de la fuente.
*/
function cambiarFuente() {
try {
var boton = document.getElementById("boton-aaa");
var total = document.getElementById("total")
var fs = total.style.fontSize;
if (fs == "0.75em") {
total.style.fontSize = "1em";
boton.title = "Zoom 125%";
} else if (fs == "1em") {
total.style.fontSize = "1.25em";
boton.title = "Zoom 150%";
} else if (fs == "1.25em") {
total.style.fontSize = "1.5em";
boton.title = "Zoom 75%";
} else {
total.style.fontSize = "0.75em";
boton.title = "Zoom 100%";
}
} catch (e) {}
}