1"use strict"; 2 3(function() { 4 var map, 5 stores, 6 circle, 7 infoWindow, 8 userLocation, 9 markers = [], 10 matchedStores = [], 11 numStoresToList = 5, 12 selectedMarker; 13 14 function isMobile() { 15 return window.matchMedia && window.matchMedia("screen and (max-width: 767px)").matches; 16 } 17 18 var icons = { 19 1: "food", 20 2: "travel", 21 3: "funeral", 22 4: "childcare", 23 5: "healthcare", 24 6: "postoffice" 25 }; 26 27 var services = { 28 1: "Food", 29 2: "Travel", 30 3: "Funeralcare", 31 4: "Childcare", 32 5: "Healthcare", 33 6: "Post Office" 34 }; 35 36 function createTimePair(open, close) { 37 if (open == "Closed" || close == "Closed") { 38 return "Closed"; 39 } 40 if (!open || !close) return "-"; 41 42 var openString = open.replace(".", ":"); 43 var closeString = close.replace(".", ":"); 44 45 if (openString == "24:00") { 46 openString = "00:00"; 47 } 48 49 if (openString.length == 4) openString = "0" + openString; 50 if (closeString.length == 4) closeString = "0" + closeString; 51 52 return openString + " - " + closeString; 53 } 54 55 function getPhone(marker) { 56 var phone = ""; 57 if (marker.data.telephone) { 58 phone = '<p>Telephone: <a href="tel:' + marker.data.telephone.replace(/ /g, "") + '"><strong>' + marker.data.telephone + '</strong></a></p>'; 59 } 60 return phone; 61 } 62 63 function getAdditionalInfo(marker) { 64 var additionalInfo = ""; 65 if (marker.data.text) { 66 additionalInfo = "<p class=\"additionalInfo\">" + marker.data.text + "</p>"; 67 } 68 return additionalInfo; 69 } 70 71 function getStoreType(marker) { 72 return '<strong class="' + icons[marker.data.tradingGroupId] + '">' + services[marker.data.tradingGroupId] + '</strong>' 73 } 74 75 function getStoreName(marker) { 76 return '<h2 style="margin-top: 0;">' + (marker.data.name ? marker.data.name : marker.data.town) + '</h2>' 77 } 78 79 function getAddress(marker) { 80 var addresslines = []; 81 if (marker.data.addressLine1) { addresslines.push(marker.data.addressLine1); } 82 if (marker.data.addressLine2) { addresslines.push(marker.data.addressLine2); } 83 if (marker.data.addressLine3) { addresslines.push(marker.data.addressLine3); } 84 if (marker.data.town) { addresslines.push(marker.data.town); } 85 if (marker.data.county) { addresslines.push(marker.data.county); } 86 if (marker.data.postcode) { addresslines.push(marker.data.postcode); } 87 88 return '<p>' + addresslines.join(", ") + '</p>'; 89 } 90 91 function getOpeningHours(marker) { 92 var times = ""; 93 if (marker.data.mondayOpen && marker.data.mondayClose) { 94 var extraText = ''; 95 if (marker.data.byAppointmentOnly) { 96 extraText = '<h3 class="openingHours" style="margin-top:0;">By Telephone Appointment Only</h3>'; 97 } 98 times = '<h3 class="openingHours">Opening Hours:</h3>' + extraText + 99 '<table class="table">' + 100 ' <tr><td><strong>Monday</strong></td><td> ' + createTimePair(marker.data.mondayOpen, marker.data.mondayClose) + '</td></tr> ' + 101 ' <tr><td><strong>Tuesday</strong></td><td> ' + createTimePair(marker.data.tuesdayOpen, marker.data.tuesdayClose) + '</td></tr> ' + 102 ' <tr><td><strong>Wednesday</strong></td><td> ' + createTimePair(marker.data.wednesdayOpen, marker.data.wednesdayClose) + '</td></tr> ' + 103 ' <tr><td><strong>Thursday</strong></td><td> ' + createTimePair(marker.data.thursdayOpen, marker.data.thursdayClose) + '</td></tr> ' + 104 ' <tr><td><strong>Friday</strong></td><td> ' + createTimePair(marker.data.fridayOpen, marker.data.fridayClose) + '</td></tr> ' + 105 ' <tr><td><strong>Saturday</strong></td><td> ' + createTimePair(marker.data.saturdayOpen, marker.data.saturdayClose) + '</td></tr> ' + 106 ' <tr><td><strong>Sunday</strong></td><td> ' + createTimePair(marker.data.sundayOpen, marker.data.sundayClose) + '</td></tr>' + 107 '</table>'; 108 } 109 return times; 110 } 111 112 function largestBoundingArea(b1, b2) { 113 var b1size = google.maps.geometry.spherical.computeDistanceBetween(b1.getNorthEast(), b1.getSouthWest
113()); 114 var b2size = google.maps.geometry.spherical.computeDistanceBetween(b2.getNorthEast(), b2.getSouthWest()); 115 116 if (b1size > b2size) { 117 return b1; 118 } 119 120 return b2; 121 } 122 123 function shiftMarker(marker, x, y) { 124 var markerpos = new google.maps.LatLng(marker.getPosition().lat() + y, marker.getPosition().lng() + x); 125 marker.setPosition(markerpos); 126 } 127 128 129 jQuery(function ($) { 130 var url = $("#storesMap").data("json-uri"), 131 icon = $("#storesMap").data("icon"); 132 133 function getRadius() { 134 var radius; 135 136 if ($("#radius").val()) { 137 radius = parseInt($("#radius").val(), 10) / 0.621371 * 1000; 138 } 139 return radius; 140 } 141 142 if (!navigator.geolocation) { 143 $(".storesMapControlUseMyLocation").hide(); 144 } else { 145 $(".storesMapControlUseMyLocation .btn").click(function (e) { 146 e.preventDefault(); 147 148 var btn = $(this); 149 if (typeof(ga) != "undefined") { 150 ga('send', 'event', 'StoreLocator', 'Search', 'Geolocation'); 151 } 152 153 btn.addClass("active"); 154 155 navigator.geolocation.getCurrentPosition(function (position) { 156 $("#postcode").val(""); 157 btn.removeClass("active"); 158 var pos = { 159 location: new google.maps.LatLng(position.coords.latitude, position.coords.longitude) 160 }; 161 162 map.setCenter(pos.location); 163 164 search(pos, getRadius()); 165 }, function (err) { 166 btn.removeClass("active"); 167 alert("Sorry, the geolocation service failed to fetch your current location. Error: " + err.message); 168 }, { 169 maximumAge: 60000, 170 timeout: 5000, 171 enableHighAccuracy: true 172 }); 173 }); 174 } 175 176 function filterStores(index, matchedStores) { 177 var matchedStoresNumber = matchedStores.length; 178 var filteredStores = matchedStores.slice(index, index + numStoresToList); 179 $(".storesMapResults ul").html(""); 180 181 for (var j in filteredStores) { 182 var storeResult = $($("#storeResult").html() 183 .replace("{name}", filteredStores[j].name) 184 .replace("{type}", services[filteredStores[j].tradingGroupId]) 185 .replace("{typeClass}", icons[filteredStores[j].tradingGroupId]) 186 .replace("{mileage}", Math.round(filteredStores[j].distance * 10) / 10 + " miles")); 187 storeResult.data("marker", filteredStores[j].marker); 188 $(".storesMapResults ul").append(storeResult); 189 } 190 191 var showPrev = index >= numStoresToList; 192 var showNext = index + filteredStores.length < matchedStores.length; 193 194 if (showPrev || showNext) { 195 196 $(".storesMapResults ul").append("<li class='list-group-item storesMapResultsPager'></li>"); 197 198 if (index >= numStoresToList) { 199 $(".storesMapResultsPager") 200 .append("<a href='#' class='storesMapResultsViewPage storesMapResultsViewPrevious' data-index='" + (Math.max(index - numStoresToList, 0)) + "'><span class='fa fa-chevron-left'></span> Previous</a>"); 201 } 202 203 if (index + filteredStores.length < matchedStores.length) { 204 205 $(".storesMapResultsPager") 206 .append("<a href='#' class='storesMapResultsViewPage storesMapResultsViewNext' data-index='" + (index + filteredStores.length) + "'>Next <span class='fa fa-chevron-right'></span></a>"); 207 208 } 209 210 } 211 212 $(".storesMapResults ul").append("<li class='visible-xs list-group-item storesMapResultsViewMap'><span class='fa fa-chevron-right'></span>View results on a map</li>"); 213 214 $(".storesMapResultsViewPage").click(function (e) { 215 e.preventDefault(); 216 e.stopPropagation(); 217 filterStores($(this).data("index"), matchedStores); 218 }); 219 220 $(".storesMapResultsNumber").html("<strong>" + matchedStoresNumber + "</strong> store" + (matchedStoresNumber == 1 ? " was" : "s were") + " matched:"); 221 222 $(".storesMapResults").show(); 223 224 if (isMobile()) { 225 $(window).scrollTop($(".storesMapResults").offset().top - 15); 226 } 227 }; 228 229 function search(position, radius) { 230 var distances = []; 231 var closest = -1; 232 233 var tradingGroup; 234 if ($("#business").val()) { 235 tradingGroup = parseInt($("#business").val(), 10); 236 } 237 238 $(".gm-style").animate({ 239 opacity: 1 240 }, 500); 241 242 matchedStores = []; 243 244 for (var i = 0; i < markers.length; i++) { 245 var distance = google.maps.geometry.spherical.computeDistanceBetween(position.location, markers[i].position); 246
247 if ((!radius || distance < radius) && (!tradingGroup || markers[i].data.tradingGroupId == tradingGroup)) { 248 markers[i].data.distance = distance * 0.621371 / 1000;//meters to miles 249 distances[i] = distance; 250 if (closest == -1 || distance < distances[closest]) { 251 closest = i; 252 } 253 markers[i].data.marker = markers[i]; 254 matchedStores.push(markers[i].data); 255 markers[i].setMap(map); 256 } else { 257 markers[i].setMap(null); 258 delete markers[i].data.distance; 259 } 260 } 261 262 matchedStores.sort(function (a, b) { 263 if (!a.distance && !b.distance) return 0; 264 if (!a.distance && b.distance) return 1; 265 if (a.distance && !b.distance) return -1; 266 return a.distance - b.distance; 267 }); 268 269 if (matchedStores.length > 0) { 270 filterStores(0, matchedStores); 271 } else { 272 $(".storesMapResults").show(); 273 $(".storesMapResults ul").html(""); 274 $(".storesMapResultsNumber").html("<strong>0</strong> stores were matched"); 275 } 276 277 var home_marker_image = new google.maps.MarkerImage( 278 icon.replace("{type}", "location"), 279 new google.maps.Size(37, 55), 280 new google.maps.Point(0, 0), 281 new google.maps.Point(18, 54) 282 ); 283 284 if (circle) circle.setMap(null); 285 if (radius && !$("body").hasClass("ie6-8")) { 286 circle = new google.maps.Circle({ 287 center: position.location, 288 radius: radius, 289 fillOpacity: 0.1, 290 fillColor: "#0051a1", 291 strokeOpacity: 0.4, 292 strokeColor: "#0051a1", 293 map: map, 294 clickable: false 295 }); 296 } 297 298 if (userLocation) { 299 userLocation.setMap(null); 300 } 301 userLocation = new google.maps.Marker({ 302 position: new google.maps.LatLng(position.location.lat(), position.location.lng()), 303 map: map, 304 title: "Your Location", 305 icon: home_marker_image 306 }); 307 308 if (closest >= 0) { 309 // Create a new viewpoint bound 310 var bounds = new google.maps.LatLngBounds(); 311 312 bounds.extend(markers[closest].position); 313 bounds.extend(position.location); 314 // Fit these bounds to the map 315 if (position.bounds) { 316 map.fitBounds(largestBoundingArea(position.bounds, bounds)); 317 } 318 else { 319 map.fitBounds(bounds); 320 } 321 } 322 } 323 324 function showStoreResult(marker) { 325 if (selectedMarker) selectedMarker.setAnimation(null); 326 selectedMarker = marker; 327 setTimeout(function () { marker.setAnimation(google.maps.Animation.BOUNCE) }, 10); 328 map.setCenter(marker.position); 329 330 $(".storesMapResultInfo").html("") 331 .append(getStoreName(marker)) 332 .append(getStoreType(marker)) 333 .append(getPhone(marker)) 334 .append(getAddress(marker).replace(/, /ig, "<br/>")) 335 .append(getOpeningHours(marker)) 336 .append(getAdditionalInfo(marker)); 337 $(".storesMapResultOpeningHours").html(getOpeningHours(marker)); 338 $(".storesMapResultButtonDirections").attr("href", "https://www.google.co.uk/maps/dir/" + encodeURIComponent($("#postcode").val()) + "/" + encodeURIComponent(marker.data.latitude + "," + marker.data.longitude)); 339 340 if (typeof (marker.data.branchNumber) != "undefined") { 341 $(".storesMapResultButtonEvents").show(); 342 $(".storesMapResultButtonEvents").attr("href", $(".storesMapResultButtonEvents").attr("href").replace(/branch=.*/, "branch=" + marker.data.branchNumber)); 343 } else { 344 $(".storesMapResultButtonEvents").hide(); 345 } 346 347 $(".storesMapResult").show(); 348 $(".storesMapResults").hide(); 349 350 if (isMobile()) { 351 $(window).scrollTop($(".storesMapResult").offset().top - 15); 352 } 353 354 if (typeof(ga) != "undefined") { 355 ga('send', 'event', 'StoreLocator', 'Store Click', services[marker.data.tradingGroupId], marker.data.branchNumber); 356 } 357 } 358 359 $(window).resize(function () { 360 if (!isMobile()) { 361 $("#map").show(); 362 } 363 }); 364 365 window.initMap = function () { 366 var stacks = {}; 367 368 map = new google.maps.Map(document.getElementById('map'), { 369 center: { lat: 52.0587023, lng: -1.01720467 }, 370 zoomControl: true, 371 scrollwheel: false, 372 streetViewControl: false, 373 zoom: 8 374 }); 375 376 function markerPopup() { 377 showStoreResult(this); 378 }; 379 380 function fadeIn() { 381 $(".gm-style").animate({ 382 opacity: 1 383 }, 500); 384 } 385 386 map.addListener("click", fadeIn); 387 map.addListener("center_changed", fadeIn); 388 389 $("#mapSearch").submit(function (e) { 390 e.preventDefault(); 391 392 if (typeof(ga) != "undefined") { 393 ga('send', 'event', 'StoreLocator', 'Search', 'Postcode'); 394 } 395 396 var locationName = $("#postcode").val(); 397 398 if (locationName) { 399 var geocoder = new google.maps.Geocoder(); 400 geocoder.geocode({ address: locationName + ", UK" }, function (result, status) { 401 if (status == "OK") { 402 search(result[0].geometry, getRadius()); 403 } 404 }); 405 } else { 406 alert("Please enter a postcode or town"); 407 } 408 }); 409 410 $(document).on("click", ".storesMapResultClose", function (e) { 411 e.preventDefault(); 412 $(".storesMapResult").hide(); 413 if (matchedStores.length > 0) $(".storesMapResults").show(); 414 }); 415 416 $(document).on("click", ".storesMapResults li", function (e) { 417 e.preventDefault(); 418 419 if (!$(this).is(".storesMapResultsPager")) { 420 421 var marker = $(this).data("marker"); 422 if (marker) { 423 showStoreResult(marker); 424 } else { 425 $("#map").show(); 426 $(this).remove(); 427 google.maps.event.trigger(map, 'resize'); 428 map.setCenter(userLocation.position); 429 map.setZoom(13); 430 $(".btnBackToResults").show(); 431 if (isMobile()) { 432 $(window).scrollTop($("#map").offset().top - 15); 433 } 434 } 435 } 436 }); 437 438 $(".btnBackToResults").click(function (e) { 439 e.preventDefault(); 440 if (isMobile()) { 441 $(window).scrollTop($(".storesMapFilters").offset().top + $(".storesMapFilters").outerHeight()); 442 } 443 }); 444 445 $.ajax({
446 url: url, 447 dataType: 'json', 448 error: function(err) { 449 alert("There was an error loading our store data, please try again.") 450 }, 451 success: function (data) { 452 stores = data.stores; 453 454 for (var i in stores) { 455 var iconType = icons[stores[i].tradingGroupId]; 456 457 var marker = new google.maps.Marker({ 458 position: { lat: stores[i].latitude, lng: stores[i].longitude }, 459 map: map, 460 title: stores[i].name, 461 icon: icon.replace("{type}", iconType), 462 data: stores[i] 463 }); 464 465 marker.showInfo = markerPopup; 466 467 google.maps.event.addListener(marker, 'click', function (event) { 468 this.showInfo(); 469 }); 470 471 var dupeId = marker.data.latitude + "," + marker.data.longitude; 472 if (!stacks[dupeId]) { 473 stacks[dupeId] = []; 474 } 475 stacks[dupeId].push(marker); 476 477 markers.push(marker); 478 } 479 480 var stackCount = 0; 481 for (i in stacks) { 482 stackCount++; 483 if (stacks[i].length == 1) { 484 delete stacks[i]; 485 stackCount--; 486 } else { 487 //pull any stacks apart 488 switch (stacks[i].length) { 489 case 2: 490 shiftMarker(stacks[i][0], -0.0001, 0); 491 shiftMarker(stacks[i][1], 0.0001, 0); 492 break; 493 case 3: 494 shiftMarker(stacks[i][0], -0.00011, 0); 495 shiftMarker(stacks[i][1], 0, 0.0001); 496 shiftMarker(stacks[i][2], 0.00011, 0); 497 498 499 break; 500 case 4: 501 shiftMarker(stacks[i][0], -0.0001, 0.00007); 502 shiftMarker(stacks[i][1], 0.0001, 0.00007); 503 shiftMarker(stacks[i][2], -0.0001, -0.00007); 504 shiftMarker(stacks[i][3], 0.0001, -0.00007); 505 break; 506 case 5: 507 shiftMarker(stacks[i][0], 0, 0.0001); 508 shiftMarker(stacks[i][1], 0.0001, 0.00008); 509 shiftMarker(stacks[i][2], -0.0001, -0.00008); 510 shiftMarker(stacks[i][3], 0.00009, -0.00003); 511 shiftMarker(stacks[i][4], -0.00009, -0.00003); 512 break; 513 } 514 } 515 } 516
517 if (window.urlParams && window.urlParams["$location"] && window.urlParams["$location"] != "") { 518 $("#postcode").val(window.urlParams["$location"]); 519 } 520 521 if (window.urlParams && window.urlParams["$service"] && window.urlParams["$service"] != "") { 522 var oldservices = { 523 "food" : 1, 524 "travel" : 2, 525 "funeralcare" : 3, 526 "childcare" : 4, 527 "pharmacy" : 5, 528 "postoffice" : 6 529 }; 530 $("#business").val(oldservices[window.urlParams["$service"]]); 531 } 532 533 if ($("#postcode").val()) { 534 $(".btnStoresSearch").click(); 535 } 536 } 537 }); 538 } 539 }); 540 541})();
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.