1var locationsFull; 2 3var Locations = { 4 5 locationType: getParameterByName('location_type') ? getParameterByName('location_type').split(',') : [], 6 zip: getParameterByName('zip') || '', 7 distance: parseInt(getParameterByName('distance')) || 25, 8 9 // this is set for location subpages 10 locationsOfType: false, 11 12 zipCoords: null, 13 filterChange: true, 14 15 locations: null, 16 locationsFiltered: null, 17 map: null, 18 markers: [], 19 geocoder: null, 20 locationId: false, 21 infoWindow: null, 22 apiUrl: null, 23 24 page: 0, 25 resultsPerPage: 9, 26 27 container: null, 28 29 defaults: { 30 hours: { 31 store: null, 32 dc: null, 33 cc: null 34 } 35 }, 36 37 // set this for individual location pages 38 locationId: null, 39 currentLocation: null, 40 41 42 init: function(){ 43 44 // setup page for individual location types 45 if( document.location.pathname.indexOf("locations/donation-centers") !== -1 ){ 46 this.locationType = ["donation-center"]; 47 this.locationsOfType = true; 48 } 49 50 if( document.location.pathname.indexOf("locations/career-centers") !== -1 ){ 51 this.locationType = ["career-center"]; 52 this.locationsOfType = true; 53 } 54 55 if( document.location.pathname.indexOf("locations/stores") !== -1 ){ 56 this.locationType = ["store"]; 57 this.locationsOfType = true; 58 } 59 60 61 if( this.zip ){ 62 $('input[name=location-zip]').val(this.zip); 63 } 64 65 if( this.distance !== 25 ){ 66 $('select[name=distance]').val(this.distance); 67 } 68 69 for( var i = 0; i < this.locationType.length; i ++ ){ 70 $('.location-type-filters input[value=' + this.locationType[i] + ']').prop("checked", true); 71 } 72 73 74 this.locationId = $('#locations-app').attr('location-id'); 75 76 var maxZoom = 12; 77 78 if( this.locationId ){ 79 maxZoom = 18; 80 } 81 82 83 if( !this.locationsOfType ){ 84 this.map = new google.maps.Map(document.getElementById('locations-map'), { 85 center: new google.maps.LatLng(33.753746, -84.386330), 86 zoom: 8, 87 maxZoom: maxZoom, 88 disableDefaultUI: true, 89 styles: [ 90 { 91 "featureType": "landscape", 92 "elementType": "geometry.fill", 93 "stylers": [ 94 { 95 "color": "#e8f5ff" 96 } 97 ] 98 }, 99 { 100 "featureType": "road.highway", 101 "elementType": "geometry.fill", 102 "stylers": [ 103 { 104 "color": "#0068b3" 105 } 106 ] 107 } 108 ] 109 }); 110 111 112 } 113 114 this.geocoder = new google.maps.Geocoder(); 115 116 this.apiUrl = $('#locations-app').data('apiurl'); 117 118 119 if( this.locationId ){ 120 this.page = 0; 121 this.resultsPerPage = 3; 122 //this.container = $('.nearby-locations-grid'); 123 124 this.markerHandler(this.getCurrentLocationInfo()); 125 } else { 126 this.container = $('.locations-grid .row'); 127 } 128 129 130 var that = this; 131 132 $.post( 133 that.apiUrl, 134 {}, 135 function(data) { 136 that.locations = data; 137 that.locationsFiltered = data; 138 that.loadDefaults(); 139 140 if( !that.locationId ){ 141 that.checkGeocoding(); 142 } else { 143 that.setCurrentLocation(); 144 } 145 } 146 ); 147 }, 148 149 getCurrentLocationInfo: function(){ 150 var el = $('.location-information-hidden'); 151 152 var obj = { 153 post_title: $('.hero-content h1').text(), 154 acf: { 155 latitude: el.attr('data-latitude'), 156 longitude: el.attr('data-longitude'), 157 address_line_1: el.attr('data-address1'), 158 address_line_2: el.attr('data-address2'), 159 city: el.attr('data-city'), 160 state: el.attr('data-state'), 161 zip: el.attr('data-zip'), 162 phone_number: $('.hours .location-hours-item').first().find('phone a').text(), 163 } 164 }; 165 166 167 return obj;
168 }, 169 170 setCurrentLocation: function(){ 171 for( var i = 0; i < this.locations.length; i++ ){ 172 if( this.locations[i].ID == this.locationId ){ 173 this.currentLocation = this.locations[i]; 174 this.zip = this.currentLocation.acf.zip; 175 break; 176 } 177 } 178 179 this.checkGeocoding(); 180 }, 181 182 checkGeocoding: function(){ 183 var that = this; 184 185 if( this.zip && !this.zipCoords ){ 186 var zip = this.zip.toLowerCase(); 187 if(String.prototype.endsWith && !zip.endsWith('ga') && !zip.endsWith('georgia')) { 188 zip += ' GA'; 189 } 190 191 this.geocoder.geocode( 192 { 'address': zip }, 193 function(results, status){ 194 if( status == "OK" ){ 195 that.zipCoords = results[0].geometry.location.toJSON(); 196 that.filter(); 197 } else { 198 if( status === "ZERO_RESULTS" ){ 199 //console.log('handling zero results'); 200 that.zipCoords = "none"; 201 that.filter(); 202 } else { 203 console.log("geocoding error: " + status) 204 } 205 } 206 } 207 ) 208 } else { 209 this.filter(); 210 } 211 }, 212 213 filter: function(){ 214 215 if( this.zipCoords === "none" ){ 216 this.locationsFiltered = []; 217 } else if( this.zipCoords || this.locationType.length > 0 ){ 218 var locTemp = []; 219 220 if( this.zipCoords ){ 221 // console.log('filtering by distance'); 222 } 223 224 if( this.locationType.length > 0 ){ 225 // console.log('filtering by location type'); 226 } 227 228 for( var i = 0; i < this.locations.length; i++ ){ 229 var err = 0; 230 var loc = this.locations[i]; 231 var locLatLong = { 232 lat: loc.acf.latitude, 233 lng: loc.acf.longitude 234 } 235 236 // if individual location page check that we aren't including current location in results 237 if( this.locationId ){ 238 if( this.locationId == loc.ID ){ 239 err++; 240 } 241 } 242 243 if( this.zipCoords ){ 244 var distanceCheck = distance(this.zipCoords, locLatLong); 245 if( distanceCheck > this.distance ){ 246 err++; 247 } else { 248 loc.distance = distanceCheck; 249 } 250 } 251 252 if( this.locationType.length > 0 && this.locationType.length < 3 ){ 253 var match = 0; 254 255 for( var j = 0; j < this.locationType.length; j++ ){ 256 if( loc.location_type.indexOf(this.locationType[j]) !== -1 ){ 257 match++; 258 } 259 } 260 261 if( match === 0 ){ 262 err++; 263 } 264 } 265 266 if( err === 0 ){ 267 locTemp.push(this.locations[i]); 268 } 269 } 270 271 this.locationsFiltered = locTemp; 272 } else { 273 this.locationsFiltered = this.locations; 274 } 275 276 if( this.zipCoords ){ 277 this.locationsFiltered.sort(function(a, b){ 278 if( a.distance < b.distance ){ 279 return -1; 280 } 281 282 if( a.distance > b.distance ){ 283 return 1; 284 } 285 286 return 0; 287 }); 288 } 289 290 this.build(); 291 }, 292 293 294 295 build: function(){ 296 if( this.filterChange ){ 297 this.page = 0; 298 299 $('.locations-grid').addClass('loading'); 300 } 301 302 var start = this.page * this.resultsPerPage; 303 var end = (this.page * this.resultsPerPage) + this.resultsPerPage; 304 305 if( end >= this.locationsFiltered.length ){ 306 end = this.locationsFiltered.length; 307 $('.locations-button-bar').removeClass('active'); 308 } else { 309 $('.locations-button-bar').addClass('active'); 310 } 311 312 var html = ""; 313 314 if( this.locationsFiltered.length > 0 ){ 315 for( var i = start; i < end; i++ ){ 316 var loc = this.locationsFiltered[i]; 317 html += '' + 318 '<div class="col-12 col-md-6 col-lg-4">' + 319 '<div class="location-panel">' + 320 '<div class="title-banner">'; 321 322 323 html += '<p><a class="store-name" href="/locations/' + loc.post_name + '/">' + loc.post_title + '</a>'; 324 325 if( loc.distance ){ 326 var dist = Math.round( loc.distance * 10 ) / 10; 327 html += '<span class="distance">(' + dist + ' miles away)</span>' 328 } 329 330 html += '<span class="tags">'; 331 332 if( loc.location_type.indexOf('store') !== -1 ){ 333 html += '<i class="fa-regular fa-shop"></i>'; 334 } 335 336 if( loc.location_type.indexOf('donation-center') !== -1 ){ 337 html += '<i class="fa-light fa-box-open-full"></i>'; 338 } 339 340 if( loc.location_type.indexOf('career-center') !== -1 ){ 341 html += '<i class="fa-light fa-briefcase"></i>'; 342 } 343 344 html += '</span></p></div>'; 345 346 var address = loc.acf.address_line_1 + ", " + loc.acf.city + " " + loc.acf.state + " " + loc.acf.zip; 347 var addressEncoded = encodeURIComponent(address); 348 349 html += '<a href="https://www.google.com/maps/dir//' + addressEncoded + '" class="store-ad
349dress">' + address + '</a>'; 350 351 var currentDay = new Date().getDay(); 352 353 // console.log(loc.post_title + " : " + i); 354 355 var phoneDefault = loc.acf.phone_number; 356 var phoneDefaultStripped = phoneDefault.replaceAll("-", ""); 357 358 // get store hours/phone 359 if( loc.location_type.indexOf('store') !== -1 ){ 360 361 var hoursTemp = loc.acf.store_hours; 362 363 if( loc.acf.override_hours && hoursTemp ){ 364 hoursTemp = parseStoreHours(hoursTemp); 365 } else { 366 hoursTemp = Locations.defaults.hours.store; 367 } 368 369 html += '<p class="info-string">Store:<a href="tel:' + phoneDefaultStripped + '">' + phoneDefault + '</a><span>' + hoursTemp[currentDay] + '</span></p>'; 370 } 371 372 // get career center hours/phone 373 if( loc.location_type.indexOf('career-center') !== -1 ){ 374 375 var hoursTemp = loc.acf.career_center_hours; 376 377 if( loc.acf.override_hours && hoursTemp ){ 378 hoursTemp = parseStoreHours(hoursTemp); 379 } else { 380 hoursTemp = Locations.defaults.hours.cc; 381 } 382 383 var phoneTemp = loc.acf.career_center_phone_number || phoneDefault; 384 var stripped = phoneTemp.replaceAll("-", ""); 385 386 html += '<p class="info-string">Career Center:<a href="tel:' + stripped + '">' + phoneTemp + '</a><span>' + hoursTemp[currentDay] + '</span></p>'; 387 } 388 389 // get donation center hours/phone 390 if( loc.location_type.indexOf('donation-center') !== -1 ){ 391 392 var hoursTemp = null; 393 var phoneTemp = null; 394 395 396 // check if adc 397 if( loc.location_type.length === 1 ){ 398 hoursTemp = loc.acf.adc_hours; 399 400 if( loc.acf.override_hours && hoursTemp ){ 401 hoursTemp = parseStoreHours(hoursTemp); 402 } else { 403 hoursTemp = Locations.defaults.hours.dc; 404 } 405 406 } else { 407 hoursTemp = loc.acf.store_hours; 408 409 if( loc.acf.override_hours && hoursTemp ){ 410 hoursTemp = parseStoreHours(hoursTemp); 411 } else { 412 hoursTemp = Locations.defaults.hours.store; 413 } 414 } 415 416 phoneTemp = loc.acf.donation_center_phone_number || phoneDefault; 417 var stripped = phoneTemp.replaceAll("-", ""); 418 419 html += '<p class="info-string">Donation Center:<a href="tel:' + stripped + '">' + phoneTemp + '</a><span>' + hoursTemp[currentDay] + '</span></p>'; 420 421 422 if( loc.acf.home_pickup ){ 423 html += '<p class="instore-pickup"><a href="https://resupply.app.link/e/goodwillnorthgeorgia" target="_blank">Donation Pickups Available</a></p>'; 424 } 425 } 426 427 428 429 430 html += '<a href="/locations/' + loc.post_name + '/" class="btn btn-border">View Details</a>'; 431 432 html += "</div></div>"; 433 } 434 } else { 435 html = "<p><strong>No locations found!</strong></p>"; 436 } 437 438 if( this.filterChange ){ 439 this.container.empty(); 440 this.filterChange = false; 441 } 442 443 if( !this.locationsOfType && !this.locationId ){ 444 this.setMarkers(); 445 } 446 447 if( this.locationId ){ 448 $('.nearby-locations-grid').removeClass('loading'); 449 } else { 450 $('.locations-grid').removeClass('loading'); 451 } 452 453 454 this.container.append(html); 455 }, 456 457 458 markerHandler: function(element){ 459 that = Locations; 460 461 var lat_lng = new google.maps.LatLng(element.acf.latitude, element.acf.longitude); 462 463 var marker = new google.maps.Marker({ 464 position: lat_lng, 465 title: element.post_title, 466 icon: '/wp-content/themes/voltron/img/locations-marker.png' 467 }); 468 469 marker.setMap(that.map); 470 that.markers.push(marker); 471 472 google.maps.event.addListener(marker,"click",function(){ 473 if (that.infoWindow) { 474 that.infoWindow.close(); 475 } 476 477 if (that.locationId) { 478 address = element.acf.address_line_1 + ', '; 479 if (element.acf.address_line_2) { 480 address += element.acf.address_line_2 + ', '; 481 } 482 address += element.acf.city + ', '; 483 address += element.acf.state + ' '; 484 address += element.acf.zip; 485 486 that.infoWindow = new google.maps.InfoWindow({ 487 content: '<div class="locations-map-tooltip">' + 488 '<a href="https://www.google.com/maps/dir//' + address + '/" target="_blank" class="locations-map-tooltip-name">' + element.post_title + '</a>' + 489 element.acf.address_line_1 + '<br />' + 490 element.acf.city + ', ' + element.acf.state + ' ' + element.acf.zip + '<br />' + 491 element.acf.phone_number + 492 '<a href="https://www.google.com/maps/dir//' + address + '/" target="_blank">Get Directions</a>' + 493 '</div>' 494 }); 495 } else { 496 that.infoWindow = new google.maps.InfoWindow({ 497 content: '<div class="locations-map-tooltip">' + 498 '<a href="/location/' + element.post_name + '/" class="locations-map-tooltip-name">' + element.post_title + '</a>' + 499 element.acf.address_line_1 + '<br />' + 500 element.acf.city + ', ' + element.acf.state + ' ' + element.acf.zip + '<br />' + 501 element.acf.phone_number + 502 '<a href="/location/' + element.post_name + '/">View Details</a>' + 503 '</div>' 504 }); 505 } 506 507 that.infoWindow.open(that.map, marker); 508 }); 509 510 if (that.locationId) { 511 that.map.setZoom(16); 512 that.map.setCenter(marker.getPosition()); 513 } 514 }, 515 516 517 setMarkers: function() { 518 that = this; 519 this.clearMarkers(); 520 this.locationsFiltered.forEach(that.markerHandler); 521 522 523 if( !that.locationId ){ 524 var bounds = new google.maps.LatLngBounds(); 525 for( var i = 0; i < that.markers.length; i++ ){ 526 bounds.extend(that.markers[i].position); 527 } 528 529 that.map.fitBounds(bounds); 530 } 531 }, 532 533 clearMarkers: function() { 534 var that = this; 535 for (var i = 0; i < that.markers.length; i++ ) { 536 that.markers[i].setMap(null); 537 } 538 that.markers.length = 0; 539 }, 540
541 loadMore: function(){ 542 this.page++; 543 this.build(); 544 }, 545 546 setZip: function(zip, distance){ 547 this.zip = zip; 548 this.distance = distance; 549 this.zipCoords = null; 550 this.filterChange = true; 551 this.checkGeocoding(); 552 }, 553 554 clearZip: function(){ 555 this.zip = ""; 556 this.distance = 25; 557 this.zipCoords = null; 558 this.filterChange = true; 559 560 for( var i = 0; i < this.locations.length; i++ ){ 561 this.locations[i].distance = null; 562 } 563 564 this.checkGeocoding(); 565 }, 566 567 setLocationType: function(loc){ 568 this.locationType = loc; 569 this.filterChange = true; 570 this.checkGeocoding(); 571 }, 572 573 loadDefaults: function(){ 574 var s = $('.defaults .store-hours').text(); 575 var cc = $('.defaults .cc-hours').text(); 576 var dc = $('.defaults .dc-hours').text(); 577 578 this.defaults.hours.store = parseStoreHours(s.replaceAll("\n", ",")); 579 this.defaults.hours.cc = parseStoreHours(cc.replaceAll("\n", ",")); 580 this.defaults.hours.dc = parseStoreHours(dc.replaceAll("\n", ",")); 581 } 582} 583 584function getParameterByName(name, url) { 585 if (!url) url = window.location.href; 586 name = name.replace(/[\[\]]/g, "\\$&"); 587 var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), 588 results = regex.exec(url); 589 if (!results) return null; 590 if (!results[2]) return ''; 591 return decodeURIComponent(results[2].replace(/\+/g, " ")); 592} 593 594function distance(a, b) 595{ 596 var lat1 = a.lat; 597 var lon1 = a.lng; 598 599 var lat2 = b.lat; 600 var lon2 = b.lng; 601 602 var theta = lon1 - lon2; 603 var dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta)); 604 dist = Math.acos(dist); 605 dist = rad2deg(dist); 606 var miles = dist * 60 * 1.1515; 607 return miles; 608} 609 610function deg2rad(degrees){ 611 var pi = Math.PI; 612 return degrees * (pi/180); 613} 614 615function rad2deg(radians){ 616 var pi = Math.PI; 617 return radians * (180/pi); 618} 619 620function parseStoreHours(h){ 621 var hoursNew = ["", "", "", "", "", "", ""]; 622 623 // normalize text from text area fields 624 h = h.replaceAll("<strong>", "").replaceAll("</strong>", "").replaceAll("<br />\r\n", ","); 625 626 // check for "," at end and remove (this happens when there were extra newlines) 627 while( h[h.length-1] === "," ){ 628 h = h.substring(h,h.length-1); 629 } 630 631 632 // split each line into its own string 633 var stringArray = h.split(","); 634 635 // loop through each entry to assign to new array 636 for( var i = 0; i < stringArray.length; i++ ){ 637 var temp = stringArray[i].split(":"); 638 639 var days = temp[0].replace(" ", ""); 640 641 var hours = temp.slice(1).join(":"); 642 643 // check if string applies to multiple days 644 if( days.indexOf("-") !== -1){ 645 var dayArray = days.split("-"); 646 var startDay = getDayIndex(dayArray[0]); 647 var endDay = getDayIndex(dayArray[1]); 648 649 var done = false; 650 var dex = startDay; 651 652 while( !done ){ 653 hoursNew[dex] = hours; 654 655 if( dex === endDay ){ 656 done = true; 657 } 658 659 dex++; 660 if( dex === 7 ) dex = 0; 661 } 662 663 664 } else { 665 hoursNew[getDayIndex(days)] = hours; 666 } 667 } 668 669 // check for days that don't have hours defined. trim others 670 for( var i = 0; i < hoursNew.length; i++ ){ 671 if( hoursNew[i] === "" ){ 672 hoursNew[i] = "Closed"; 673 } else { 674 hoursNew[i] = hoursNew[i].trim(); 675 } 676 } 677 678 return hoursNew; 679} 680 681function getDayIndex(day){ 682 var cDay = day.toLowerCase(); 683 684 switch(cDay){ 685 case "sun": 686 case "sunday": 687 return 0; 688 case "mon": 689 case "monday": 690 return 1; 691 case "tue": 692 case "tues": 693 case "tuesday": 694 return 2; 695 case "wed": 696 case "wednesday": 697 return 3; 698 case "thu": 699 case "thur": 700 case "thurs": 701 case "thursday": 702 return 4; 703 case "fri": 704 case "friday": 705 return 5; 706 case "sat": 707 case "saturday": 708 return 6; 709 default: 710 // console.log("day error:" + day); 711 return 0; 712 } 713} 714 715 716 717$(document).ready(function(){ 718 if( $('#locations-app').length ){ 719 Locations.init(); 720 } 721 722 $('.load-more-locations').on('click', function(e){
723 e.preventDefault(); 724 Locations.loadMore(); 725 }); 726 727 $('.apply-location-filter').on('click', function(e){ 728 e.preventDefault(); 729 var zip = $('input[name=location-zip]').val(); 730 var distance = parseInt($('select[name=distance]').val()); 731 732 if( zip && distance ){ 733 Locations.setZip(zip, distance); 734 } else { 735 Locations.clearZip(); 736 } 737 738 }); 739 740 $('.clear-location-filter').on('click', function(e){ 741 e.preventDefault(); 742 743 var zip = $('input[name=location-zip]').val(""); 744 var distance = $('select[name=distance]').val(25); 745 746 Locations.clearZip(); 747 }); 748 749 $('.location-type-filters input').on('change', function(e){ 750 var locTypes = []; 751 752 $('.location-type-filters input').each(function(){ 753 if( $(this).is(":checked") ){ 754 locTypes.push($(this).val()); 755 } 756 }) 757 758 Locations.setLocationType(locTypes); 759 }); 760});
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.