1// ââ Result code constants for the processSocialMediaLogin AJAX endpoint ââââââââââ 2 3const SOCIAL_LOGIN_RESULT_KEY = 'RESULT'; 4const SOCIAL_LOGIN_EMAIL_ERROR = 'EMAIL_ERROR'; 5const SOCIAL_LOGIN_EMAIL_EXISTENTE = 'EXISTING_EMAIL'; 6const SOCIAL_LOGIN_GENERIC_ERROR = 'GENERIC_ERROR'; 7 8// ââ Google Sign-In ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 9 10/** 11 * Starts the Google Auth2 sign-in flow for the header modal button (#milar-modal-google-btn). 12 * Called on DOMContentLoaded â gapi is available at that point because the SDK 13 * is a synchronous script tag loaded earlier in the page. 14 * No-op if the button or gapi are unavailable. 15 */ 16function startAppModal() { 17 const btn = document.getElementById('milar-modal-google-btn'); 18 if (!btn || !window.gapi) { 19 return; 20 } 21 const config = window.socialLoginConfig || {}; 22 gapi.load('auth2', function () { 23 const auth2Modal = gapi.auth2.init({ 24 client_id: config.googleClientId || '', 25 cookiepolicy: 'single_host_origin' 26 }); 27 attachSigninModal(btn, auth2Modal); 28 }); 29} 30 31/** 32 * Attaches the Google sign-in click handler to the given button element. 33 * Disables the button while the AJAX call is in flight; re-enables it on completion. 34 * On success, reloads the current page. 35 * 36 * @param {HTMLElement} element - The button to attach the handler to 37 * @param {object} auth2Modal - The gapi.auth2 instance 38 */ 39function attachSigninModal(element, auth2Modal) { 40 if (!element) { 41 return; 42 } 43 const config = window.socialLoginConfig || {}; 44 auth2Modal.attachClickHandler(element, {}, 45 function (googleUser) { 46 element.disabled = true; 47 const profile = googleUser.getBasicProfile(); 48 const dataString = 'metodoAction=processSocialMediaLogin' 49 + '&email=' + profile.getEmail() 50 + '&surname=' + profile.getFamilyName() 51 + '&forename=' + profile.getGivenName(); 52 53 const request = new XMLHttpRequest(); 54 request.open('POST', '/contenedorMetodosAjax.do', true); 55 request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 56 request.send(dataString); 57 request.onreadystatechange = function () { 58 if (request.readyState !== 4) { 59 return; 60 } 61 element.disabled = false; 62 if (request.status >= 200 && request.status < 400) { 63 const response = JSON.parse(request.response); 64 if (response[SOCIAL_LOGIN_RESULT_KEY] === SOCIAL_LOGIN_EMAIL_EXISTENTE) { 65 alert(config.emailAlreadyRegisteredMsg || 'El correo ya está registrado.'); 66 } else if (response[SOCIAL_LOGIN_RESULT_KEY] === SOCIAL_LOGIN_EMAIL_ERROR) { 67 alert('No se ha facilitado ningún correo electrónico'); 68 } else if (response[SOCIAL_LOGIN_RESULT_KEY] === SOCIAL_LOGIN_GENERIC_ERROR) { 69 alert('Error iniciando sesión con Google.'); 70 } else { 71 location.reload(); 72 } 73 } else { 74 alert('Se ha producido un error. Si vuelve a ocurrir, puede contactar con Atención al Cliente'); 75 } 76 }; 77 }, 78 function () { 79 // User cancelled or sign-in error â re-enable the button 80 element.disabled = false; 81 } 82 ); 83} 84 85// ââ Facebook Sign-In ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 86 87/** 88 * Initiates the Facebook login flow from the header modal. 89 * Called by onclick="fbModalLogin()" on the #milar-modal-fb-btn element. 90 */ 91function fbModalLogin() { 92 FB.login(function (response) { 93 if (response.authResponse) { 94 processFbMilarModalUserData(); 95 } 96 }, {scope: 'email'}); 97} 98 99/** 100 * Fetches the Facebook user profile and calls the processSocialMediaLogin backend endpoint. 101 * Disables the button while the AJAX call is in flight; re-enables it on completion. 102 * On success, reloads the current page. 103 */ 104function processFbMilarModalUserData() { 105 const fbBtn = document.getElementById('milar-modal-fb-btn'); 106 const config = window.socialLoginConfig || {}; 107 FB.api('/me', {locale: 'es_ES', fields: 'first_name,last_name,email'}, 108 function (response) { 109 if (fbBtn) { 110 fbBtn.disabled = true; 111 } 112 const dataString = 'metodoAction=processSocialMediaLogin' 113 + '&email=' + response.email 114 + '&surname=' + response.last_name 115 + '&forename=' + response.first_name; 116 117 $.ajax({ 118 type: 'POST', 119 url: '/contenedorMetodosAjax.do', 120 data: dataString, 121 success: function (resp) { 122 if (fbBtn) { 123 fbBtn.disabled = false;
124 } 125 const parsed = JSON.parse(resp); 126 if (parsed[SOCIAL_LOGIN_RESULT_KEY] === SOCIAL_LOGIN_EMAIL_EXISTENTE) { 127 alert(config.emailAlreadyRegisteredMsg || 'El correo ya está registrado.'); 128 } else if (parsed[SOCIAL_LOGIN_RESULT_KEY] === SOCIAL_LOGIN_EMAIL_ERROR) { 129 alert('No se ha facilitado ningún correo electrónico'); 130 } else if (parsed[SOCIAL_LOGIN_RESULT_KEY] === SOCIAL_LOGIN_GENERIC_ERROR) { 131 alert('Error iniciando sesión con Facebook.'); 132 } else { 133 location.reload(); 134 } 135 }, 136 error: function () { 137 if (fbBtn) { 138 fbBtn.disabled = false; 139 } 140 alert('Se ha producido un error. Si vuelve a ocurrir, puede contactar con Atención al Cliente'); 141 } 142 }); 143 } 144 ); 145} 146 147// ââ "Usar mi ubicación" Button ââââââââââââââââââââââââââââââââââââââââââââââââââââ 148 149/** 150 * Initialises the "Usar mi ubicación" button inside the Milar zip-code modal. 151 * 152 * On click, tries to resolve the delivery zip code using GPS coordinates. 153 * Primary path uses woosmapGeo (IP-based); falls back to updateZipCodeByGeolocation 154 * (GPS coords). Reloads on success; shows an inline error in #modal_zip_code_error_id 155 * if location cannot be resolved. 156 * 157 * No-op if the #milar-use-location element is not present in the DOM. 158 */ 159function initLocationButtonMilar() { 160 const locBtn = document.getElementById('milar-use-location'); 161 if (!locBtn) { 162 return; 163 } 164 165 /** 166 * Toggles the loading state of the location button. 167 * @param {boolean} isLoading - True to show loading, false to restore 168 */ 169 function setLoading(isLoading) { 170 locBtn.disabled = isLoading; 171 locBtn.style.opacity = isLoading ? '0.6' : ''; 172 } 173 174 /** 175 * Shows an error message in the modal error element (#modal_zip_code_error_id). 176 * @param {string} msg - The message to display 177 */ 178 function showErrorZipCodeNotFound(msg) { 179 const errorEl = document.getElementById('modal_zip_code_error_id'); 180 if (errorEl) { 181 errorEl.textContent = msg; 182 } 183 } 184 185 locBtn.addEventListener('click', function () { 186 if (!('geolocation' in navigator)) { 187 showErrorZipCodeNotFound('Tu navegador no permite obtener la ubicación. Introduce el código postal manualmente.'); 188 return; 189 } 190 191 setLoading(true); 192 193 navigator.geolocation.getCurrentPosition( 194 // GPS success: resolve zip code via woosmapGeo, with coords fallback 195 function (position) { 196 const lat = position.coords.latitude; 197 const lng = position.coords.longitude; 198 199 /** 200 * Fallback: resolves zip code via updateZipCodeByGeolocation using GPS coords. 201 * Reloads on success; shows an inline error if the endpoint returns no zip. 202 */ 203 function resolveWithCoords() { 204 fetch('contenedorMetodosAjax.do?metodoAction=updateZipCodeByGeolocation&lat=' + lat + '&lng=' + lng, {method: 'POST'}) 205 .then(function (response) { 206 return response.text(); 207 }) 208 .then(function (text) { 209 setLoading(false); 210 const res = (text ? JSON.parse(text)['ok'] : '') || ''; 211 if (res) { 212 window.dataLayer = window.dataLayer || []; 213 window.dataLayer.push({'event': 'geolocation', 'Location': res}); 214 location.reload(); 215 } else { 216 showErrorZipCodeNotFound('No hemos podido determinar tu código postal. Introdúcelo manualmente.'); 217 } 218 }) 219 .catch(function () { 220 setLoading(false); 221 showErrorZipCodeNotFound('Se ha producido un error obteniendo tu ubicación. Introdúcela manualmente.'); 222 }); 223 } 224 225 /** 226 * Primary path: resolves zip code via woosmapGeo using the public IP. 227 * Falls back to resolveWithCoords() if woosmapGeo returns no zip. 228 * @param {string} ip - The resolved public IP address 229 */ 230 function resolveWithIp(ip) { 231 fetch('contenedorMetodosAjax.do?metodoAction=woosmapGeo&ip=' + encodeURIComponent(ip), {method: 'POST'}) 232 .then(function (response) { 233 return response.text(); 234 }) 235 .then(function (text) { 236 const res = (text ? JSON.parse(text)['ok'] : '') || ''; 237 if (res) {
238 setLoading(false); 239 window.dataLayer = window.dataLayer || []; 240 window.dataLayer.push({'event': 'geolocation', 'Location': res}); 241 location.reload(); 242 } else { 243 // woosmapGeo returned no zip â fall back to GPS coords 244 resolveWithCoords(); 245 } 246 }) 247 .catch(function () { 248 // woosmapGeo request failed â fall back to GPS coords 249 resolveWithCoords(); 250 }); 251 } 252 253 const ip = (typeof IP !== 'undefined' && IP) ? IP : ''; 254 if (ip) { 255 resolveWithIp(ip); 256 } else { 257 // IP not yet available â fetch it from ipify, then resolve 258 fetch('https://api.ipify.org?format=json') 259 .then(function (response) { 260 return response.json(); 261 }) 262 .then(function (data) { 263 IP = data.ip; 264 resolveWithIp(IP); 265 }) 266 .catch(function (error) { 267 // Could not obtain IP â fall back directly to GPS coords 268 console.error('Error al obtener la dirección IP:', error); 269 resolveWithCoords(); 270 }); 271 } 272 }, 273 // GPS error: permission denied, timeout, unavailable 274 function (error) { 275 setLoading(false); 276 if (error.code === error.PERMISSION_DENIED) { 277 showErrorZipCodeNotFound('Has bloqueado el acceso a tu ubicación. Introduce el código postal manualmente.'); 278 } else { 279 showErrorZipCodeNotFound('No hemos podido obtener tu ubicación. Introduce el código postal manualmente.'); 280 } 281 },
282 {enableHighAccuracy: false, timeout: 10000, maximumAge: 60000} 283 ); 284 }); 285} 286 287// ââ Event Listener Registration âââââââââââââââââââââââââââââââââââââââââââââââââââ 288 289document.addEventListener('DOMContentLoaded', startAppModal, false); 290document.addEventListener('DOMContentLoaded', initLocationButtonMilar, false); 291
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.