1/** 2 * ZOOM Store Locator Optimization 3 * Integración personalizada para Agile Store Locator (ASL) 4 * 5 * Reglas de negocio implementadas: 6 * 1. Filtro geográfico estricto (Hard filter): Solo oficinas con distancia <= radio seleccionado. 7 * 2. JerarquÃa de ordenamiento de 2 niveles: 8 * - Prioridad 1: Coincidencia por tÃtulo con el término buscado (dentro del radio). 9 * - Prioridad 2: Resto de oficinas dentro del radio ordenadas por distancia ASC. 10 */ 11(function ($) { 12 'use strict'; 13 14 /** 15 * Normaliza texto: minúsculas, sin acentos/tildes, sin caracteres especiales. 16 */ 17 function normalizeText(text) { 18 if (!text) return ''; 19 return String(text) 20 .toLowerCase() 21 .normalize('NFD') 22 .replace(/[\u0300-\u036f]/g, '') // Elimina marcas diacrÃticas (acentos) 23 .replace(/[^a-z0-9\s]/g, ' ') // Remueve puntuación / caracteres especiales 24 .replace(/\s+/g, ' ') // Unifica espacios 25 .trim(); 26 } 27 28 /** 29 * Obtiene el término de búsqueda relevante ingresado por el usuario. 30 */ 31 function getSearchTerms() { 32 var $input = $('#auto-complete-search, .asl-search-address, .asl-search-name'); 33 var rawVal = $input.length ? ($input.val() || '') : ''; 34 35 // Si el valor es de geolocalización automática por defecto, se ignora como término de tÃtulo 36 if (window.asl_configuration && window.asl_configuration.words) { 37 var geoWords = [ 38 window.asl_configuration.words.your_cur_loc, 39 window.asl_configuration.words.geo, 40 'tu ubicacion actual', 41 'current location' 42 ]; 43 var normVal = normalizeText(rawVal); 44 for (var k = 0; k < geoWords.length; k++) { 45 if (geoWords[k] && normVal === normalizeText(geoWords[k])) { 46 return { raw: '', primary: '' }; 47 } 48 } 49 } 50 51 var fullNorm = normalizeText(rawVal); 52 // El primer segmento antes de la coma suele ser la localidad/sucursal ("Baruta, Caracas..." -> "baruta") 53 var primaryNorm = normalizeText(rawVal.split(',')[0]); 54 55 return { 56 raw: fullNorm, 57 primary: primaryNorm 58 }; 59 } 60 61 /** 62 * Calcula el puntaje de coincidencia en el tÃtulo de la tienda. 63 */ 64 function getTitleMatchScore(store, searchTerms) { 65 if (!searchTerms.raw && !searchTerms.primary) return 0; 66 67 var title = ''; 68 if (store.props_ && store.props_.title) { 69 title = normalizeText(store.props_.title); 70 } else if (store.title) { 71 title = normalizeText(store.title); 72 } 73 74 if (!title) return 0; 75 76 // Coincidencia con el segmento principal (ej. "Baruta" en "Zoom C.C. Baruta") 77 if (searchTerms.primary && searchTerms.primary.length >= 2 && title.indexOf(searchTerms.primary) !== -1) { 78 return 2; 79 } 80 81 // Coincidencia con el término completo 82 if (searchTerms.raw && searchTerms.raw.length >= 2 && title.indexOf(searchTerms.raw) !== -1) { 83 return 1; 84 } 85 86 return 0; 87 } 88 89 /** 90 * Inicialización e intercepción de los métodos de Agile Store Locator 91 */ 92 function initAslCustomSorting() { 93 if (typeof window.asl_engine === 'undefined' || !window.asl_engine.dataSource) { 94 // Reintentar si ASL aún no está inicializado 95 setTimeout(initAslCustomSorting, 100); 96 return; 97 } 98 99 console.log('Enhanced Search On'); 100 101 var proto = window.asl_engine.dataSource.prototype; 102 103 // Sobrescribir el método sortDistance de ASL 104 proto.sortDistance = function (originCoords, storeList) { 105 if (!storeList || !storeList.length) return; 106 107 var searchTerms = getSearchTerms(); 108 var maxRadius = (window.asl_configuration && window.asl_configuration.radius_range) 109 ? parseFloat(window.asl_configuration.radius_range) 110 : null; 111 112 // 1. FILTRO ESTRICTO (Hard Filter por radio de distancia) 113 if (maxRadius && !isNaN(maxRadius) && maxRadius > 0) { 114 for (var idx = storeList.length - 1; idx >= 0; idx--) { 115 var s = storeList[idx]; 116 var d = (s.props_ && typeof s.props_.distance === 'number') 117 ? s.props_.distance 118 : (originCoords && typeof s.distanceTo === 'function' ? s.distanceTo(originCoords) : 0); 119 120 if (d > maxRadius) { 121 storeList.splice(idx, 1); 122 } 123 } 124 } 125 126 // 2. JERARQUÃA DE ORDENAMIENTO (1° TÃtulo dentro del radio, 2° Distancia ASC) 127 storeList.sort(function (a, b) { 128 var distA = (a.props_ && typeof a.props_.distance === 'number') 129 ? a.props_.distance 130 : (originCoords && typeof a.distanceTo === 'function' ? a.distanceTo(originCoords) : 0); 131 132 var distB = (b.props_ && typeof b.props_.distance === 'number') 133 ? b.props_.distance 134 : (originCoords && typeof b.distanceTo === 'function' ? b.distanceTo(originCoords) : 0); 135 136 var scoreA = getTitleMatchScore(a, searchTerms); 137 var scoreB = getTitleMatchScore(b, searchTerms); 138 139 // Prioridad 1: Coincidencia de tÃtulo 140 if (scoreA !== scoreB) { 141 return scoreB - scoreA; // El que tenga mayor score va primero 142 } 143 144 // Prioridad 2: Proximidad (distancia menor a mayor) 145 return distA - distB; 146 }); 147 }; 148 149 // Adicionalmente, asegurar que en refreshView de la vista se mantenga la jerarquÃa 150 if (typeof window.asl_locator !== 'undefined' && window.asl_locator.View) { 151 var originalRefreshView = window.asl_locator.View.prototype.refreshView; 152 153 window.asl_locator.View.prototype.refreshView = function (t) { 154 var viewInstance = this; 155 originalRefreshView.call(viewInstance, t); 156 }; 157 } 158 } 159 160 $(document).ready(function () { 161 initAslCustomSorting(); 162 }); 163 164})(jQuery);
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.