1XA.component.search.locationfilter = (function ($, document) { 2 3 "use strict"; 4 5 var api = {}, 6 locationFilters = [], 7 views = [], 8 queryModel, 9 urlHelperModel, 10 scriptsLoaded = false, 11 mapsConnector = XA.connector.mapsConnector, 12 LocationFilterModel, 13 LocationFilterView, 14 initialize; 15 16 initialize = function() { 17 var i, view; 18 for (i = 0; i < locationFilters.length; i++) { 19 //crate Backbone.js views - one view per component on the page 20 view = new LocationFilterView({el: locationFilters[i], model: new LocationFilterModel()}); 21 } 22 }; 23 24 LocationFilterModel = Backbone.Model.extend({ 25 defaults: { 26 dataProperties: {}, 27 sig: [] 28 }, 29 initAutocompleteEngine : function() { 30 var _this = this, 31 searchEngine; 32 33 //initialize predictive only when number of predictions is non-zero 34 if(_this.get("dataProperties").p > 0){ 35 searchEngine = new Bloodhound({ 36 datumTokenizer: Bloodhound.tokenizers.obj.whitespace("name"), 37 queryTokenizer: Bloodhound.tokenizers.whitespace, 38 limit : _this.get("dataProperties").p, 39 remote : { 40 url : "-", 41 replace : function(){ 42 return Date.now().toString(); 43 }, 44 transport : function(options, onSuccess, onError){ 45 var queryParams = _this.get("queryParams"); 46 if(!queryParams.text){ 47 onSuccess([]); 48 return; 49 } 50 mapsConnector.locationAutocomplete(queryParams, 51 function (results) { //success 52 var simplifiedResults = results.map(function(result) { 53 if (result.hasOwnProperty("text")) { 54 return result.text; 55 } 56 return result; 57 }); 58 59 onSuccess(simplifiedResults); 60 }, 61 function(){ //fail 62 onError("Could not autocomplete"); 63 }); 64 } 65 } 66 }); 67 searchEngine.initialize(); 68 this.set({"searchEngine" : searchEngine}); 69 } 70 } 71 }); 72 73 LocationFilterView = XA.component.search.baseView.extend({ 74 initialize: function () { 75 var inst = this, 76 dataProperties = this.$el.data(), 77 $textBox = this.$el.find(".location-search-box-input"), 78 signatures = dataProperties.properties.searchResultsSignature.split(','); 79 80 if (dataProperties.properties.searchResultsSignature === null) { 81 dataProperties.properties.searchResultsSignature = ""; 82 } 83 84 this.model.set({ dataProperties: dataProperties.properties }); 85 this.model.set({ sig: signatures}); 86 this.model.set({ queryParams: { maxResults: dataProperties.p, text: "" } }); 87 this.model.initAutocompleteEngine(); 88 89 var autocompleteEngine = this.model.get("searchEngine"); 90 91 if(autocompleteEngine){ 92 $textBox.typeahead({ 93 hint : true, 94 minLength : 2 95 }, 96 { 97 source : autocompleteEngine.ttAdapter(), 98 templates : { 99 suggestion : function(data) { 100 return '<div class="suggestion-item">' + data + '</div>'; 101 } 102 } 103 }).on("typeahead:selected",function(args, selected){ 104 inst.translateUserLocation(selected); 105 $textBox.typeahead("val", selected); 106 }); 107 } 108 109 this.addressLookup(); 110 111 XA.component.search.vent.on("hashChanged", function(hash) { 112 var address = hash[signatures.length > 0 && signatures[0] !== "" ? signatures[0] + "_a" : "a"]; 113 if (typeof address !== "undefined" && address !== null && address !== "") { 114 $textBox.val(address); 115 } 116 }); 117 }, 118 events: { 119 "click .location-search-box-button": "addressLookup", 120 "keypress .location-search-box-input": "searchTextChanges", 121 "keyup .location-search-box-input" : "autocomplete" 122 }, 123 addressLookup: function(e){
124 var properties = this.model.get("dataProperties"), 125 lookupQuery = { 126 text : this.getAddress(), 127 maxResults : 1 128 }, 129 hashObj; 130 131 if (lookupQuery.text === "") { 132 hashObj = this.createHashObject("", ""); 133 this.updateHash(hashObj, properties); 134 return; 135 } 136 137 switch (properties.mode) { 138 case "Location": { 139 //use browser to detect location 140 this.detectLocation(); 141 break; 142 } 143 case "UserProvided": { 144 //take address entered by user and try to convert it to latitude and longitude 145 this.translateUserLocation(lookupQuery); 146 break; 147 } 148 case "Mixed": { 149 //use user address otherwise try to detect location by browser 150 if (typeof(lookupQuery.text) === "undefined" || lookupQuery.text === "") { 151 this.detectLocation(); 152 } else { 153 this.translateUserLocation(lookupQuery); 154 } 155 break; 156 } 157 } 158 }, 159 getAddress: function() { 160 var $textBox = this.$el.find(".location-search-box-input.tt-input"), 161 text = $textBox.length !== 0 ? $textBox.val() : this.$el.find(".location-search-box-input").val(), 162 hash = queryModel.parseHashParameters(window.location.hash), 163 signatures = this.model.get("sig"), 164 address; 165 166 if (text === "" || typeof text === "undefined") { 167 address = hash[signatures.length > 0 && signatures[0] !== "" ? signatures[0] + "_a" : "a"]; 168 if (address !== "") { 169 text = address; 170 } 171 if (typeof text === "undefined") { 172 text = ""; 173 } 174 } 175 176 return text; 177 }, 178 autocomplete : function(args){ 179 var $textBox, 180 queryParams, 181 properties = this.model.get("dataProperties"); 182 183 args.stopPropagation(); 184 if (args.keyCode === 13) { 185 return; 186 } 187 188 $textBox = this.$el.find(".location-search-box-input.tt-input"); 189 190 queryParams = { 191 text : $textBox.length !== 0 ? $textBox.val() : this.$el.find(".location-search-box-input").val(), 192 maxResults : properties.p 193 }; 194 this.model.set({queryParams : queryParams}); 195 }, 196 searchTextChanges: function(e) { 197 e.stopPropagation(); 198 if (e.keyCode === 13) { 199 this.addressLookup(e); 200 return false; 201 } 202 return true; 203 }, 204 translateUserLocation: function(lookupQuery) { 205 var that = this, 206 properties = this.model.get("dataProperties"), 207 text = typeof lookupQuery.text !== "undefined" ? lookupQuery.text : lookupQuery, 208 $textBox = this.$el.find(".location-search-box-input.tt-input"), 209 hashObj = {}; 210 211 if (text === "") { 212 return; 213 } 214 mapsConnector.addressLookup({ text: text }, function(data) { 215 hashObj = that.createHashObject(data[0] + "|" + data[1], properties.f + ",Ascending"); 216 that.updateHash(hashObj, properties); 217 }, function () { 218 console.error("Error while getting '" + text + "' location"); 219 }); 220 $textBox.blur(); 221 if ($textBox.val() === "") { 222 $textBox.val(text); 223 } 224 }, 225 detectLocation: function() { 226 var properties = this.model.get("dataProperties"), 227 $textBox = this.$el.find(".location-search-box-input"), 228 sig = this.model.get("sig"), 229 hash = queryModel.parseHashParameters(window.location.hash), 230 param, 231 hashObj = {}, 232 that = this; 233 234 XA.component.locationService.detectLocation( 235 function (location) { 236 hashObj = that.createHashObject(location[0] + "|" + location[1], properties.f + ",Ascending"); 237 that.updateHash.call(that, hashObj, properties); 238 if ($textBox.length > 0) { 239 $textBox.attr("placeholder", properties.myLocationText); 240 } 241 }, 242 function (errorMessage) { 243 //do not update the hash in any way when then location isn't available 244 console.log(errorMessage); 245 } 246 ); 247 }, 248 updateHash: function (params, properties) { 249 var sig = this.model.get("sig"), 250 signature, 251 searchModels = typeof XA.component.search !== "undefined" ? XA.component.search.results.searchResultModels : [], 252 $textBox = this.$el.find(".location-search-box-input.tt-input"), 253 text = $textBox.length !== 0 ? $textBox.val() : this.$el.find(".location-search-box-input").val(), 254 i, j; 255 256 //clear load more offset in each of search results with the same signature when location is changes 257 //at the moment this is needed to clear offset but should be handle in search service in the future 258 for (i = 0; i < searchModels.length; i++) { 259 for (j = 0; j < sig.length; j++) { 260 signature = sig[j]; 261 if (searchModels[i].get("dataProperties").sig === signature) { 262 searchModels[i].set("loadMoreOffset", 0); 263 } 264 } 265 } 266 267 if (text !== null && text !== "") { 268 for (i = 0; i < sig.length; i++) { 269 signature = sig[i]; 270 params[signature !== "" ? signature + "_a" : "a"] = text; 271 } 272 } 273
274 queryModel.updateHash(params, properties.targetUrl); 275 for (i = 0; i < sig.length; i++) { 276 XA.component.search.vent.trigger("my-location-coordinates-changed", { 277 sig: sig[i], 278 coordinates: params[sig[i] !== "" ? sig[i] + "_g" : "g"].split("|") 279 }); 280 } 281 }, 282 createHashObject: function(g, o) { 283 var sig = this.model.get("sig"), 284 signature, 285 hashObj = {}, 286 i; 287 288 for (i = 0; i < sig.length; i++) { 289 signature = sig[i]; 290 hashObj[signature !== "" ? signature + "_g" : "g"] = g; 291 hashObj[signature !== "" ? signature + "_o" : "o"] = o; 292 } 293 294 return hashObj; 295 } 296 }); 297 298 api.init = function() { 299 if ($("body").hasClass("on-page-editor")) { 300 return; 301 } 302 303 queryModel = XA.component.search.query; 304 urlHelperModel = XA.component.search.url; 305 306 var components = $(".location-filter:not(.initialized)"); 307 308 _.each(components, function(elem) { 309 var $el = $(elem), 310 properties = $el.data("properties"); 311 312 //collect all found components - we will use them later to create views 313 locationFilters.push($el); 314 315 //load google or bing scripts in order to properly use address lookup functionality but just 316 //when we are not in Location mode (in this mode we are taking location form the browser) 317 if (!scriptsLoaded && properties.mode !== "Location") { 318 mapsConnector.loadScript(properties.key, XA.component.search.locationfilter.scriptsLoaded); 319 } else { 320 initialize(); 321 } 322 323 $el.addClass("initialized"); 324 }); 325 }; 326 327 api.scriptsLoaded = function() { 328 if (!scriptsLoaded) { 329 console.log("Maps api loaded"); 330 scriptsLoaded = true; 331 initialize(); 332 } 333 }; 334 335 return api; 336 337}(jQuery, document)); 338 339XA.register("locationfilter", XA.component.search.locationfilter);
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.