/* globals jQuery, google, sowb */ window.sowb = window.sowb || {}; sowb.SiteOriginGoogleMap = function($) { return { // So that we can always display something, even if no location or address was entered. DEFAULT_LOCATIONS: [ 'Addo Elephant National Park, R335, Addo', 'Cape Town, Western Cape, South Africa', 'San Francisco Bay Area, CA, United States', 'New York, NY, United States', ], showMap: function(element, location, options) { var zoom = Number(options.zoom); if ( !zoom ) zoom = 14; var breakpointCheck = window.matchMedia( '(max-width: ' + options.breakpoint + 'px)' ) // Check if the user is viewing the map on mobile if ( breakpointCheck.matches ) { zoom = options.mobileZoom; } var userMapTypeId = 'user_map_style'; var mapOptions = { zoom: zoom, gestureHandling: options.gestureHandling, disableDefaultUI: options.disableUi, zoomControl: options.zoomControl, panControl: options.panControl, center: location, mapTypeControlOptions: { mapTypeIds: [ google.maps.MapTypeId.ROADMAP, google.maps.MapTypeId.SATELLITE, userMapTypeId ] } }; var map = new google.maps.Map(element, mapOptions); var userMapOptions = { name: options.mapName }; var userMapStyles = options.mapStyles; if ( userMapStyles ) { var userMapType = new google.maps.StyledMapType(userMapStyles, userMapOptions); map.mapTypes.set(userMapTypeId, userMapType); map.setMapTypeId(userMapTypeId); } if (options.markerAtCenter) { this.centerMarker = new google.maps.Marker({ position: location, map: map, draggable: options.markersDraggable, icon: options.markerIcon, title: '' }); } if(options.keepCentered) { var center; google.maps.event.addDomListener(map, 'idle', function () { center = map.getCenter(); }); google.maps.event.addDomListener(window, 'resize', function () { map.setCenter(center); }); } this.linkAutocompleteField(options.autocomplete, options.autocompleteElement, map, options); this.showMarkers(options.markerPositions, map, options); this.showDirections(options.directions, map, options); }, linkAutocompleteField: function (autocomplete, autocompleteElement, map, options) { if( autocomplete && autocompleteElement ) { var updateMapLocation = function ( address ) { if ( this.inputAddress !== address ) { this.inputAddress = address; this.getLocation( this.inputAddress ).done( function ( location ) { map.setZoom( 15 ); map.setCenter( location ); if( this.centerMarker ) { this.centerMarker.setPosition( location ); this.centerMarker.setTitle( this.inputAddress ); } }.bind( this ) ); } }.bind( this ); var $autocompleteElement = $( autocompleteElement ); autocomplete.addListener( 'place_changed', function () { var place = autocomplete.getPlace(); map.setZoom( 15 ); if ( place.geometry ) { map.setCenter( place.geometry.location ); if( this.centerMarker ) { this.centerMarker.setPosition(place.geometry.location); } } }.bind( this ) ); google.maps.event.addDomListener( autocompleteElement, 'keypress', function ( event ) { var key = event.keyCode || event.which; if ( key === '13' ) { event.preventDefault(); } } ); $autocompleteElement.focusin( function () { if ( !this.resultsObserver ) { var autocompleteResultsContainer = document.querySelector( '.pac-container' ); this.resultsObserver = new MutationObserver( function () { var $topResult = $( $( '.pac-item' ).get( 0 ) ); var queryPartA = $topResult.find( '.pac-item-query' ).text(); var queryPartB = $topResult.find( 'span' ).not( '[class]' ).text(); var topQuery = queryPartA + ( queryPartB ? (', ' + queryPartB) : '' ); if ( topQuery ) { updateMapLocation( topQuery ); } } ); var config = { attributes: true, childList: true, characterData: true }; this.resultsObserver.observe( autocompleteResultsContainer, config ); } }.bind( this ) ); var revGeocode = function ( latLng ) { this.getGeocoder().geocode( { location: latLng }, function ( results, status ) { if ( status === google.maps.GeocoderStatus.OK ) { if ( results.length > 0 ) { var addr = results[ 0 ].formatted_address; $autocompleteElement.val( addr ); if( this.centerMarker ) { this.centerMarker.setPosition(latLng); this.centerMarker.setTitle(addr); } } } }.bind( this ) ); }.bind( this ); map.addListener( 'click', function ( event ) { revGeocode( event.latLng ); } ); this.centerMarker.addListener( 'dragend', function ( event ) { revGeocode( event.latLng ); } ); } }, showMarkers: function(markerPositions, map, options) { if ( markerPositions && markerPositions.length ) { this.infoWindows = []; var markerBatches = []; var BATCH_SIZE = 10; // Group markers into batches of 10 in attempt to avoid query limits for ( var i = 0; i < markerPositions.length; i++ ) { var batchIndex = parseInt( i / BATCH_SIZE ); // truncate decimals if ( markerBatches.length === batchIndex ) { markerBatches[ batchIndex ] = []; } markerBatches[ batchIndex ][ i % BATCH_SIZE ] = markerPositions[ i ]; } var geocodeMarker = function ( mrkr ) { var customIcon = mrkr.custom_marker_icon; var markerInfo = mrkr.hasOwnProperty( 'info' ) ? mrkr.info : null; var infoMaxWidth = mrkr.hasOwnProperty( 'info_max_width' ) ? mrkr.info_max_width : null; return this.getLocation( mrkr.place ).done( function ( location ) { var mrkerIcon = options.markerIcon; if ( customIcon ) { mrkerIcon = customIcon; } var marker = new google.maps.Marker( { position: location, map: map, draggable: options.markersDraggable, icon: mrkerIcon, title: '' } ); if ( markerInfo ) { var infoWindowOptions = { content: markerInfo }; if ( infoMaxWidth ) { infoWindowOptions.maxWidth = infoMaxWidth; } var infoDisplay = options.markerInfoDisplay; infoWindowOptions.disableAutoPan = infoDisplay === 'always'; var infoWindow = new google.maps.InfoWindow( infoWindowOptions ); this.infoWindows.push( infoWindow ); var openEvent = infoDisplay; if ( infoDisplay === 'always' ) { openEvent = 'click'; infoWindow.open( map, marker ); } marker.addListener( openEvent, function () { infoWindow.open( map, marker ); if ( infoDisplay !== 'always' && !options.markerInfoMultiple ) { this.infoWindows.forEach( function ( iw ) { if ( iw !== infoWindow ) { iw.close(); } } ); } }.bind( this ) ); if ( infoDisplay === 'mouseover' ) { marker.addListener( 'mouseout', function () { setTimeout( function () { infoWindow.close(); }, 100 ); } ); } } }.bind( this ) ) .fail( function ( errorStatus ) { overQuota = errorStatus === google.maps.GeocoderStatus.OVER_QUERY_LIMIT; console.log( errorStatus ); } ); }.bind( this ); var overQuota = false; var geocodeMarkerBatch = function ( markerBatchHead, markerBatchTail ) { var doneCount = 0; for ( var i = 0; i < markerBatchHead.length; i++ ) { // If we're over the quota we want to stop making any more requests. if ( overQuota ) { break; } geocodeMarker( markerBatchHead[ i ] ).then( function () { if ( ++doneCount === markerBatchHead.length && markerBatchTail.length ) { geocodeMarkerBatch( markerBatchTail.shift(), markerBatchTail ); } } ); } }.bind( this ); geocodeMarkerBatch( markerBatches.shift(), markerBatches ); } }, showDirections: function(directions, map) { if ( directions ) { if ( directions.waypoints && directions.waypoints.length ) { directions.waypoints.map( function (wypt) { wypt.stopover = Boolean(wypt.stopover); } ); } var directionsRenderer = new google.maps.DirectionsRenderer(); directionsRenderer.setMap(map); var directionsService = new google.maps.DirectionsService(); directionsService.route({ origin: directions.origin, destination: directions.destination, travelMode: directions.travelMode.toUpperCase(), avoidHighways: directions.avoidHighways, avoidTolls: directions.avoidTolls, waypoints: directions.waypoints, optimizeWaypoints: directions.optimizeWaypoints, }, function(result, status) { if (status === google.maps.DirectionsStatus.OK) { directionsRenderer.setOptions( { preserveViewport: directions.preserveViewport } ); directionsRenderer.setDirections(result); } }); } }, initMaps: function() { // Init any autocomplete fields first. var $autoCompleteFields = $( '.sow-google-map-autocomplete' ); var autoCompleteInit = new $.Deferred(); if( $autoCompleteFields.length === 0 ) { autoCompleteInit.resolve(); } else { $autoCompleteFields.each(function (index, element) { if ( typeof google.maps.places === 'undefined' ) { autoCompleteInit.reject('Sorry, we couldn\'t load the "places" library due to another plugin, so the autocomplete feature is not available.'); return; } var autocomplete = new google.maps.places.Autocomplete( element ); var $mapField = $(element).siblings('.sow-google-map-canvas'); if ($mapField.length > 0) { var options = $mapField.data('options'); options.autocomplete = autocomplete; options.autocompleteElement = element; this.getLocation(options.address).done( function (location) { this.showMap($mapField.get(0), location, options); $mapField.data('initialized', true); autoCompleteInit.resolve(); }.bind(this) ).fail(function () { $mapField.append('
' + soWidgetsGoogleMap.geocode.noResults + '
' + soWidgetsGoogleMap.geocode.noResults + '