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) {} }