PageSourceSearch

https://www.habitare-pamplona.com/assets/js/base.js?v=0.9

js habitare-pamplona.com collected 2026-10-08 13:25:07 UTC 42,000 bytes, 1,611 lines download raw bytes

1/**
2 * Compruebo si por alguna razon la variable global de traducciones no esta disponible. Si
3 * ese es el caso, entonces se procede a intentar tomarlo del local storage.
4 * Si el local storage no contiene las traducciones, entonces se procede a solicitarlo por una peticion sincrona
5 */
6
7
8var textos_traducciones = window.textos_traducciones
9
10var global_slugs = window.global_slugs
11
12;(function configureActionRequests($) {
13	if (!$ || typeof $.ajaxPrefilter !== 'function') {
14		return;
15	}
16	$.ajaxPrefilter(function (options, originalOptions, xhr) {
17		try {
18			let target = new URL(options.url || originalOptions.url || '', window.location.href);
19			let method = String(options.type || originalOptions.type || 'GET').toUpperCase();
20			if (target.origin !== window.location.origin || method !== 'POST' || target.pathname.indexOf('/action/') === -1) {
21				return;
22			}
23			let meta = document.querySelector('meta[name="csrf-token"]');
24			let token = meta ? meta.getAttribute('content') : '';
25			if (/^[a-f0-9]{64}$/.test(token)) {
26				xhr.setRequestHeader('X-CSRF-Token', token);
27			}
28			// Legacy themes/CMS parse JSON themselves and expect response text.
29			// Keep that contract until each consumer declares its dataType (P14).
30			// Explicit JSON/HTML and requests outside Myweb actions stay unchanged.
31			if (/^\/(?:[a-z]{2}\/)?action\/[a-z0-9_]+\/?$/i.test(target.pathname)
32				&& options.dataTypes.length === 1 && options.dataTypes[0] === '*') {
33				return 'text';
34			}
35		} catch (error) {
36			// A malformed URL remains untouched and will be rejected by the request layer.
37		}
38	});
39})(window.jQuery);
40
41if (empty(window.textos_traducciones)) {
42
43	console.error("No existe traducciones global");
44
45	window.textos_traducciones = localStorage.getItem('traducciones_' + get_lang());
46
47	if (typeof (window.textos_traducciones) === "string") {
48		window.textos_traducciones = JSON.parse(window.textos_traducciones);
49	}
50
51	if (empty(window.textos_traducciones)) {
52		console.log("hago peticion asyncrona contra traducciones");
53		get_textos_traducciones();
54	}
55}
56
57// Forzar la inicializacion de los name by lang controller
58get_name_controller_by_lang('property');
59
60class Myweb {
61
62	static hooks = {};
63
64	static add_hook(target_name, name_func) {
65
66		const func = window[name_func];
67
68		if (typeof func === 'function') {
69			this.hooks[target_name] = func;
70		}
71	}
72
73	static add_grip(name_grip, data) {
74
75		const func = this.hooks[name_grip];
76
77		if (typeof func === 'function') {
78
79			func(data);
80		}
81	}
82}
83
84/**
85 * Set global translations
86 * @returns {void}
87 */
88function get_textos_traducciones() {
89	$.ajax({
90		type: 'POST',
91		async: false,
92		url: get_base_url() + '/' + get_lang() + '/action/get_t',
93		success: function (result) {
94			window.textos_traducciones = result;
95			localStorage.setItem('traducciones_' + get_lang(), result);
96		}
97	});
98}
99
100/**
101 * Get the base url of the web
102 * @returns {string}
103 */
104function get_base_url() {
105	return '//' + window.location.host;
106}
107
108/**
109 * Get the translate of a string
110 * @param {string} letter
111 * @param {object} opt
112 * @returns {string}
113 */
114function T(letter, opt = {}) {
115
116	let texto = '';
117
118	letter = letter.toUpperCase();
119	letter = letter.normalize("NFD").replace(/[\u0300-\u036f]/g, '');
120
121	letter = replaceAll_adapted_explorer(letter, " ", "_");
122
123	if (empty(window.textos_traducciones) || empty(window.textos_traducciones[letter])) {
124		console.log("No existe traduccion: " + letter);
125		texto = letter;
126	} else {
127		texto = window.textos_traducciones[letter];
128
129		if (Object.keys(opt).length > 0) {
130			if (opt["param1"] !== undefined) {
131				texto = texto.replace("%1", opt["param1"]);
132			}
133			if (opt["param2"] !== undefined) {
134				texto = texto.replace("%2", opt["param2"]);
135			}
136			if (opt["param3"] !== undefined) {
137				texto = texto.replace("%3", opt["param3"]);
138			}
139		}
140	}
141
142	return texto;
143}
144
145/**
146 * Get a object with locale data
147 * @returns {object}
148 */
149function get_locale() {
150	let data_separator = {};
151	switch (get_lang()) {
152		case "en":
153			data_separator.separador_miles = ",";
154			data_separator.separador_decimal = ".";
155			data_separator.user_lang = "en_GB";
156			break;
157		case "eu":
158			data_separator.separador_miles = ".";
159			data_separator.separador_decimal = ",";
160			data_separator.user_lang = "eu_ES";
161			break;
162		case "ca":
163			data_separator.separador_miles = ".";
164			data_separator.separador_decimal = ",";
165			data_separator.user_lang = "ca_ES";
166			break;
167		case "fr":
168			data_separator.separador_miles = " ";
169			data_separator.separador_decimal = ",";
170			data_separator.user_lang = "fr_FR";
171			break;
172		default:
173			data_separator.separador_miles = ".";
174			data_separator.separador_decimal = ",";
175			data_separator.user_lang = "es_ES";
176	}
177
178	return data_separator;
179}
180
181/**
182 * Clean image url
183 * @param {string} path
184 * @returns {string}
185 */
186function clean_image_path(path) {
187	//Replace URL
188	if (empty(path)) {
189
190		path = document.documentElement.dataset.medefault ?? '';
191
192		if (empty(path)) {
193			path = '/assets/images/no-photo.png';
194		}
195
196		return path;
197	}
198
199	path = replaceAll_adapted_explorer(path, ' ', '%20');
200	path = path.replace('https:', '');
201	path = path.replace('http:', '');
202	path = path.replace('//img.pruebas-inmotek.net', '');
203	path = path.replace('//img.inmotek.net', '');
204
205	if (path == '') {
206		path = document.documentElement.dataset.medefault ?? '';
207
208		if (path == '') {
209			path = '/assets/images/no-photo.png';
210		}
211	}
212
213	return path;
214}
215
216/**
217 * Format Number by locale
218 * @param {number} number
219 * @returns {string}
220 */
221function formatNumber(number, locale = 'es-ES') {
222	if (isNaN(number)) {
223		return 0;
224	}
225
226	// Convert the input to a float
227	number = parseFloat(number.toString());
228
229	// Use Intl.NumberFormat for formatting
230	return new Intl.NumberFormat(locale, {
231		minimumFractionDigits: 0,
232		maximumFractionDigits: 0
233	}).format(number);
234}
235
236/**
237 * Get clean text of tag
238 * @param {string} html
239 * @returns {string}
240 */
241function stripHtml(html) {
242	const temporalDivElement = document.createElement('div');
243	temporalDivElement.innerHTML = html;
244	return temporalDivElement.textContent || temporalDivElement.innerText || '';
245}
246
247/**
248 * Format a phone
249 * @param {number} phone
250 * @returns {string}
251 */
252function format_phone(phone) {
253	if (empty(phone)) {
254		return '';
255	}
256
257	let new_phone = phone.toString()
258
259	const len = new_phone.length;
260	const last = new_phone.substr(len - 3, 3);
261	const med = new_phone.substr(len - 6, 3);
262	const first = new_phone.substr(len - 9, 3);
263	if (len > 9) {
264		let extra = new_phone.substr(0, len - 9);
265		return extra + ' ' + first + ' ' + med + ' ' + last;
266	}
267	else if (len == 3) {
268		return last;
269	}
270	else {
271		return first + ' ' + med + ' ' + last;
272	}
273}
274
275/**
276 * Format a date
277 * @param {string} date
278 * @param {boolean} mysql_format
279 * @returns {string}
280 */
281function format_date(date, mysql_format) {
282	let d = new Date(date),
283		month = '' + (d.getMonth() + 1),
284		day = '' + d.getDate(),
285		year = d.getFullYear();
286
287	let h = d.getHours().toString();
288	let m = d.getMinutes().toString();
289	let s = d.getSeconds().toString();
290
291	if (month.length < 2)
292		month = '0' + month;
293	if (day.length < 2)
294		day = '0' + day;
295	if (h.length < 2)
296		h = '0' + h;
297	if (m.length < 2)
298		m = '0' + m;
299	if (s.length < 2)
300		s = '0' + s;
301
302	if (mysql_format) {
303		return [year, month, day].join('-');
304	} else {
305		return [day, month, year].join('-');
306	}
307}
308
309/**
310 * Get the name of controller by lang selected
311 * @param {string} nameController
312 * @param {string} selected_lang
313 * @returns {string}
314 */
315function get_name_controller_by_lang(nameController, selected_lang = "") {
316
317	let lang = '';
318
319	if (nameController === "custom") {
320		nameController = get_custom_pagename();
321	}
322
323	if (empty(selected_lang)) {
324		lang = get_lang();
325	} else {
326		lang = selected_lang;
327	}
328
329	let name_controllers_slugs = [];
330
331	if (window.global_slugs != null && window.global_slugs != undefined) {
332
333		name_controllers_slugs = global_slugs;
334
335		if (name_controllers_slugs[nameController] === undefined ||
336			name_controllers_slugs[nameController][lang] === undefined) {
337			console.log("NO EXISTE: " + nameController + " CON " + lang);
338		}
339
340	} else if (getCookie("slugs")) {
341
342		name_controllers_slugs = JSON.parse(getCookie("slugs"));
343
344		if (empty(name_controllers_slugs)) {
345			console.log("El name_controllers_slug es undefinido en " + lang + " para " + nameController);
346			return "inicio";
347		}
348
349		if (empty(name_controllers_slugs[nameController])) {
350			console.log("Warning: No existe lang de " + lang + " para " + nameController);
351			return "inicio";
352		}
353
354		if (empty(name_controllers_slugs[nameController][lang])) {
355			console.log("Warning: No existe lang de " + lang + " para " + nameController);
356			return "inicio";
357		}
358
359	} else {
360
361		$.ajax({
362			type: 'POST',
363			async: false,
364			url: get_base_url() + '/' + get_lang() + '/action/get_slugs',
365			success: function (result) {
366
367				setCookie("slugs", result, 2)
368
369				name_controllers_slugs = JSON.parse(result)
370
371				if (empty(name_controllers_slugs)) {
372					console.log("El name_controllers_slug es undefinido en " + lang + " para " + nameController)
373					return "inicio"
374				}
375
376				if (empty(name_controllers_slugs[nameController])) {
377					console.log("Warning: No existe lang de " + lang + " para " + nameController)
378					return "inicio";
379				}
380
381				if (empty(name_controllers_slugs[nameController][lang])) {
382					console.log("Warning: No existe lang de " + lang + " para " + nameController)
383					return "inicio"
384				}
385			}
386		})
387	}
388
389	if (empty(name_controllers_slugs[nameController])) {
390		console.log("Error slug:", nameController)
391	}
392
393	return name_controllers_slugs[nameController][lang].toLowerCase()
394}
395
396/**
397 * Get URL of controller by lang
398 * @deprecated Unused
399 * @param {string} selected_lang
400 * @returns {string}
401 */
402function get_url_by_lang(selected_lang) {
403	let path = window.location.pathname;
404	let array_path = path.split("/");
405	array_path.shift();
406	let lang = array_path.shift();
407	let menu_def = array_path.shift();
408	let end_path = array_path.join("/");
409
410	lang = selected_lang;
411
412	if (empty(menu_def)) {
413		menu_def = 'home';
414	}
415	menu_def = get_name_controller_by_lang(get_pagename(), lang);
416
417	if (end_path == '') {
418		return window.location.protocol + '//' + window.location.hostname + '/' + lang + '/' + menu_def;
419	} else {
420		return window.location.protocol + '//' + window.location.hostname + '/' + lang + '/' + menu_def + '/' + end_path;
421	}
422}
423
424/**
425 * Get the selected lang
426 * @returns {string}
427 */
428function get_lang() {
429	if (empty(document.documentElement.dataset.lang)) {
430		return 'es';
431	}
432	return document.documentElement.dataset.lang ?? '';
433}
434
435/**
436 * Get codename
437 * @returns {string}
438 */
439function get_codename() {
440	return document.documentElement.dataset.codename ?? '';
441}
442
443/**
444 * Get pagename
445 * @returns {string}
446 */
447function get_pagename() {
448	return document.documentElement.dataset.page ?? '';
449}
450
451/**
452 * Get custom page name
453 * @returns {string}
454 */
455function get_custom_pagename() {
456	return document.documentElement.dataset.cpage ?? '';
457}
458
459/**
460 * Get name primary color
461 * @returns {string}
462 */
463function get_name_color() {
464	return document.documentElement.dataset.colorp ?? '';
465}
466
467/**
468 * Get name alternative color
469 * @returns {string}
470 */
471function get_name_alternative_color() {
472	return document.documentElement.dataset.colora ?? '';
473}
474
475/**
476 * Get hex primary color
477 * @returns {string}
478 */
479function get_primary_color() {
480	return document.documentElement.dataset.color1 ?? '';
481}
482
483/**
484 * Gey hex secondary color
485 * @returns {string}
486 */
487function get_secundary_color() {
488	return document.documentElement.dataset.color2 ?? '';
489}
490
491/**
492 * Get hex alternative coloe
493 * @returns {string}
494 */
495function get_alternative_color() {
496	return document.documentElement.dataset.color3 ?? '';
497}
498
499/**
500 * Find a parameter of url
501 * @param {string} parameterName
502 * @param {string} url
503 * @returns {?string}
504 */
505function findGetParameter(parameterName, url) {
506	let result = null,
507		tmp = [];
508	let items = url != undefined ? url.substr(1).split("&") : location.search.substr(1).split("&");
509	for (let index = 0; index < items.length; index++) {
510		tmp = items[index].split("=");
511		if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
512	}
513	return result;
514}
515
516/**
517 * Replace parameter of URL
518 * @param {string} url
519 * @param {string} paramName
520 * @param {string} paramValue
521 * @returns {string}
522 */
523function replaceUrlParameter(url, paramName, paramValue) {
524
525	if (isValidURL(url) === false) {
526
527		console.error("The first param of `replaceUrlParameter` is not a valid URL")
528
529		if (paramValue == null) {
530			paramValue = '';
531		}
532
533		let pattern = new RegExp('\\b(' + paramName + '=).*?(&|#|$)');
534
535		if (url.search(pattern) >= 0) {
536			return url.replace(pattern, '$1' + paramValue + '$2');
537		}
538
539		url = url.replace(/[?#]$/, '');
540
541		return url + (url.includes('?') ? '&' : '?') + paramName + '=' + paramValue;
542
543	} else {
544		// Parse the URL
545		const urlObj = new URL(url);
546
547		// Set or update the parameter
548		urlObj.searchParams.set(paramName, paramValue);
549
550		// Return the modified URL
551		return urlObj.toString();
552	}
553}
554
555/**
556 * Checks if a given string is a valid URL
557 * @param {string} str - The string to check
558 * @returns {boolean} - True if the string is a valid URL, false otherwise
559 */
560function isValidURL(str) {
561	try {
562		new URL(str);
563		return true;
564	} catch (_) {
565		return false;
566	}
567}
568
569/**
570 * Remove param of URL
571 * @param {string} url
572 * @param {string} parameter
573 * @returns {string}
574 */
575function removeURLParameter(url, parameter) {
576	//prefer to use l.search if you have a location/link object
577	var urlparts = url.split('?');
578	if (urlparts.length >= 2) {
579
580		var prefix = encodeURIComponent(parameter) + '=';
581		var pars = urlparts[1].split(/[&;]/g);
582
583		//reverse iteration as may be destructive
584		for (var i = pars.length; i-- > 0;) {
585			//idiom for string.startsWith
586			if (pars[i].lastIndexOf(prefix, 0) !== -1) {
587				pars.splice(i, 1);
588			}
589		}
590
591		return urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : '');
592	}
593	return url;
594}
595
596/**
597 * Increase the number of visits to a property listing by one
598 * @param {string} propertyCode
599 * @param {string} tracking_token
600 * @returns {void}
601 */
602function update_visit_inmotek(propertyCode, tracking_token) {
603
604	let url = ('https:' == window.location.protocol ? 'https:' : 'http:') + get_base_url();
605
606	$.post(get_base_url() + '/' + get_lang() + '/action/update_visit', {
607		property_code: propertyCode,
608		url: url,
609		tracking_token: tracking_token,
610		useragent: navigator.userAgent
611	}).done(function (result) {
612		console.log(result);
613	})
614}
615
616/**
617 * Description
618 * @param {string} cname
619 * @returns {string}
620 */
621function getCookie(cname) {
622	var name = cname + "=";
623	var decodedCookie = decodeURIComponent(document.cookie);
624	var ca = decodedCookie.split(';');
625	for (var i = 0; i < ca.length; i++) {
626		var c = ca[i];
627		while (c.charAt(0) == ' ') {
628			c = c.substring(1);
629		}
630		if (c.indexOf(name) == 0) {
631			return c.substring(name.length, c.length);
632		}
633	}
634	return ''
635}
636
637/**
638 * Description
639 * @param {any} cname
640 * @param {any} cvalue
641 * @param {any} exdays
642 * @returns {void}
643 */
644function setCookie(cname, cvalue, exdays) {
645	var d = new Date();
646	d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
647	var expires = "expires=" + d.toUTCString();
648	document.cookie = cname + "=" + cvalue + ";SameSite=Strict;" + expires + ";path=/";
649}
650
651/**
652 * Get translate of type
653 * @param {string} type 
654 * @returns {void}
655 */
656function get_type_for_translate(type) {
657	type = type.replace(' ', '_');
658	type = type.toUpperCase();
659	let name_types = [];
660
661	/** Tipos en español */
662	name_types['PISO'] = "PISO";
663	name_types['CASA'] = "CASA";
664	name_types['LOCAL'] = "LOCAL";
665	name_types['NAVE'] = "NAVE";
666	name_types['GARAJE'] = "GARAJE";
667	name_types['OFICINA'] = "OFICINA";
668	name_types['TRASTERO'] = "TRASTERO";
669	name_types['TERRENO'] = "TERRENO";
670
671	name_types['FLAT'] = "PISO";
672	name_types['HOME'] = "CASA";
673	name_types['LOCAL'] = "LOCAL";
674	name_types['INDUSTRIAL_WAREHOUSE'] = "NAVE";
675	name_types['GARAGE'] = "GARAJE";
676	name_types['OFFICE'] = "OFICINA";
677	name_types['STORAGE_ROOM'] = "TRASTERO";
678	name_types['LAND'] = "TERRENO";
679
680	return name_types[type];
681}
682
683
684/**
685 * Description
686 * @param {string} data
687 * @returns {boolean}
688 */
689function is_empty(data) {
690	if (empty(data) || data.length == 0) {
691		return true;
692	} else {
693		return false;
694	}
695}
696
697/**
698 * Parse number
699 * @param {string|number} x
700 * @param {string} sep
701 * @returns {?string}
702 */
703function numberWithCommas(x, sep) {
704	if (empty(x)) {
705		return null;
706	}
707	return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, sep);
708}
709
710/**
711 * List prices of rent minify
712 * @returns {array}
713 */
714function get_list_prices_rent_minify() {
715	let price_list =
716		[
717			{ "id": '', "value": T("SIN_LIMITE") },
718			{ "id": "500", "value": "500" },
719			{ "id": "600", "value": "600" },
720			{ "id": "700", "value": "700" },
721			{ "id": "800", "value": "800" },
722			{ "id": "900", "value": "900" },
723			{ "id": "1000", "value": "1.000" },
724			{ "id": "1100", "value": "1.100" },
725			{ "id": "1200", "value": "1.200" },
726			{ "id": "1300", "value": "1.300" },
727			{ "id": "1400", "value": "1.400" },
728			{ "id": "1500", "value": "1.500" },
729			{ "id": "1750", "value": "1.750" },
730			{ "id": "2000", "value": "2.000" },
731			{ "id": "4000", "value": "4.000" },
732			{ "id": "6000", "value": "6.000" },
733			{ "id": "8000", "value": "8.000" },
734			{ "id": "10000", "value": "10.000" }
735		];
736	return price_list;
737}
738/**
739 * List prices of rent
740 * @returns {array}
741 */
742function get_list_prices_rent() {
743	let price_list =
744		[
745			{ "id": '', "value": T("SIN_LIMITE") },
746			{ "id": "60", "value": "60" },
747			{ "id": "80", "value": "80" },
748			{ "id": "100", "value": "100" },
749			{ "id": "150", "value": "150" },
750			{ "id": "200", "value": "200" },
751			{ "id": "250", "value": "250" },
752			{ "id": "300", "value": "300" },
753			{ "id": "350", "value": "350" },
754			{ "id": "400", "value": "400" },
755			{ "id": "450", "value": "450" },
756			{ "id": "500", "value": "500" },
757			{ "id": "550", "value": "550" },
758			{ "id": "600", "value": "600" },
759			{ "id": "650", "value": "650" },
760			{ "id": "700", "value": "700" },
761			{ "id": "750", "value": "750" },
762			{ "id": "800", "value": "800" },
763			{ "id": "850", "value": "850" },
764			{ "id": "900", "value": "900" },
765			{ "id": "950", "value": "950" },
766			{ "id": "1000", "value": "1.000" },
767			{ "id": "1100", "value": "1.100" },
768			{ "id": "1200", "value": "1.200" },
769			{ "id": "1300", "value": "1.300" },
770			{ "id": "1400", "value": "1.400" },
771			{ "id": "1500", "value": "1.500" },
772			{ "id": "1600", "value": "1.600" },
773			{ "id": "1700", "value": "1.700" },
774			{ "id": "1800", "value": "1.800" },
775			{ "id": "1900", "value": "1.900" },
776			{ "id": "2000", "value": "2.000" },
777			{ "id": "2100", "value": "2.100" },
778			{ "id": "2200", "value": "2.200" },
779			{ "id": "2300", "value": "2.300" },
780			{ "id": "2400", "value": "2.400" },
781			{ "id": "2500", "value": "2.500" },
782			{ "id": "2600", "value": "2.600" },
783			{ "id": "2700", "value": "2.700" },
784			{ "id": "2800", "value": "2.800" },
785			{ "id": "2900", "value": "2.900" },
786			{ "id": "3000", "value": "3.000" },
787			{ "id": "3500", "value": "3.500" },
788			{ "id": "4000", "value": "4.000" },
789			{ "id": "4500", "value": "4.500" },
790			{ "id": "5000", "value": "5.000" },
791			{ "id": '', "value": T("SIN_LIMITE") }];
792	return price_list;
793}
794
795/**
796 * List prices of sale
797 * @returns {array}
798 */
799function get_list_prices_sale() {
800	let price_list =
801		[
802			{ "id": '', "value": T("SIN_LIMITE") },
803			{ "id": "20000", "value": "20.000" },
804			{ "id": "40000", "value": "40.000" },
805			{ "id": "60000", "value": "60.000" },
806			{ "id": "80000", "value": "80.000" },
807			{ "id": "100000", "value": "100.000" },
808			{ "id": "120000", "value": "120.000" },
809			{ "id": "140000", "value": "140.000" },
810			{ "id": "160000", "value": "160.000" },
811			{ "id": "180000", "value": "180.000" },
812			{ "id": "200000", "value": "200.000" },
813			{ "id": "220000", "value": "220.000" },
814			{ "id": "240000", "value": "240.000" },
815			{ "id": "260000", "value": "260.000" },
816			{ "id": "280000", "value": "280.000" },
817			{ "id": "300000", "value": "300.000" },
818			{ "id": "320000", "value": "320.000" },
819			{ "id": "340000", "value": "340.000" },
820			{ "id": "360000", "value": "360.000" },
821			{ "id": "380000", "value": "380.000" },
822			{ "id": "400000", "value": "400.000" },
823			{ "id": "450000", "value": "450.000" },
824			{ "id": "500000", "value": "500.000" },
825			{ "id": "550000", "value": "550.000" },
826			{ "id": "600000", "value": "600.000" },
827			{ "id": "650000", "value": "650.000" },
828			{ "id": "700000", "value": "700.000" },
829			{ "id": "750000", "value": "750.000" },
830			{ "id": "800000", "value": "800.000" },
831			{ "id": "850000", "value": "850.000" },
832			{ "id": "900000", "value": "900.000" },
833			{ "id": "950000", "value": "950.000" },
834			{ "id": "1000000", "value": T("1_MILLON") },
835			{ "id": "1100000", "value": T("1_1_MILLON") },
836			{ "id": "1200000", "value": T("1_2_MILLON") },
837			{ "id": "1300000", "value": T("1_3_MILLON") },
838			{ "id": "1400000", "value": T("1_4_MILLON") },
839			{ "id": "1500000", "value": T("1_5_MILLON") },
840			{ "id": "2000000", "value": T("2_MILLON") },
841			{ "id": "2500000", "value": T("2_5_MILLON") },
842			{ "id": "3000000", "value": T("3_MILLON") },
843			{ "id": "4000000", "value": T("4_MILLON") },
844			{ "id": "5000000", "value": T("5_MILLON") },
845			{ "id": '', "value": T("SIN_LIMITE") }]
846	return price_list;
847}
848
849function get_list_rooms_min() {
850	let rooms =
851		[
852			{ "id": "1", "value": T("X_O_MAS_HABS", { param1: 1 }) },
853			{ "id": "2", "value": T("X_O_MAS_HABS", { param1: 2 }) },
854			{ "id": "3", "value": T("X_O_MAS_HABS", { param1: 3 }) },
855			{ "id": "4", "value": T("X_O_MAS_HABS", { param1: 4 }) },
856			{ "id": "5", "value": T("X_O_MAS_HABS", { param1: 5 }) }
857		];
858	return rooms;
859}
860
861/**
862 * 
863 * @returns {array}
864 */
865function get_list_meters() {
866	return [{ "id": '', "value": T("SIN_LIMITE") }, { "id": "40", "value": "40 m²" }, { "id": "60", "value": "60 m²" }, { "id": "80", "value": "80 m²" }, { "id": "100", "value": "100 m²" }, { "id": "120", "value": "120 m²" },
867	{ "id": "140", "value": "140 m²" }, { "id": "160", "value": "160 m²" }, { "id": "180", "value": "180 m²" }, { "id": "200", "value": "200 m²" }, { "id": "250", "value": "250 m²" }, { "id": "300", "value": "300 m²" },
868	{ "id": "350", "value": "350 m²" }, { "id": "400", "value": "400 m²" }, { "id": "450", "value": "450 m²" }, { "id": "500", "value": "500 m²" }, { "id": "550", "value": "550 m²" }, { "id": "600", "value": "600 m²" },
869	{ "id": "650", "value": "650 m²" }, { "id": "700", "value": "700 m²" }, { "id": "750", "value": "750 m²" }, { "id": "800", "value": "800 m²" }, { "id": "850", "value": "850 m²" }, { "id": "900", "value": "900 m²" }, { "id": "950", "value": "950 m²" }, { "id": '', "value": T("SIN_LIMITE") }]
870}
871
872/**
873 * Funcion que se usa para obtener el total de inmuebles segun parametros. Es necesario ya que cada pagina solicita una parte del total, pero para saber cuantas paginas se debe crear se debe conocer el total
874 * @param {array|string} params_search
875 * @returns {number}
876 */
877function get_max_propertys(params_search) {
878
879	let num = 1;
880
881	$.ajax({
882		type: 'POST',
883		data: params_search,
884		async: false,
885		url: get_base_url() + '/' + get_lang() + '/action/get_num_properties_search',
886		success: function (result) {
887			result = JSON.parse(result);
888			num = result['num_properties'];
889		}
890	});
891
892	return num;
893}
894
895/**
896 * Hacer scroll hacia algun punto
897 * @param {string} id_destino
898 * @returns {void}
899 * @deprecated
900 */
901function abrir_ancla(id_destino) {
902	//Creamos el string del enlace ancla
903	const codigo = "#" + id_destino;
904	//Funcionalidad de scroll lento para el enlace ancla en 1.5 segundos
905	const offsetTop = $(codigo).offset() ?? { top: 0 }
906
907	$("html,body").animate({ scrollTop: offsetTop.top }, 1500);
908}
909
910/**
911 * Get a mortgage calculation
912 * @param {string} deuda
913 * @param {string} anos
914 * @param {string} interes
915 * @returns {number}
916 * @deprecated
917 */
918function calcular_hipoteca(deuda, anos, interes) {
919
920	const _deuda = parseFloat(deuda);
921
922	const _anos = parseFloat(anos);
923
924	const _interes = parseFloat(interes);
925
926	const calc_interes = (_interes / 100) / 12;
927
928	let m = (_deuda * calc_interes * (Math.pow((1 + calc_interes), (_anos * 12)))) / ((Math.pow((1 + calc_interes), (_anos * 12))) - 1);
929
930	return m;
931
932}
933
934/**
935 * Browser data
936 * @returns {any}
937 * @deprecated
938 */
939function getBrowserInfo() {
940	var ua = navigator.userAgent, tem,
941		M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
942	if (/trident/i.test(M[1])) {
943		tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
944		return 'IE ' + (tem[1] || '');
945	}
946	if (M[1] === 'Chrome') {
947		tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
948		if (tem != null) return tem.slice(1).join(' ').replace('OPR', 'Opera');
949	}
950	M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
951	if ((tem = ua.match(/version\/(\d+)/i)) != null) M.splice(1, 1, tem[1]);
952	return M.join(' ');
953}
954
955/**
956 * Uppcase first letter of string
957 * @param {string} string
958 * @returns {string}
959 */
960function capitalizeFirstLetter(string) {
961	if (empty(string)) {
962		return string;
963	}
964	return string.charAt(0).toUpperCase() + string.slice(1);
965}
966
967/**
968 * Check if a string is a URL
969 * @param {string} s
970 * @returns {boolean}
971 */
972function isUrl(s) {
973	var regexp = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
974	return regexp.test(s);
975}
976
977/**
978 * Clean price by points
979 * @param {object} donde
980 * @param {string} caracter
981 * @returns {void}
982 * @deprecated
983 */
984function puntitos(donde, caracter = '.') {
985	let separador_decimal = ".";
986	let separador_miles = ".";
987
988	const pat = /[\*,\+,\(,\),\?,\\,\$,\[,\],\^]/;
989	const valor = donde.value;
990
991	let entero = ''
992	let decimal = ''
993	// SOLO LA PARTE ENTERA
994	if (valor.indexOf(',') > 0) {
995		entero = valor.substr(0, valor.indexOf(','));
996		decimal = valor.substr(valor.indexOf(',') + 1);
997	} else {
998		entero = valor;
999	}
1000	const largo = entero.length;
1001	const crtr = true;
1002
1003	let nums = new Array();
1004
1005	let cont = 0;
1006
1007	for (let m = 0; m < largo; m++) {
1008		if (entero.charAt(m) == separador_miles || entero.charAt(m) == " ") {
1009			continue;
1010
1011		} else {
1012			nums[cont] = entero.charAt(m);
1013			cont++;
1014		}
1015	}
1016
1017	var cad1 = '';
1018	var cad2 = '';
1019	var tres = 0;
1020	if (largo > 3 && crtr == true) {
1021		for (let k = nums.length - 1; k >= 0; k--) {
1022			cad1 = nums[k];
1023			cad2 = cad1 + cad2;
1024			tres++;
1025			if ((tres % 3) == 0) {
1026				if (k != 0) {
1027					cad2 = separador_miles + cad2;
1028				}
1029			}
1030		}
1031
1032		if (valor.indexOf(',') > 0) {
1033			donde.value = cad2 + separador_decimal + decimal;
1034		} else {
1035			donde.value = cad2;
1036		}
1037	}
1038}
1039
1040/**
1041 * Shuffle an array
1042 * @param {Array} array
1043 * @returns {Array}
1044 */
1045function shuffle(array) {
1046	var currentIndex = array.length, randomIndex;
1047
1048	// While there remain elements to shuffle...
1049	while (0 !== currentIndex) {
1050
1051		// Pick a remaining element...
1052		randomIndex = Math.floor(Math.random() * currentIndex);
1053		currentIndex--;
1054
1055		// And swap it with the current element.
1056		[array[currentIndex], array[randomIndex]] = [
1057			array[randomIndex], array[currentIndex]];
1058	}
1059
1060	return array;
1061}
1062
1063/**
1064 * Sanitize string to alpha
1065 * @param {string} a
1066 * @returns {string}
1067 */
1068function sanitize_alpha(a) {
1069	return a.replace(/[^a-zA-Z]+/g, '');
1070}
1071
1072/**
1073 * Sanitize string to numeric
1074 * @param {any} a
1075 * @returns {any}
1076 */
1077function sanitize_numeric(a) {
1078	var numsStr = a.replace(/[^0-9]/g, '');
1079	return parseInt(numsStr);
1080}
1081
1082/**
1083 * Reorder array
1084 * @param {Array} array
1085 * @returns {void}
1086 */
1087function reorder_simple_array(array) {
1088	array.sort(function (a, b) { return a - b });
1089}
1090
1091/**
1092 * Escape characterts by regex
1093 * @param {string} string
1094 * @returns {string}
1095 * @deprecated
1096 */
1097function escapeRegExp(string) {
1098	return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
1099}
1100
1101/**
1102 * Polyfill of replaceAll
1103 * @param {string} str
1104 * @param {string} find
1105 * @param {string} replace
1106 * @returns {string}
1107 * @deprecated
1108 */
1109function replaceAll_adapted_explorer(str, find, replace) {
1110	return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
1111}
1112
1113/**
1114 *  cobs(`header`, (data) => {
1115 *	    console.log(`datos de header:
1116 *	    ${data.width}
1117 *	    ${data.height}`);
1118 *	});
1119 */
1120
1121function cobs(id, x) {
1122	//DECLARE OBSERVER FOR ELEMENTS
1123	let type_element = '';
1124
1125	if (!!document.getElementById(id) == false && document.getElementsByClassName(id).length == 0) {
1126		console.warn(`${id} - does not exist or not is accesible`);
1127	} else if (!!document.getElementById(id)) {
1128		type_element = 'id';
1129	} else if (document.getElementsByClassName(id).length > 0) {
1130		type_element = 'class';
1131	}
1132
1133	//@ts-ignore
1134	cobs_listener = {
1135		aInternal: null,
1136		aListener: function (val) { },
1137		set data(val) {
1138			this.aInternal = val;
1139			this.aListener(val);
1140		},
1141		get data() {
1142			return this.aInternal;
1143		},
1144		registerListener: function (listener) {
1145			this.aListener = listener;
1146		}
1147	}
1148
1149	const resize_ob = new ResizeObserver(function (entries) {
1150		// since we are observing only a single element, so we access the first element in entries array
1151		let p = entries;
1152		p = p.filter((t) => {
1153			if (type_element == 'id') {
1154				return t.target.id == id;
1155			}
1156			if (type_element == 'class') {
1157				return Array.from(t.target.classList).includes(id);
1158			}
1159		});
1160
1161		//@ts-ignore
1162		p = p[0];
1163
1164		//@ts-ignore
1165		let rect = p.contentRect;
1166		//@ts-ignore
1167		let box = (p.borderBoxSize.inlineSize === undefined ? p.borderBoxSize[0] : p.borderBoxSize);
1168
1169		// current width & height
1170		let width = rect.width;
1171		let height = rect.height;
1172		let offsetWidth = box.inlineSize;
1173		let offsetHeight = box.blockSize;
1174		//@ts-ignore
1175		cobs_listener.data = { width: width, height: height, offsetWidth: offsetWidth, offsetHeight: offsetHeight };
1176	});
1177
1178	if (type_element == 'id') {
1179		try {
1180			//@ts-ignore
1181			resizeObserver.unobserve(document.querySelector(`#${id}`));
1182		} catch (error) {
1183			//If no exist the first time no problem
1184		}
1185		//@ts-ignore
1186		resize_ob.observe(document.querySelector(`#${id}`));
1187	} else if (type_element == 'class') {
1188		try {
1189			//@ts-ignore
1190			resizeObserver.unobserve(document.querySelector(`.${id}`));
1191		} catch (error) {
1192			//If no exist the first time no problem
1193		}
1194		//@ts-ignore
1195		resize_ob.observe(document.querySelector(`.${id}`));
1196	} else {
1197		console.warn(`${id} - is not observable`);
1198	}
1199	//@ts-ignore
1200	cobs_listener.registerListener(x);
1201}
1202
1203function cobs_end(id) {
1204	let type_element = 'id';
1205
1206	if (!!document.getElementById(id) == false && document.getElementsByClassName(id).length == 0) {
1207		throw new Error(`${id} is not accessible or does not exist`);
1208	} else if (!!document.getElementById(id)) {
1209		type_element = 'id';
1210	} else if (document.getElementsByClassName(id).length > 0) {
1211		type_element = 'class';
1212	}
1213
1214	if (type_element == 'id') {
1215		//@ts-ignore
1216		resizeObserver.unobserve(document.querySelector(`#${id}`));
1217		return true;
1218	} else if (type_element == 'class') {
1219		//@ts-ignore
1220		resizeObserver.unobserve(document.querySelector(`.${id}`));
1221		return true;
1222	} else {
1223		throw new Error(`${id} - is not observable`);
1224	}
1225}
1226//----------------------Code for Lazy images of css----------------------
1227document.addEventListener("DOMContentLoaded", function () {
1228	var lazyloadImages;
1229
1230	if ("IntersectionObserver" in window) {
1231		lazyloadImages = document.querySelectorAll(".lazy");
1232		var imageObserver = new IntersectionObserver(function (entries, observer) {
1233			entries.forEach(function (entry) {
1234				if (entry.isIntersecting) {
1235					var image = entry.target;
1236					image.classList.remove("lazy");
1237					imageObserver.unobserve(image);
1238				}
1239			});
1240		});
1241
1242		lazyloadImages.forEach(function (image) {
1243			imageObserver.observe(image);
1244		});
1245	} else {
1246		var lazyloadThrottleTimeout;
1247		lazyloadImages = document.querySelectorAll(".lazy");
1248
1249		function lazyload() {
1250			if (lazyloadThrottleTimeout) {
1251				clearTimeout(lazyloadThrottleTimeout);
1252			}
1253
1254			lazyloadThrottleTimeout = setTimeout(function () {
1255				var scrollTop = window.pageYOffset;
1256				lazyloadImages.forEach(function (img) {
1257					if (img.offsetTop < (window.innerHeight + scrollTop)) {
1258						img.src = img.dataset.src;
1259						img.classList.remove('lazy');
1260					}
1261				});
1262				if (lazyloadImages.length == 0) {
1263					document.removeEventListener("scroll", lazyload);
1264					window.removeEventListener("resize", lazyload);
1265					window.removeEventListener("orientationChange", lazyload);
1266				}
1267			}, 20);
1268		}
1269
1270		document.addEventListener("scroll", lazyload);
1271		//@ts-ignore
1272		window.addEventListener("resize", lazyload);
1273		//@ts-ignore
1274		window.addEventListener("orientationChange", lazyload);
1275	}
1276})
1277//-------------------------------------------------------------------------
1278
1279/**
1280 * Call and set theme
1281 * @returns {void}
1282 */
1283function call_theme() {
1284	const id_theme = getCookie("theme_inmotek");
1285	if (empty(id_theme)) {
1286		if ($("#no-snow-inmotek").length) {
1287			setCookie("theme_inmotek", 100, 1);
1288			$("#no-snow-inmotek").addClass("snow");
1289		}
1290	}
1291}
1292
1293/**
1294 * Fetch data
1295 * @param {string} link
1296 * @param {Object} object_params
1297 * @param {Function} func_sucess
1298 * @param {Function} func_done
1299 * @param {Function} func_fail
1300 * @param {Function} func_always
1301 * @returns {void}
1302 */
1303function fetch_data_post(link, object_params, func_sucess, func_done, func_fail, func_always) {
1304
1305	object_params = object_params ?? {}
1306	func_sucess = func_sucess ?? function () { }
1307	func_done = func_done ?? function () { }
1308	func_fail = func_fail ?? function () { }
1309	func_always = func_always ?? function () { }
1310
1311	//@ts-ignore
1312	$.ajax({
1313		type: 'POST',
1314		data: object_params,
1315		async: true,
1316		url: link,
1317		success: func_sucess
1318	})
1319		//@ts-ignore
1320		.done(func_done)
1321		//@ts-ignore
1322		.fail(func_fail)
1323		//@ts-ignore
1324		.always(func_always);
1325
1326}
1327
1328/**
1329 * Duplicated function "stripHtml"
1330 * @param {string} text
1331 * @returns {string}
1332 */
1333function delete_html_tags(text) {
1334
1335	if (empty(text)) {
1336		return '';
1337	}
1338
1339	text = text.replace(/(<([^>]+)>)/ig, '');
1340
1341	return text;
1342
1343}
1344
1345/**
1346 * Duplicated "with is_empty"
1347 * @param {any} var_data
1348 * @returns {any}
1349 */
1350function has_value(var_data) {
1351
1352	return ((var_data !== null && var_data !== '' && var_data !== undefined) ? true : false)
1353
1354}
1355
1356/**
1357 * Delete a class of all HTML element
1358 * @param {string} class_name
1359 * @returns {void}
1360 */
1361function delete_class_of_all_elements(class_name) {
1362
1363	let elements = document.querySelectorAll("." + class_name)
1364
1365	elements.forEach(element => {
1366		element.classList.remove(class_name)
1367	})
1368}
1369
1370/**
1371 * Enable Spinner animation
1372 * @returns {void}
1373 */
1374function set_enable_spinner() {
1375	if (document.querySelector(".spinner-search") == null) {
1376		$('#page-content').addClass("justify-content-center")
1377		$('#page-content').addClass("align-items-center")
1378		$('#page-content').removeClass("pb-4")
1379		$('#page-content').addClass("py-9")
1380		$('#page-content').addClass("hp-4")
1381		$('#page-content').html(`<span class="spinner-search"></span>`)
1382	}
1383}
1384
1385/**
1386 * Disable Spinner animation
1387 * @returns {void}
1388 */
1389function set_disable_spinner() {
1390	$('#page-content').removeClass("justify-content-center")
1391	$('#page-content').removeClass("align-items-center")
1392	$('#page-content').removeClass("py-9")
1393	$('#page-content').addClass("pb-4")
1394	$('#page-content').removeClass("hp-4")
1395	$('#page-content .spinner-search').hide()
1396}
1397
1398function add_flag_catchmen() {
1399
1400	let flag_html = `<div style="position: fixed;left: -40px;width: 220px;height: 40px;border: 1px solid #797211ff;top: 20px;transform: rotate(-25deg);text-align: center;text-transform: uppercase;font-weight: bold;color: #fff;background-color: #ffbf00;line-height: 35px;">${T("CAPTACION")}</div>`;
1401
1402	$("body").append(flag_html);
1403}
1404
1405function add_flag_managed() {
1406
1407	let flag_html = `<div style="position: fixed;left: -40px;width: 220px;height: 40px;border: 1px solid #791111;top: 20px;transform: rotate(-25deg);text-align: center;text-transform: uppercase;font-weight: bold;color: #fff;background-color: red;line-height: 35px;">${T("GESTIONADO")}</div>`;
1408
1409	$("body").append(flag_html);
1410}
1411
1412
1413function delete_quotes(string) {
1414	return string.normalize("NFD").replace(/[\u0300-\u036f]/g, '');
1415}
1416
1417function delete_special_characters(string) {
1418	return string.replace(/[¿¡?!#&]/g, '');
1419}
1420
1421function url_title_seo_generate(title, fallback = '') {
1422	// Generación del texto SEO
1423	let text_seo = title != '' ? title : fallback;
1424
1425	// Mapeo de caracteres cirílicos a latinos
1426	const cyrillic_to_latin_map = {
1427		'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
1428		'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm',
1429		'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
1430		'ф': 'f', 'х': 'kh', 'ц': 'ts', 'ч': 'ch', 'ш': 'sh', 'щ': 'shch', 'ъ': '',
1431		'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya',
1432		'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo',
1433		'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'Y', 'К': 'K', 'Л': 'L', 'М': 'M',
1434		'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',
1435		'Ф': 'F', 'Х': 'Kh', 'Ц': 'Ts', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Shch', 'Ъ': '',
1436		'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya'
1437	};
1438
1439	// Trimming and lowercase conversion
1440	text_seo = text_seo.trim().toLowerCase();
1441
1442	// Normalización de caracteres latinos (sin eliminar diacríticos para caracteres cirílicos)
1443	text_seo = text_seo
1444		.replace(/ñ/g, "n")
1445		.replace(/á/g, "a")
1446		.replace(/é/g, "e")
1447		.replace(/í/g, "i")
1448		.replace(/ó/g, "o")
1449		.replace(/ú/g, "u")
1450		.replace(/Ã¥/g, "a")
1451		.replace(/ä/g, "a")
1452		.replace(/ö/g, "o")
1453		.replace(/ /g, "-")
1454		.replace(/[!?]/g, '');
1455
1456	// Conversión de caracteres cirílicos a latinos
1457	text_seo = text_seo.split('').map(char => cyrillic_to_latin_map[char] || char).join('');
1458
1459	// Eliminación de paréntesis y contenido dentro de ellos
1460	text_seo = text_seo.replace(/\([^)]+\)/g, '');
1461
1462	// Eliminación de caracteres no alfanuméricos y guiones (excepto caracteres cirílicos)
1463	text_seo = text_seo.replace(/[^\wа-яё0-9-]/g, '');
1464
1465	// Consolidación de guiones múltiples
1466	text_seo = text_seo.replace(/-+/g, "-");
1467
1468	// Codificación de URI
1469	text_seo = encodeURI(text_seo);
1470
1471	return text_seo;
1472}
1473
1474function url_text_seo_generate(type, operation, town, title = '') {
1475	// Generación del texto SEO
1476	let text_seo = (title !== '' ? title : T("X_EN_X_EN_X", {
1477		param1: type,
1478		param2: ((operation.includes("v") && operation.includes("a")) ? T("VENTA_Y_ALQUILER") : (operation.includes("v") ? T("VENTA") : T("ALQUILER"))),
1479		param3: town.replaceAll("-", " ")
1480	}));
1481
1482	// Mapeo de caracteres cirílicos a latinos
1483	const cyrillic_to_latin_map = {
1484		'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo',
1485		'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm',
1486		'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u',
1487		'ф': 'f', 'х': 'kh', 'ц': 'ts', 'ч': 'ch', 'ш': 'sh', 'щ': 'shch', 'ъ': '',
1488		'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya',
1489		'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo',
1490		'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'Y', 'К': 'K', 'Л': 'L', 'М': 'M',
1491		'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U',
1492		'Ф': 'F', 'Х': 'Kh', 'Ц': 'Ts', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Shch', 'Ъ': '',
1493		'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu', 'Я': 'Ya'
1494	};
1495
1496	// Trimming and lowercase conversion
1497	text_seo = text_seo.trim().toLowerCase();
1498
1499	// Normalización de caracteres latinos (sin eliminar diacríticos para caracteres cirílicos)
1500	text_seo = text_seo
1501		.replace(/ñ/g, "n")
1502		.replace(/á/g, "a")
1503		.replace(/é/g, "e")
1504		.replace(/í/g, "i")
1505		.replace(/ó/g, "o")
1506		.replace(/ú/g, "u")
1507		.replace(/Ã¥/g, "a")
1508		.replace(/ä/g, "a")
1509		.replace(/ö/g, "o")
1510		.replace(/ /g, "-")
1511		.replace(/[!?]/g, '');
1512
1513	// Conversión de caracteres cirílicos a latinos
1514	text_seo = text_seo.split('').map(char => cyrillic_to_latin_map[char] || char).join('');
1515
1516	// Eliminación de paréntesis y contenido dentro de ellos
1517	text_seo = text_seo.replace(/\([^)]+\)/g, '');
1518
1519	// Eliminación de caracteres no alfanuméricos y guiones (excepto caracteres cirílicos)
1520	text_seo = text_seo.replace(/[^\wа-яё0-9-]/g, '');
1521
1522	// Consolidación de guiones múltiples
1523	text_seo = text_seo.replace(/-+/g, "-");
1524
1525	// Asegurarse de que la URL comience con una barra "/"
1526	text_seo = "/" + text_seo;
1527
1528	// Codificación de URI
1529	text_seo = encodeURI(text_seo);
1530
1531	return text_seo;
1532}
1533
1534function get_params_url(url) {
1535	var qd = {};
1536
1537	if (empty(url)) {
1538		return qd;
1539	}
1540
1541	const markIndex = url.indexOf('?');
1542
1543	if (markIndex === -1) {
1544		return qd;
1545	}
1546
1547	url = url.substring(markIndex + 1);
1548
1549	if (url) url.substr(1).split("&").forEach(function (item) {
1550		var s = item.split("="),
1551			k = s[0],
1552			v = s[1] && decodeURIComponent(s[1]);
1553		(qd[k] = qd[k] || []).push(v);
1554	});
1555
1556	return qd;
1557}
1558
1559/**
1560 * Get query string
1561 * @param {?string} url
1562 * @returns {string}
1563 */
1564function get_query_string(url = null) {
1565
1566	if (url === null) {
1567		url = location.href
1568	}
1569
1570	const urlObj = new URL(url);
1571
1572	const queryString = urlObj.search;
1573
1574	return queryString.substring(1);
1575}
1576
1577function sleep(ms) {
1578	return new Promise(resolve => setTimeout(resolve, ms));
1579}
1580
1581function empty(data) {
1582	let data_to_return = false
1583	if ((typeof data !== 'symbol') && data === undefined || data === null || data === '' || data === 0 ||
1584		data === false || (Array.isArray(data) && data.length === 0) ||
1585		(typeof data === 'object' && Object.keys(data).length === 0) ||
1586		(data instanceof Map && data.size === 0) ||
1587		(data instanceof Set && data.size === 0)) {
1588		data_to_return = true
1589	}
1590	return data_to_return
1591}
1592
1593function add_hook(target_hook, the_name_of_function_you_want_to_use, priority = 0, accepted_args = {}) {
1594
1595	if (empty(target_hook)) {
1596		throw new Error("Target hook is mandatory");
1597	}
1598
1599	if (empty(the_name_of_function_you_want_to_use)) {
1600		throw new Error("The name of function you want to use is mandatory");
1601	}
1602
1603	if (target_hook == 'list_properties_search_engine') {
1604
1605		const func = window[the_name_of_function_you_want_to_use];
1606
1607		if (typeof func === 'function') {
1608			func(accepted_args);
1609		}
1610	}
1611}

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.