/**
* Ciudad dependiente de Provincia — Releasit COD Form
* ----------------------------------------------------
* Convierte el campo de texto libre "Ciudad" del formulario Releasit
* en un desplegable con autocompletado, filtrado según la Provincia
* que el cliente ya haya elegido.
*
* Probado en vivo contra el formulario real de la tienda
* (campos con id="province_country_field" e id="city").
*
* Fuente de datos: dataset abierto de municipios de España (INE),
* mantenido por CodeForSpain, vía CDN de jsDelivr (con CORS habilitado).
* https://github.com/codeforspain/ds-organizacion-administrativa
*
* INSTALACIÓN
* -----------
* 1. Ve a Shopify Admin → Tienda online → Temas → (tu tema) → Editar código.
* 2. Abre "layout/theme.liquid".
* 3. Pega este script justo antes de la etiqueta de cierre
,
* envuelto en una etiqueta
*
* 4. Guarda. No requiere ninguna configuración adicional dentro de Releasit.
*
* Si en algún momento cambian los ids de los campos en el formulario de
* Releasit (por una actualización de la app), solo hay que actualizar las
* dos constantes PROVINCE_SELECT_ID y CITY_INPUT_ID de abajo.
*/
(function () {
'use strict';
// ids reales del formulario Releasit, confirmados en vivo
var PROVINCE_SELECT_ID = 'province_country_field';
var CITY_INPUT_ID = 'city';
// Traduce el texto exacto que usa el select de Provincia de Releasit
// a su código INE, para poder buscar sus municipios.
var PROVINCE_NAME_TO_INE = {
'A Coruña': '15', 'Albacete': '02', 'Alicante': '03', 'Almeria': '04',
'Araba': '01', 'Asturias': '33', 'Ávila': '05', 'Badajoz': '06',
'Barcelona': '08', 'Bizkaia': '48', 'Burgos': '09', 'Caceres': '10',
'Cádiz': '11', 'Cantabria': '39', 'Castellón': '12', 'Ciudad Real': '13',
'Córdoba': '14', 'Cuenca': '16', 'Gipuzkoa': '20', 'Girona': '17',
'Granada': '18', 'Guadalajara': '19', 'Huelva': '21', 'Huesca': '22',
'Jaén': '23', 'La Rioja': '26', 'Léon': '24', 'Lleida': '25', 'Lugo': '27',
'Madrid': '28', 'Málaga': '29', 'Murcia': '30', 'Navarra': '31',
'Ourense': '32', 'Palencia': '34', 'Pontevedra': '36', 'Salamanca': '37',
'Segovia': '40', 'Sevilla': '41', 'Soria': '42', 'Tarragona': '43',
'Teruel': '44', 'Toledo': '45', 'Valencia': '46', 'Valladolid': '47',
'Zamora': '49', 'Zaragoza': '50'
};
var MUNICIPIOS_URL =
'https://cdn.jsdelivr.net/gh/codeforspain/ds-organizacion-administrativa@master/data/municipios.json';
var municipiosPorProvincia = null;
var municipiosPromise = null;
function cargarMunicipios() {
if (municipiosPromise) return municipiosPromise;
municipiosPromise = fetch(MUNICIPIOS_URL)
.then(function (r) { return r.json(); })
.then(function (data) {
var agrupado = {};
data.forEach(function (m) {
if (!agrupado[m.provincia_id]) agrupado[m.provincia_id] = [];
agrupado[m.provincia_id].push(m.nombre);
});
Object.keys(agrupado).forEach(function (k) {
agrupado[k].sort(function (a, b) { return a.localeCompare(b, 'es'); });
});
municipiosPorProvincia = agrupado;
return agrupado;
})
.catch(function (err) {
console.error('No se pudo cargar el listado de municipios de España:', err);
return {};
});
return municipiosPromise;
}
// "Acebeda, La" -> "Acebeda La" (formato natural, igual que en el
// formulario de referencia)
function formatear(nombre) {
return nombre.replace(/, (La|El|Las|Los)$/, ' $1');
}
// Forma correcta de fijar el valor de un input controlado por React
// para que su estado interno (y la validación del formulario) se
// actualicen igual que si el cliente hubiera escrito el valor.
function setReactInputValue(input, value) {
var nativeSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype, 'value'
).set;
nativeSetter.call(input, value);
input.dispatchEvent(new Event('input', { bubbles: true }));
input.dispatchEvent(new Event('change', { bubbles: true }));
}
function crearListaDesplegable() {
var lista = document.createElement('div');
lista.className = 'ciudad-autocomplete-lista';
Object.assign(lista.style, {
position: 'absolute',
zIndex: '9999',
background: '#fff',
border: '1px solid #ccc',
borderRadius: '4px',
maxHeight: '220px',
overflowY: 'auto',
boxShadow: '0 4px 10px rgba(0,0,0,0.12)',
display: 'none',
fontFamily: 'inherit'
});
document.body.appendChild(lista);
return lista;
}
function posicionarLista(lista, input) {
var rect = input.getBoundingClientRect();
lista.style.left = (rect.left + window.scrollX) + 'px';
lista.style.top = (rect.bottom + window.scrollY) + 'px';
lista.style.width = rect.width + 'px';
}
function mostrarOpciones(lista, cityInput, opciones) {
lista.innerHTML = '';
if (!opciones.length) {
lista.style.display = 'none';
return;
}
opciones.slice(0, 200).forEach(function (nombreCrudo) {
var nombre = formatear(nombreCrudo);
var item = document.createElement('div');
item.textContent = nombre;
Object.assign(item.style, {
padding: '8px 12px',
cursor: 'pointer',
fontSize: '14px'
});
item.addEventListener('mouseenter', function () { item.style.background = '#f0f0f0'; });
item.addEventListener('mouseleave', function () { item.style.background = '#fff'; });
// mousedown (no click) para que dispare antes del blur del input
item.addEventListener('mousedown', function (e) {
e.preventDefault();
setReactInputValue(cityInput, nombre);
lista.style.display = 'none';
});
lista.appendChild(item);
});
posicionarLista(lista, cityInput);
lista.style.display = 'block';
}
function inicializarCampos(provinceSelect, cityInput) {
if (cityInput.dataset.ciudadAutocompleteInit) return;
cityInput.dataset.ciudadAutocompleteInit = '1';
var lista = crearListaDesplegable();
cityInput.setAttribute('autocomplete', 'off');
function provinciaActualId() {
return PROVINCE_NAME_TO_INE[provinceSelect.value] || null;
}
function actualizarPlaceholder() {
cityInput.placeholder = provinciaActualId() ? 'Ciudad' : 'Elige primero tu provincia';
}
actualizarPlaceholder();
provinceSelect.addEventListener('change', function () {
setReactInputValue(cityInput, '');
actualizarPlaceholder();
lista.style.display = 'none';
});
cityInput.addEventListener('input', function () {
var provId = provinciaActualId();
if (!provId) { lista.style.display = 'none'; return; }
cargarMunicipios().then(function (datos) {
var todas = datos[provId] || [];
var texto = cityInput.value.trim().toLowerCase();
var filtradas = texto
? todas.filter(function (n) { return formatear(n).toLowerCase().indexOf(texto) !== -1; })
: todas;
mostrarOpciones(lista, cityInput, filtradas);
});
});
cityInput.addEventListener('focus', function () {
var provId = provinciaActualId();
if (!provId) return;
cargarMunicipios().then(function (datos) {
mostrarOpciones(lista, cityInput, datos[provId] || []);
});
});
document.addEventListener('click', function (e) {
if (e.target !== cityInput) lista.style.display = 'none';
});
window.addEventListener('scroll', function () {
if (lista.style.display === 'block') posicionarLista(lista, cityInput);
}, true);
// Precarga el listado de municipios en segundo plano
cargarMunicipios();
}
function buscarEInicializar() {
var provinceSelect = document.getElementById(PROVINCE_SELECT_ID);
var cityInput = document.getElementById(CITY_INPUT_ID);
if (provinceSelect && cityInput) {
inicializarCampos(provinceSelect, cityInput);
}
}
function observarFormulario() {
// El formulario de Releasit se inserta dinámicamente (popup),
// así que vigilamos el DOM hasta que aparezca.
var observer = new MutationObserver(buscarEInicializar);
observer.observe(document.body, { childList: true, subtree: true });
buscarEInicializar(); // por si ya está presente al cargar
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', observarFormulario);
} else {
observarFormulario();
}
})();