/** * Script de validación directa para campos de DNI/documento * Versión: 1.0.1 */ // Iniciar cuando el DOM esté cargado document.addEventListener('DOMContentLoaded', inicializarValidador); // También intentar inicializar después de que la página esté completamente cargada window.addEventListener('load', inicializarValidador); // Definir variable global para controlar inicialización window.dniValidatorInitialized = window.dniValidatorInitialized || false; /** * Inicializa el validador de documentos */ function inicializarValidador() { // Evitar inicializar múltiples veces if (window.dniValidatorInitialized) return; console.log("Iniciando validador de documentos..."); // Inicializar la validación para los campos específicos const campos = [ document.getElementById('delivery_dni'), document.getElementById('field-dni'), ...Array.from(document.getElementsByName('dni')), ...Array.from(document.querySelectorAll('[data-validation*="isDniLite"]')) ].filter(campo => campo !== null); // Si no encontramos ningún campo, intentar una búsqueda más amplia if (campos.length === 0) { console.log("No se encontraron campos de DNI con los selectores principales. Buscando alternativas..."); // Buscar campos por sus atributos const camposAdicionales = [ ...Array.from(document.querySelectorAll('input[placeholder*="Identificaci"]')), ...Array.from(document.querySelectorAll('input[placeholder*="DNI"]')), ...Array.from(document.querySelectorAll('input[id*="dni"]')), ...Array.from(document.querySelectorAll('input[id*="DNI"]')), ...Array.from(document.querySelectorAll('input[name*="dni"]')), ...Array.from(document.querySelectorAll('input[name*="DNI"]')) ].filter(campo => campo !== null); campos.push(...camposAdicionales); } // Eliminar duplicados const camposUnicos = Array.from(new Set(campos)); console.log(`Se encontraron ${camposUnicos.length} campos para validar:`, camposUnicos); if (camposUnicos.length > 0) { camposUnicos.forEach(configurarCampoDNI); window.dniValidatorInitialized = true; // Configurar también la validación para campos que puedan cargarse dinámicamente configurarObservadorMutaciones(); // Integración con el sistema de validación existente if (window.$ && window.$.formUtils) { window.$.formUtils.addValidator({ name: 'isDniLite', validatorFunction: function(value) { return validarDocumento(value).valido; }, errorMessage: 'Documento de identidad no válido', errorMessageKey: 'badDNI' }); console.log("Integración con jQuery Form Validator completada"); } } else { console.log("No se encontraron campos de DNI/documento en la página actual"); } } /** * Configura un observador de mutaciones para detectar cambios en el DOM * y aplicar la validación a nuevos campos que puedan aparecer */ function configurarObservadorMutaciones() { // Crear un observador de mutaciones const observer = new MutationObserver((mutations) => { let newNodes = false; // Revisar si se han añadido nuevos nodos mutations.forEach(mutation => { if (mutation.addedNodes.length) { newNodes = true; } }); // Si hay nuevos nodos, buscar campos de DNI if (newNodes) { const nuevosCampos = [ ...Array.from(document.querySelectorAll('#delivery_dni:not([data-dni-validator])')), ...Array.from(document.querySelectorAll('#field-dni:not([data-dni-validator])')), ...Array.from(document.querySelectorAll('input[name="dni"]:not([data-dni-validator])')), ...Array.from(document.querySelectorAll('[data-validation*="isDniLite"]:not([data-dni-validator])')) ].filter(campo => campo !== null); if (nuevosCampos.length > 0) { console.log(`Se encontraron ${nuevosCampos.length} nuevos campos para validar`); nuevosCampos.forEach(configurarCampoDNI); } } }); // Iniciar la observación observer.observe(document.body, { childList: true, subtree: true }); console.log("Observador de mutaciones configurado para detectar nuevos campos"); } /** * Configura un campo de DNI con los eventos necesarios */ function configurarCampoDNI(campo) { // Marcar el campo como configurado campo.setAttribute('data-dni-validator', 'true'); console.log("Configurando campo:", campo.id || campo.name || "sin id/nombre"); // Validar al perder el foco campo.addEventListener('blur', function() { const resultado = validarDocumento(this.value); console.log("Resultado validación:", resultado); mostrarResultadoValidacion(this, resultado); }); // Convertir a mayúsculas durante la escritura campo.addEventListener('input', function() { if (/[a-zA-Z]/.test(this.value)) { const start = this.selectionStart; const end = this.selectionEnd; this.value = this.value.toUpperCase(); this.setSelectionRange(start, end); } }); // Configurar validación en el formulario const form = campo.closest('form'); if (form && !form.hasAttribute('data-dni-validator')) { form.setAttribute('data-dni-validator', 'true'); form.addEventListener('submit', function(e) { // Validar todos los campos de documento en este formulario const camposDNI = form.querySelectorAll('[data-dni-validator]'); let formValido = true; camposDNI.forEach(campoDNI => { // Solo validar campos visibles if (campoDNI.offsetParent !== null) { const resultado = validarDocumento(campoDNI.value); if (!resultado.valido) { formValido = false; e.preventDefault(); mostrarResultadoValidacion(campoDNI, resultado); campoDNI.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } }); return formValido; }); } // Añadir icono de información si es necesario // (Comentado para evitar posibles problemas de diseño) /* if (!campo.nextElementSibling || !campo.nextElementSibling.classList.contains('info-icon')) { const infoIcon = document.createElement('span'); infoIcon.className = 'info-icon'; infoIcon.innerHTML = ''; infoIcon.title = 'Ver formatos aceptados'; campo.insertAdjacentElement('afterend', infoIcon); infoIcon.addEventListener('click', function() { alert('Documentos aceptados:\\n\n' + '• Personas físicas (España):\n' + ' - DNI: 12345678Z\n' + ' - NIE: X1234567L\n' + ' - Pasaporte: AAA000000\n\n' + '• Empresas:\n' + ' - CIF español: B70915004\n' + ' - VAT europeo: ESB70915004, FR12345678901\n\n' + '• Otros países:\n' + ' - Portugal, Italia, Francia, Reino Unido, etc.'); }); } */ // Validación inicial const resultado = validarDocumento(campo.value); if (campo.value) { mostrarResultadoValidacion(campo, resultado); } } /** * Muestra el resultado de la validación */ function mostrarResultadoValidacion(inputElement, resultado) { // Crear ID único para el mensaje const mensajeId = (inputElement.id ? inputElement.id : 'dni') + '-validation-message'; // Buscar o crear elemento para mensajes let mensajeElement = document.getElementById(mensajeId); if (!mensajeElement) { mensajeElement = document.createElement('div'); mensajeElement.id = mensajeId; mensajeElement.style.fontSize = '12px'; mensajeElement.style.marginTop = '5px'; mensajeElement.style.marginBottom = '5px'; // Insertar después del campo o su contenedor más cercano if (inputElement.parentNode) { inputElement.parentNode.appendChild(mensajeElement); } } // Actualizar mensaje según resultado if (!resultado.valido) { // DNI incompleto if (resultado.tipo === 'DNI_incompleto') { mensajeElement.textContent = resultado.mensaje || 'DNI incompleto. Añade la letra.'; // Calcular letra correcta if (/^\d{8}$/.test(inputElement.value.trim())) { const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(inputElement.value.trim()) % 23); mensajeElement.textContent += ' La letra correcta es: ' + letraCalculada; } } // DNI con letra incorrecta else if (resultado.tipo === 'DNI_letra_incorrecta') { const numero = inputElement.value.trim().substring(0, 8); const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(numero) % 23); mensajeElement.textContent = 'La letra del DNI no es correcta. Debería ser: ' + letraCalculada; } // NIE con letra incorrecta else if (resultado.tipo === 'NIE_letra_incorrecta') { const valor = inputElement.value.trim().toUpperCase(); const primera = valor.charAt(0); const numero = valor.substring(1, 8); let numeroCompleto; switch (primera) { case 'X': numeroCompleto = '0' + numero; break; case 'Y': numeroCompleto = '1' + numero; break; case 'Z': numeroCompleto = '2' + numero; break; } const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(numeroCompleto) % 23); mensajeElement.textContent = 'La letra del NIE no es correcta. Debería ser: ' + letraCalculada; } // Formato similar a un DNI pero incorrecto else if (resultado.tipo === 'formato_similar_dni') { mensajeElement.textContent = 'Formato similar a un DNI/NIE pero incorrecto. Verifica el documento.'; } // Otros errores else { mensajeElement.textContent = 'Documento no válido. Verifica el formato.'; } // Aplicar estilos para errores mensajeElement.style.color = '#d9534f'; // Rojo inputElement.style.borderColor = '#d9534f'; // Añadir clases de error según el tema de PrestaShop inputElement.classList.add('is-invalid'); inputElement.classList.remove('valid'); inputElement.classList.add('error'); } else { // Documento válido let tipoDocumento = getTipoDocumentoNombre(resultado.tipo); mensajeElement.textContent = 'Documento válido: ' + tipoDocumento; mensajeElement.style.color = '#5cb85c'; // Verde inputElement.style.borderColor = '#5cb85c'; // Añadir clases de validez según el tema de PrestaShop inputElement.classList.remove('is-invalid', 'error'); inputElement.classList.add('is-valid', 'valid'); } } /** * Validar documento de identidad */ function validarDocumento(value) { if (!value) return { valido: false, tipo: 'desconocido' }; value = value.trim().toUpperCase(); // Caso especial: DNI incompleto (8 dígitos) if (/^\d{8}$/.test(value)) { return { valido: false, tipo: 'DNI_incompleto', mensaje: 'Parece un DNI español sin letra. Añade la letra correcta.' }; } // Validar CIF de empresa española if (validarCIF(value)) { return { valido: true, tipo: 'CIF_ESP' }; } // Validar VAT europeo if (validarVAT(value)) { return { valido: true, tipo: 'VAT_EU' }; } // Caso especial: formato similar a DNI (7 dígitos + 1 letra) if (/^\d{7}[A-Z]$/.test(value)) { return { valido: false, tipo: 'formato_similar_dni', mensaje: 'Formato similar a un DNI pero incorrecto (7 dígitos + letra).' }; } // Validar DNI español if (validarDNI(value)) { return { valido: true, tipo: 'DNI_ESP' }; } else if (/^\d{8}[A-Z]$/.test(value)) { // DNI con letra incorrecta return { valido: false, tipo: 'DNI_letra_incorrecta', mensaje: 'La letra del DNI no es correcta.' }; } // Validar NIE if (validarNIE(value)) { return { valido: true, tipo: 'NIE_ESP' }; } else if (/^[XYZ]\d{7}[A-Z]$/.test(value)) { // NIE con letra incorrecta return { valido: false, tipo: 'NIE_letra_incorrecta', mensaje: 'La letra del NIE no es correcta.' }; } // Validar pasaporte español if (validarPasaporteEspanol(value)) { return { valido: true, tipo: 'pasaporte_ESP' }; } // Validar NIF Portugal if (validarNIFPortugal(value)) { return { valido: true, tipo: 'NIF_PT' }; } // Validar Codice Fiscale Italia if (validarCodiceFiscaleItalia(value)) { return { valido: true, tipo: 'CF_IT' }; } // Validar Carte Nationale d'Identité Francia if (validarCNIFrancia(value)) { return { valido: true, tipo: 'CNI_FR' }; } // Validar National Insurance Number UK if (validarNINOReinoUnido(value)) { return { valido: true, tipo: 'NINO_UK' }; } // Validar pasaporte extranjero if (validarPasaporteExtranjero(value)) { return { valido: true, tipo: 'pasaporte_extranjero' }; } return { valido: false, tipo: 'desconocido' }; } // Resto de funciones (validaciones específicas) /** * Validar DNI español */ function validarDNI(dni) { dni = dni.toUpperCase(); const dniRegex = /^(\d{8})([A-Z])$/; if (!dniRegex.test(dni)) return false; const match = dni.match(dniRegex); const numero = match[1]; const letra = match[2]; // Calcular letra correcta const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(numero) % 23); return letra === letraCalculada; } /** * Validar NIE */ function validarNIE(nie) { nie = nie.toUpperCase(); const nieRegex = /^([XYZ])(\d{7})([A-Z])$/; if (!nieRegex.test(nie)) return false; const match = nie.match(nieRegex); const primera = match[1]; const numero = match[2]; const letra = match[3]; // Reemplazar la primera letra con su equivalente numérico let numeroCompleto; switch (primera) { case 'X': numeroCompleto = '0' + numero; break; case 'Y': numeroCompleto = '1' + numero; break; case 'Z': numeroCompleto = '2' + numero; break; } // Calcular letra correcta const letras = 'TRWAGMYFPDXBNJZSQVHLCKE'; const letraCalculada = letras.charAt(parseInt(numeroCompleto) % 23); return letra === letraCalculada; } /** * Validar CIF español */ function validarCIF(cif) { cif = cif.toUpperCase(); // Si es un VAT español, quitar el prefijo ES if (/^ES[A-Z0-9]{9}$/.test(cif)) { cif = cif.substring(2); } // Comprobar formato del CIF const cifRegex = /^([ABCDEFGHJKLMNPQRSUVW])(\d{7})([0-9A-J])$/; if (!cifRegex.test(cif)) return false; const match = cif.match(cifRegex); const letra = match[1]; const numero = match[2]; const control = match[3]; // Calcular dígito de control let suma = 0; // Suma dígitos pares for (let i = 1; i < 7; i += 2) { suma += parseInt(numero.charAt(i)); } // Suma dígitos impares (multiplicados por 2) for (let i = 0; i < 7; i += 2) { let temp = parseInt(numero.charAt(i)) * 2; if (temp > 9) { temp = Math.floor(temp/10) + (temp % 10); } suma += temp; } // Calcular el dígito de control let controlCalculado = (10 - (suma % 10)) % 10; // Para ciertos tipos de entidades, el control es numérico const letrasCifNumero = 'ABCDEFGHJUV'; if (letrasCifNumero.indexOf(letra) >= 0) { return controlCalculado.toString() === control; } else { // Para el resto, el control es una letra const letrasControl = 'JABCDEFGHI'; return letrasControl.charAt(controlCalculado) === control; } } /** * Validar VAT europeo */ function validarVAT(vat) { vat = vat.toUpperCase(); // España (ESB12345678) if (/^ES[A-Z0-9]{9}$/.test(vat)) { return validarCIF(vat.substring(2)); } // Portugal (PT123456789) if (/^PT\d{9}$/.test(vat)) { return validarNIFPortugal(vat.substring(2)); } // Francia (FR12345678901) if (/^FR[A-Z0-9]{11}$/.test(vat)) { return true; // Validación simplificada } // Italia (IT12345678901) if (/^IT\d{11}$/.test(vat)) { return true; // Validación simplificada } // Reino Unido (GB123456789, GB123456789012) if (/^GB(\d{9}|\d{12})$/.test(vat)) { return true; // Validación simplificada } // Alemania (DE123456789) if (/^DE\d{9}$/.test(vat)) { return true; // Validación simplificada } return false; } /** * Validar pasaporte español */ function validarPasaporteEspanol(pasaporte) { pasaporte = pasaporte.toUpperCase(); const pasaporteRegex = /^[A-Z]{3}\d{6}$/; return pasaporteRegex.test(pasaporte); } /** * Validar NIF Portugal */ function validarNIFPortugal(nif) { const nifRegex = /^(\d{9})$/; if (!nifRegex.test(nif)) return false; // Algoritmo de validación const numero = nif.substring(0, 8); const control = parseInt(nif.charAt(8), 10); let suma = 0; for (let i = 0; i < 8; i++) { suma += parseInt(numero.charAt(i)) * (9 - i); } let resto = suma % 11; let checkDigit; if (resto === 0 || resto === 1) { checkDigit = 0; } else { checkDigit = 11 - resto; } return control === checkDigit; } /** * Validar Codice Fiscale Italia */ function validarCodiceFiscaleItalia(cf) { cf = cf.toUpperCase(); const cfRegex = /^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$/; return cfRegex.test(cf); } /** * Validar Carte Nationale d'Identité Francia */ function validarCNIFrancia(cni) { const cniRegex = /^\d{12}$/; return cniRegex.test(cni); } /** * Validar National Insurance Number UK */ function validarNINOReinoUnido(nino) { nino = nino.toUpperCase(); const ninoRegex = /^[A-CEGHJ-PR-TW-Z][A-CEGHJ-NPR-TW-Z]\d{6}[A-D]$/; return ninoRegex.test(nino); } /** * Validar pasaporte extranjero */ function validarPasaporteExtranjero(pasaporte) { pasaporte = pasaporte.toUpperCase(); // 1. Longitud 7-9 caracteres if (pasaporte.length < 7 || pasaporte.length > 9) return false; // 2. Patrón alfanumérico const pasaporteExtRegex = /^[A-Z0-9]{7,9}$/; if (!pasaporteExtRegex.test(pasaporte)) return false; // 3. No confundir con DNI y formatos similares if (/^\d{8}$/.test(pasaporte)) return false; if (/^\d{7}[A-Z]$/.test(pasaporte)) return false; if (/^\d{8}[A-Z]$/.test(pasaporte)) return false; // 4. No confundir con NIE o CIF if (/^[A-Z]\d{7}[A-Z]$/.test(pasaporte)) { // Si primera letra es X, Y, Z (NIE) o letras de CIF const primeraLetra = pasaporte.charAt(0); if ('XYZ'.includes(primeraLetra)) return false; if ('ABCDEFGHJKLMNPQRSUVW'.includes(primeraLetra) && validarCIF(pasaporte)) return false; } // 5. Otros casos especiales if (/^\d{9}$/.test(pasaporte)) { const primeros8 = pasaporte.substring(0, 8); if (/^[0-7]\d{7}$/.test(primeros8)) return false; } return true; } /** * Obtener nombre descriptivo del tipo de documento */ function getTipoDocumentoNombre(tipo) { switch(tipo) { case 'DNI_ESP': return 'DNI español'; case 'NIE_ESP': return 'NIE'; case 'pasaporte_ESP': return 'Pasaporte español'; case 'CIF_ESP': return 'CIF de empresa española'; case 'VAT_EU': return 'VAT Number europeo'; case 'NIF_PT': return 'NIF portugués'; case 'CF_IT': return 'Codice Fiscale italiano'; case 'CNI_FR': return 'Carte d\'identité francesa'; case 'NINO_UK': return 'National Insurance Number británico'; case 'pasaporte_extranjero': return 'Pasaporte extranjero'; default: return 'Documento válido'; } } // Iniciar validador en caso de que el evento DOMContentLoaded ya haya ocurrido if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(inicializarValidador, 1); }

Los más vendidos

Separadores de rodamientos Separadores de rodamientos 2
  • Nuevo
Consultar entrega.
Accesorios

Separadores de rodamientos

Helya
STDI92
4,00 €
Separadores de 10 mm fabricados en aluminio. Minimiza el bamboleo y el agotamiento de los rodamientos. Para ejes de patines de 7 mm. Precio: (8 unidades)
Aceite ISB para Rodamientos
  • Nuevo
Consultar entrega.
Accesorios En Línea

Aceite ISB para Rodamientos

ISB
30.201
3,50 €
Lubricante de alto rendimiento. Aceite para rodamientos. Botella de 10 ml.
RODAMIENTOS ABEC 9 BLACK/BLUE RS ISB - 8 mm RODAMIENTOS ABEC 9 BLACK/BLUE RS ISB - 8 mm 2
  • Nuevo
Consultar entrega.
35,00 €
Rodamientos 608-2RS Abec 9 Black Inner RS Blue ISB Aros de color negro, con tratamiento Black Oxyde Coating Lubricación: Grasa Mobile 2RS: Junta de goma (tapas) a ambos lados del rodamiento Tapas color azul Precisión ABEC 9 Conjunto de 16 rodamientos + 4 UNIDADES GRATIS Medidas: Interior: 8 mm Exterior: 22 mm...
Aceite KOMPLEX Aceite KOMPLEX 2
  • Nuevo
Consultar entrega.
Accesorios

Aceite KOMPLEX

Komplex
40102
4,50 €
Aceite de KOMPLEX para rodamientos. Botella de 10 ml. de capacidad, dosificador y con tapa de seguridad.
Suspensiones KOMPLEX Silver 016 Suspensiones KOMPLEX Silver 016 2
  • Nuevo
Consultar entrega.
Artístico

Suspensiones KOMPLEX Silver 016

Komplex
40051
19,00 €
Las suspensión de KOMPLEX garantizan una excelente estabilidad con buena respuesta elástica. El juego de suspensiones está formado por 4 suspensiones inferiores y 4 superiores. La 1ª opción es para un peso inferior a 30 kg. La 2ª es de 30 hasta 55 kg. La 3ª es de 55 hasta 70 kg. La 4ª a partir de 70 kg.
Juego de ruedas KOMPLEX FELIX  Ø57
  • Nuevo
Consultar entrega.
Caja 8 Ruedas

Juego de ruedas KOMPLEX FELIX Ø57

Komplex
40012
23,50 €
Caja con 8 ruedas. Ruedas FELIX 52 para principiantes o nivel medio. Moldeado por inyección en poliuretano. Superficie: madera y cemento liso. Dureza: HD 52. Diámetro: 57 mm.
Frenos KOMPLEX PINK Frenos KOMPLEX PINK 2
  • Nuevo
Consultar entrega.
En Línea

Frenos KOMPLEX PINK

Komplex
40036
21,00 €
Set de 2 frenos KOMPLEX PINX SUPER REBOUND. Consumo: 3,5 Agarre: 4,5 Elasticidad: 4,5
Juego de ruedas KOMPLEX IRIS  Ø57 Juego de ruedas KOMPLEX IRIS  Ø57 2
  • Nuevo
Consultar entrega.
Caja 8 Ruedas

Juego de ruedas KOMPLEX IRIS Ø57

Komplex
40011
20,00 €
Caja con 8 ruedas. Rueda IRIS diseñada para principiantes. Superficie: madera y cemento liso. Dureza:HD 52/53. Diámetro: 57 mm.
Ruedas sueltas KOMPLEX BOLERO Ruedas sueltas KOMPLEX BOLERO 2
  • Nuevo
Consultar entrega.
Caja 8 Ruedas

Ruedas sueltas KOMPLEX BOLERO

Komplex
40021.1
7,25 €
Ruedas Bi-Component con formidable Grip y muy buena suavidad para Patinadores de Grupos de Danza y Show, expresamente diseñadas para superficies extremadamente resbaladizas. Diámetro de 63 mm. y perfil medio. Durezas: HD 38: Parquet, madera muy resbaladiza. HD 40: Parquet, madera muy resbaladiza. HD 43: Parquet, madera resbaladiza, cemento...
Frenos KOMPLEX AVANA Frenos KOMPLEX AVANA 2
  • Nuevo
Consultar entrega.
En Línea

Frenos KOMPLEX AVANA

Komplex
40033
21,00 €
Set de dos frenos modelo AVANA fabricados en goma natural. El freno ofrece una buena respuesta elástica, un buen agarre y una óptima duración. Tornillo forrado en aluminio de alta resistencia. Diseño especialmente estudiado para aumentar la superficie de apoyo. Consumo: 3,5 Agarre: 3,5 Elasticidad: 3
Ruedas sueltas KOMPLEX TANGO Ø63 Ruedas sueltas KOMPLEX TANGO Ø63 2
  • Nuevo
Consultar entrega.
Ruedas Sueltas

Ruedas sueltas KOMPLEX TANGO Ø63

Komplex
40023.1
9,60 €
Ruedas Tango de Komplex: Excelencia en Patinaje Artístico Excelencia en Patinaje Artístico Explora las ruedas Tango de Komplex, perfectas para patinadores artísticos que buscan el mejor rendimiento. Disponibles en diferentes niveles de dureza, estas ruedas están diseñadas para proporcionar un excelente agarre y...
Caja para rodamientos Caja para rodamientos 2
  • Nuevo
Consultar entrega.
Accesorios

Caja para rodamientos

Helya
9004
0,50 €
· Caja de polímero trasparente con tapa abatible. · Capacidad para un juego completo (16 unidades) Rodamientos no incluidos.
Product added to wishlist
Product added to compare.