PageSourceSearch

https://cdn.milar.es/estaticos/js/Milar/header.js?2026091601

js milar.es collected 2026-09-30 21:48:28 UTC 10,591 bytes, 291 lines download raw bytes

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.