1(function ($) { 2 "use strict"; 3 4 /** 5 * 6 * @constructor 7 */ 8 var WebManagerMap = function () { 9 this.confData = {}; 10 this.selfCount = {}; 11 this.mapInstance = {}; 12 this.mapMarkers = {}; 13 this.activeMap = null; 14 15 if ($(".js-mapComponent").length) { 16 this.initialize(); 17 } 18 }; 19 20 /** 21 * 22 * @param postcode 23 * @returns {string} 24 */ 25 WebManagerMap.prototype.getAddressForPostcode = function (componentName, postcode, houseNum) { 26 var address = "", 27 locations = this.confData[componentName].locations; 28 29 for (var i = 0; i < locations.length; i++) { 30 if (locations[i].address.indexOf(postcode) !== -1) { 31 if (houseNum !== null) { 32 if (locations[i].address.indexOf(houseNum) !== -1) { 33 address = locations[i].address; 34 break; 35 } 36 } else { 37 address = locations[i].address; 38 break; 39 } 40 } 41 } 42 return address; 43 }; 44 45 /** 46 * Set up map instance for the map elements on the page 47 */ 48 WebManagerMap.prototype.initialize = function () { 49 var self = this; 50 51 // Get all the map elements with the same class. 52 var mapElements = $('.js-mapComponent'); 53 var mapsUrl = '//smbmaps.ibsrv.net/world_tiles/{z}/{x}/{y}.png'; 54 55 // For each container that will hold a map. 56 mapElements.each( 57 function () { 58 // Get the component alias 59 var componentName = $(this).closest('[data-component-name]').data('componentName'); 60 61 // Initialize a map 62 self.mapInstance[componentName] = L.map(this); 63 64 L.tileLayer( 65 mapsUrl, 66 { 67 attribution: 'Map data provided by <a href="http://www.internetbrands.com/">Internet Brands</a>', 68 maxZoom: 18 69 } 70 ).addTo(self.mapInstance[componentName]); 71 72 self.mapInstance[componentName].scrollWheelZoom.disable(); 73 74 self.confData[componentName] = JSON.parse($(this).closest('[data-component-name]').find('input[type=hidden]').val()); 75 76 self.setupMap(self.mapInstance[componentName], self.confData[componentName]); 77 78 self.mapSize(this, self.confData[componentName], componentName); 79 80 self.attachEvents(this, self.confData[componentName], componentName); 81 82 var locations = self.confData[componentName].locations; 83 // have to make array reverse because the centered marker should be the first one in the listing 84 // of locations manager 85 if(locations.length > 1 && !self.confData[componentName].fitBounds){ 86 locations = locations.reverse(); 87 } 88 89 for (var i = 0; i < locations.length; i++) { 90 //if there is latitude and longitude for the location 91 if (locations[i].latitude != null && locations[i].longitude != null) { 92 var json = [{ 93 "lat": locations[i].latitude, 94 "lon": locations[i].longitude, 95 "address": { 96 "name": locations[i].address, 97 } 98 }]; 99 100 // create the marker 101 self.applyData(json, componentName, this, i); 102 } 103 // if there is an address for the location 104 else { 105 //get the latitude for the current location 106 self.geolocateLocation(locations[i], componentName, this); 107 } 108 } 109 110 var xaxisPan = self.confData[componentName].xaxis, 111 yaxisPan = self.confData[componentName].yaxis; 112 113 // set map X/Y - Axis Offset for desktop resolution 114 if ($(window).width() > 768) { 115 if(xaxisPan != 0 || yaxisPan != 0) self.mapInstance[componentName].panBy([xaxisPan, yaxisPan]) 116 } 117 } 118 ); 119 120 // Toggle map scrolling 121 $("body").click(function (e) { 122 if ($(e.target).hasClass("js-mapComponent")) { 123 var componentName = $(e.target).closest('[data-component-name]').data('componentName'); 124 // Disable scroll on other map instance if already enabled 125 if (self.activeMap !== null) { 126 self.mapInstance[self.activeMap].scrollWheelZoom.disable(); 127 } 128 self.activeMap = componentName; 129 130 if(self.confData[componentName].zoomControl){ 131 self.mapInstance[componentName].scrollWheelZoom.enable(); 132 } 133 } else { 134 if (self.activeMap !== null) { 135 self.mapInstance[self.activeMap].scrollWheelZoom.disable(); 136 self.activeMap = null; 137 } 138 } 139 }); 140 }; 141 142 /** 143 * Attach events 144 * 145 * @param map 146 * @param mapData 147 * @param componentName 148 */ 149 WebManagerMap.prototype.attachEvents = function (map, mapData, componentName) { 150 var self = this, 151 winResizeTimer; 152 153 $(window).resize(function () { 154 self.mapSize(map, mapData, componentName); 155 clearTimeout(winResizeTimer); 156 //Call mapCenter function when the resizing completely will stop/finish 157 winResizeTimer = setTimeout(function () { 158 if (self.mapMarkers[componentName].length > 1 && self.confData[componentName].fitBounds) { 159 var markerGroup = L.featureGroup(self.mapMarkers[componentName]); 160 self.mapCenter(componentName, markerGroup); 161 } 162 }, 250); 163 }); 164 } 165 166 /** 167 * 168 * @param mapInstance 169 * @param mapData 170 */ 171 WebManagerMap.prototype.setupMap = function (mapInstance, mapData) { 172 var zoomControl = mapData.zoomControl; 173 174 if (!zoomControl) { 175 // Drawing a square area to zoom 176 mapInstance.boxZoom.disable(); 177 178 // The zoom on double click 179 mapInstance.doubleClickZoom.disable(); 180 181 // Like when you hit the keys for + and - 182 mapInstance.keyboard.disable(); 183 184 // The zoom with scroll 185 mapInstance.scrollWheelZoom.disable(); 186 187 if (mapInstance.tap) { 188 mapInstance.tap.disable(); 189 } 190 191 // The zoom via touch 192 mapInstance.touchZoom.disable(); 193 194 // The + and - buttons 195 $(".leaflet-control-zoom").css("visibility", "hidden"); 196 } 197 }; 198 199 /** 200 * Set fit bound for map instance with multiple locations 201 * @param componentName Alias of the map component 202 * @param markerLayer The layer containing all the markers 203 */ 204 WebManagerMap.prototype.mapCenter = function (componentName, markerLayer) { 205 var self = this; 206 207 self.mapInstance[componentName].fitBounds(markerLayer.getBounds().pad(0.5)); 208 }; 209 210 211 /** 212 * Calculates the size of the map based on the settings 213 * @param element Map instance 214 * @param mapData Settings for the map 215 */ 216 WebManagerMap.prototype.mapSize = function (element, mapData, componentName) { 217 var self = this, parent = $(element).parent(); 218 219 if (mapData.autoFit) { 220 var titleCaptionHeight, pleMapAwrapHeight; 221 (!self.confData[componentName].isPle) ? titleCaptionHeight = parent.children('.component__title-caption-wrap').outerHeight(true) : pleMapAwrapHeight = parent.find('.map__wrap').outerHeight(true); 222 223 parent.css('height', '100%'); 224 var elementHeight = parent.height(); 225 226 // If there title or caption is shown in the component subtract it from the parent height 227 if (!self.confData[componentName].isPle && titleCaptionHeight !== null) { 228 elementHeight = elementHeight - titleCaptionHeight; 229 } else { 230 if ($(window).width() <= 768 && pleMapAwrapHeight !== null) { 231 elementHeight = elementHeight - pleMapAwrapHeight; 232 } 233 } 234 235 // Resize the map and trigger map.resize event 236 $(element).css({width: parent.width(), height: elementHeight}); 237 $(element).trigger('map.resize'); 238 239 } else { 240 $(element).css({width: mapData.width, height: mapData.height}); 241 } 242 }; 243 244 /** 245 * Notice the param json_callback=jsonMapCallback 246 * Check more here: http://wiki.openstreetmap.org/wiki/Nominatim 247 * json_callback=<string> - Wrap json output in a callback function (JSONP) i.e. <string>(<json>) 248 * @type {string} 249 */ 250 WebManagerMap.prototype.geocodeURL = "https://nominatim.openstreetmap.org/search?[QUERY]&format=json&polygon=1&addressdetails=1&limit=1"; 251 252 /** 253 * 254 * @param location 255 */ 256 WebManagerMap.prototype.geolocateLocation = function (location, componentName, mapElement) { 257 var self = this, 258 geocodeURL = this.geocodeURL; 259 260 geocodeURL = geocodeURL.replace("[QUERY]", location.query); 261 262 // Geocode the location and apply the response to the map instance 263 $.ajax({ 264 url: geocodeURL, 265 dataType: "jsonp", 266 jsonp: 'json_callback', 267 success: function (json) { 268 self.applyData(json, componentName, mapElement); 269 } 270 }); 271 // @todo: Maybe find another solution for this cross-domain query 272 }; 273 274 /** 275 * Apply the location data on the map instance 276 * @param json 277 * @param componentName 278 */ 279 WebManagerMap.prototype.applyData = function (json, componentName, mapElement, index) { 280 281 var self = this; 282 if (json.length > 0) { 283 self.selfCount[componentName] = self.selfCount[componentName] || 0; 284 285 var data = json[0], 286 lat = data.lat, 287 lon = data.lon; 288 289 290 self.mapInstance[componentName].setView([lat, lon], self.confData[componentName].zoom, {animation: true}); 291 self.selfCount[componentName]++; 292 293 var markerOptions = []; 294 markerOptions['alt'] = 'Map Marker'; 295 296 var assetsPath = self.confData[componentName].assetsPath; 297 298 if (self.confData[componentName].iconUrl) { 299 var iconUrl = self.confData[componentName].iconUrl, 300 icon = new L.Icon({ 301 iconUrl: iconUrl, 302 shadowUrl: assetsPath + 'images/marker-shadow.png', 303 iconSize: [25, 41], 304 iconAnchor: [12, 41], 305 popupAnchor: [1, -34], 306 shadowSize: [41, 41] 307 }); 308 309 markerOptions['icon'] = icon; 310 } 311 312 // var marker = L.marker([lat, lon], markerOptions).addTo(self.mapInstance[componentName]); 313 var marker = L.marker([lat, lon], markerOptions); 314 315 if (self.confData[componentName].alwaysShowInfoWindow || self.confData[componentName].showAddressOnHover) { 316 var location = data.display_name || null; // Default to display_name attribute or null 317 var addressFromPostcode = null; 318 319 if ('postcode' in data.address) {
320 var houseNum = ('house_number' in data.address) ? data.address.house_number : null; 321 322 addressFromPostcode = self.getAddressForPostcode(componentName, data.address.postcode, houseNum); 323 location = (addressFromPostcode != '') ? addressFromPostcode : location; 324 } 325 else if (data.address.name) { 326 location = data.address.name; 327 } 328 329 if (location) { 330 marker.bindPopup(location); 331 } 332 } 333 self.mapMarkers[componentName] = self.mapMarkers[componentName] || []; 334 self.mapMarkers[componentName].push(marker); 335 336 // TODO: this needs to be in the map init section? 337 if (self.confData[componentName].hue) { 338 var hueObj = self.confData[componentName].hue, 339 hueStylers = hueObj.stylers, 340 // @todo: Maybe find a way to convert gama, lightness and the hue (rbg color by some reason) into a rgb? 341 gama = hueStylers[0].gama, 342 lightness = hueStylers[1].lightness, 343 hue = hueStylers[2].hue; 344 345 if (hue !== "none") { 346 $(mapElement).css("background-color", hue); 347 $("div.leaflet-tile-pane", mapElement).css("opacity", "0.9"); 348 } 349 } 350 351 // Add the markers to the map 352 if (self.selfCount[componentName] >= self.confData[componentName].locations.length) { 353 var markerGroup = L.featureGroup(self.mapMarkers[componentName]).addTo(self.mapInstance[componentName]); 354 355 // Center the map if more then one marker 356 if (self.mapMarkers[componentName].length > 1 && self.confData[componentName].fitBounds) { 357 self.mapCenter(componentName, markerGroup); 358 } 359 360 // Open the info window if the setting is set 361 if (self.confData[componentName].alwaysShowInfoWindow) { 362 self.mapMarkers[componentName][self.mapMarkers[componentName].length - 1].openPopup(); 363 } 364 } 365 } else { 366 console.log("No data found."); 367 } 368 }; 369 370 /** 371 * PLE specific to change text based on clicked location 372 */ 373 function pleMap(){ 374 var locationFields = [ 375 { 376 selector: '.map-search__location-distance h3 b', 377 property: 'title', 378 type: 'text' 379 }, 380 { 381 selector: '.map-search__location-address p', 382 property: 'address_format', 383 type: 'text' 384 }, 385 { 386 selector: '.map-search__location-phone', 387 property: 'phone', 388 type: 'text' 389 }, 390 { 391 selector: '.map-search__location-phone2', 392 property: 'phone2', 393 type: 'text' 394 }, 395 { 396 selector: '.map-search__location-fax', 397 property: 'fax', 398 type: 'text' 399 }, 400 { 401 selector: '.map-search__location-directions a', 402 property: ['cta','buttonText'], 403 type: 'text' 404 }, 405 { 406 selector: '.map-search__location-directions a', 407 property: ['cta','linkPage'], 408 type: 'href' 409 }, 410 { 411 selector: '.map-search__email', 412 property: 'email', 413 type: 'text' 414 } 415 ]; 416 417 $('#gmap-location-list').on('click', '.gmap-location a', function (event) { 418 event.preventDefault(); 419 var componentName = $(this).closest('[data-component-name]').data('componentName'); 420 var locations = window.webManagerMap.confData[componentName].locations; 421 var clickedID = $(this).parent().attr('id'); 422 var location = locations.find(function(obj) { 423 return obj.ID === clickedID 424 }); 425 426 locationFields.forEach(function (field, i) { 427 var loc = {}; 428 var prop = field.property; 429 if(typeof prop === 'string' || prop instanceof String){ 430 loc = location[prop] 431 }else{ 432 var lc = location;
433 prop.forEach(function (pr) { 434 lc = lc[pr]; 435 }); 436 loc = lc; 437 } 438 if( typeof loc === 'string' || loc instanceof String){ 439 if(field.type === 'text'){ 440 $(field.selector).text(loc); 441 }else if(field.type === 'href'){ 442 $(field.selector).attr('href', loc); 443 } 444 if(loc.length > 0 ){ 445 $(field.selector).show(); 446 }else{ 447 $(field.selector).hide(); 448 } 449 }else{ 450 var vals = Object.values(Object.keys(location[prop]).map(function(e) { 451 return location[prop][e]; 452 })); 453 $(field.selector).html(vals.join("<br>")); 454 } 455 }); 456 }); 457 } 458 459 $(document).ready( 460 function () { 461 window.webManagerMap = new WebManagerMap(); 462 463 if($('.map-a').length > 0){ 464 pleMap(); 465 } 466 } 467 ); 468})(window.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.