@@ -7,6 +7,7 @@ var EventEmitter = require('events').EventEmitter;
77var exceptions = require ( './exceptions' ) ;
88var MapboxClient = require ( '@mapbox/mapbox-sdk' ) ;
99var mbxGeocoder = require ( '@mapbox/mapbox-sdk/services/geocoding' ) ;
10+ var mbxGeocoderV6 = require ( "@mapbox/mapbox-sdk/services/geocoding-v6" ) ;
1011var MapboxEventManager = require ( './events' ) ;
1112var localization = require ( './localization' ) ;
1213var subtag = require ( 'subtag' ) ;
@@ -31,6 +32,36 @@ function getFooterNode() {
3132 return div ;
3233}
3334
35+ function getItemValue ( item ) {
36+ return item . place_name
37+ }
38+
39+ function render ( item ) {
40+ var placeName = item . place_name . split ( ',' ) ;
41+ return '<div class="mapboxgl-ctrl-geocoder--suggestion"><div class="mapboxgl-ctrl-geocoder--suggestion-title">' + placeName [ 0 ] + '</div><div class="mapboxgl-ctrl-geocoder--suggestion-address">' + placeName . splice ( 1 , placeName . length ) . join ( ',' ) + '</div></div>' ;
42+ }
43+
44+ function getItemValueV6 ( item ) {
45+ const { name, place_formatted } = item . properties ;
46+ return name + ( place_formatted ? `, ${ place_formatted } ` : "" ) ;
47+ }
48+
49+ function renderV6 ( item ) {
50+ const { name, place_formatted } = item . properties ;
51+ return `<div class="mapboxgl-ctrl-geocoder--suggestion">
52+ ${
53+ name
54+ ? `<div class="mapboxgl-ctrl-geocoder--suggestion-title">${ name } </div>`
55+ : ""
56+ }
57+ ${
58+ place_formatted
59+ ? `<div class="mapboxgl-ctrl-geocoder--suggestion-address">${ place_formatted } </div>`
60+ : ""
61+ }
62+ </div>` ;
63+ }
64+
3465/**
3566 * A geocoder component using the [Mapbox Geocoding API](https://docs.mapbox.com/api/search/#geocoding)
3667 * @class MapboxGeocoder
@@ -75,6 +106,7 @@ function getFooterNode() {
75106 * @param {Boolean } [options.routing=false] Specify whether to request additional metadata about the recommended navigation destination corresponding to the feature or not. Only applicable for address features.
76107 * @param {String } [options.worldview="us"] Filter results to geographic features whose characteristics are defined differently by audiences belonging to various regional, cultural, or political groups.
77108 * @param {Boolean } [options.enableGeolocation=false] If `true` enable user geolocation feature.
109+ * @param {'v5'|'v6' } [options.version='v5'] If `v6` use v6 endpoint instead of v5. The default value is set to v5 API.
78110 * @param {('address'|'street'|'place'|'country') } [options.addressAccuracy="street"] The accuracy for the geolocation feature with which we define the address line to fill. The browser API returns the user's position with accuracy, and sometimes we can get the neighbor's address. To prevent receiving an incorrect address, you can reduce the accuracy of the definition.
79111 * @example
80112 * var geocoder = new MapboxGeocoder({ accessToken: mapboxgl.accessToken });
@@ -85,11 +117,15 @@ function getFooterNode() {
85117
86118function MapboxGeocoder ( options ) {
87119 this . _eventEmitter = new EventEmitter ( ) ;
88- this . options = extend ( { } , this . options , options ) ;
120+ this . options = extend ( { } , this . options , {
121+ getItemValue : options . version === 'v6' ? getItemValueV6 : getItemValue ,
122+ render : options . version === 'v6' ? renderV6 : render ,
123+ } , options ) ;
89124 this . inputString = '' ;
90125 this . fresh = true ;
91126 this . lastSelected = null ;
92127 this . geolocation = new Geolocation ( ) ;
128+ this . geocoderFactory = this . options . version === 'v6' ? mbxGeocoderV6 : mbxGeocoder ;
93129}
94130
95131MapboxGeocoder . prototype = {
@@ -110,13 +146,7 @@ MapboxGeocoder.prototype = {
110146 clearOnBlur : false ,
111147 enableGeolocation : false ,
112148 addressAccuracy : 'street' ,
113- getItemValue : function ( item ) {
114- return item . place_name
115- } ,
116- render : function ( item ) {
117- var placeName = item . place_name . split ( ',' ) ;
118- return '<div class="mapboxgl-ctrl-geocoder--suggestion"><div class="mapboxgl-ctrl-geocoder--suggestion-title">' + placeName [ 0 ] + '</div><div class="mapboxgl-ctrl-geocoder--suggestion-address">' + placeName . splice ( 1 , placeName . length ) . join ( ',' ) + '</div></div>' ;
119- }
149+ version : 'v5'
120150 } ,
121151
122152 /**
@@ -181,7 +211,7 @@ MapboxGeocoder.prototype = {
181211 this . setLanguage ( ) ;
182212
183213 if ( ! this . options . localGeocoderOnly ) {
184- this . geocoderService = mbxGeocoder (
214+ this . geocoderService = this . geocoderFactory (
185215 MapboxClient ( {
186216 accessToken : this . options . accessToken ,
187217 origin : this . options . origin
@@ -340,7 +370,13 @@ MapboxGeocoder.prototype = {
340370 this . _showClearButton ( ) ;
341371 this . fresh = false ;
342372
343- const config = {
373+ const config = this . options . version === 'v6' ? {
374+ longitude : geojson . geometry . coordinates [ 0 ] ,
375+ latitude : geojson . geometry . coordinates [ 1 ] ,
376+ limit : 1 ,
377+ language : this . options . language ,
378+ types : [ "address" ] ,
379+ } : {
344380 limit : 1 ,
345381 language : [ this . options . language ] ,
346382 query : geojson . geometry . coordinates ,
@@ -532,7 +568,16 @@ MapboxGeocoder.prototype = {
532568
533569 _fly : function ( selected ) {
534570 var flyOptions ;
535- if ( selected . properties && exceptions [ selected . properties . short_code ] ) {
571+ const bbox = this . options . version === 'v6' ? selected . properties . bbox : selected . bbox ;
572+
573+ let exceptionCode ;
574+ if ( this . options . version === 'v6' && selected . properties . feature_type === 'country' ) {
575+ exceptionCode = selected . properties . context . country . country_code . toLowerCase ( ) ;
576+ } else if ( this . options . version === 'v5' ) {
577+ exceptionCode = selected . properties && selected . properties . short_code ;
578+ }
579+
580+ if ( selected . properties && exceptions [ exceptionCode ] ) {
536581 // Certain geocoder search results return (and therefore zoom to fit)
537582 // an unexpectedly large bounding box: for example, both Russia and the
538583 // USA span both sides of -180/180, or France includes the island of
@@ -541,10 +586,9 @@ MapboxGeocoder.prototype = {
541586 // short-term solution; this may be amended as necessary.
542587 flyOptions = extend ( { } , this . options . flyTo ) ;
543588 if ( this . _map ) {
544- this . _map . fitBounds ( exceptions [ selected . properties . short_code ] . bbox , flyOptions ) ;
589+ this . _map . fitBounds ( exceptions [ exceptionCode ] . bbox , flyOptions ) ;
545590 }
546- } else if ( selected . bbox ) {
547- var bbox = selected . bbox ;
591+ } else if ( bbox ) {
548592 flyOptions = extend ( { } , this . options . flyTo ) ;
549593 if ( this . _map ) {
550594 this . _map . fitBounds ( [ [ bbox [ 0 ] , bbox [ 1 ] ] , [ bbox [ 2 ] , bbox [ 3 ] ] ] , flyOptions ) ;
@@ -581,32 +625,36 @@ MapboxGeocoder.prototype = {
581625
582626 _setupConfig : function ( requestType , search ) {
583627 // Possible config properties to pass to client
628+ const v5Keys = [
629+ 'fuzzyMatch' ,
630+ 'routing' ,
631+ 'reverseMode' ,
632+ ] ;
584633 const keys = [
585634 'bbox' ,
586635 'limit' ,
587636 'proximity' ,
588637 'countries' ,
589638 'types' ,
590639 'language' ,
591- 'reverseMode' ,
592640 'mode' ,
593641 'autocomplete' ,
594- 'fuzzyMatch' ,
595- 'routing' ,
596642 'worldview'
597643 ] ;
644+ const allKeys = [ ...( this . options . version === 'v6' ? [ ] : v5Keys ) , ...keys ] ;
645+ // countries, types, and language need to be passed in as arrays to client
646+ // https://github.com/mapbox/mapbox-sdk-js/blob/master/services/geocoding.js#L38-L47
647+ const arrayParameters = [ 'countries' , 'types' , ...( this . options . version === 'v6' ? [ ] : [ 'language' ] ) ] ;
598648 const spacesOrCommaRgx = / [ \s , ] + / ;
599649
600650 var self = this ;
601- var config = keys . reduce ( function ( config , key ) {
651+ var config = allKeys . reduce ( function ( config , key ) {
602652 // don't include undefined/null params, but allow boolean, among other, values
603653 if ( self . options [ key ] === undefined || self . options [ key ] === null ) {
604654 return config ;
605655 }
606656
607- // countries, types, and language need to be passed in as arrays to client
608- // https://github.com/mapbox/mapbox-sdk-js/blob/master/services/geocoding.js#L38-L47
609- [ 'countries' , 'types' , 'language' ] . indexOf ( key ) > - 1
657+ arrayParameters . indexOf ( key ) > - 1
610658 ? ( config [ key ] = self . options [ key ] . split ( spacesOrCommaRgx ) )
611659 : ( config [ key ] = self . options [ key ] ) ;
612660
@@ -626,24 +674,18 @@ MapboxGeocoder.prototype = {
626674
627675 switch ( requestType ) {
628676 case GEOCODE_REQUEST_TYPE . REVERSE : {
677+ // expected to be coordinates in the form `lat, lon`
629678 var coords = search . split ( spacesOrCommaRgx ) . map ( function ( c ) {
630679 return parseFloat ( c , 10 ) ;
631680 } )
632681 if ( ! self . options . flipCoordinates ) {
633682 coords . reverse ( ) ;
634683 }
635684
636- // client only accepts one type for reverseGeocode, so
637- // use first config type if one, if not default to poi
638- config . types ? [ config . types [ 0 ] ] : [ "poi" ] ;
639- config = extend ( config , { query : coords , limit : 1 } ) ;
640-
641- // Remove config options not supported by the reverseGeocoder
642- [ 'proximity' , 'autocomplete' , 'fuzzyMatch' , 'bbox' ] . forEach ( function ( key ) {
643- if ( key in config ) {
644- delete config [ key ]
645- }
646- } ) ;
685+ config = extend ( config ,
686+ this . options . version === 'v6' ? { longitude : coords [ 0 ] , latitude : coords [ 1 ] } : { query : coords } ,
687+ { limit : 1 }
688+ ) ;
647689 } break ;
648690 case GEOCODE_REQUEST_TYPE . FORWARD : {
649691 // Ensure that any reverse geocoding looking request is cleaned up
@@ -657,6 +699,23 @@ MapboxGeocoder.prototype = {
657699 } break ;
658700 }
659701
702+ if ( this . options . version === 'v6' && config . mode ) {
703+ config . permanent = config . mode === 'mapbox.places-permanent' ;
704+ delete config . mode ;
705+ }
706+
707+ // Remove config options not supported by the reverseGeocoder and v5 keys if v6 mode chosen
708+ const unsupportedKeys = [
709+ ...( requestType === GEOCODE_REQUEST_TYPE . REVERSE ? [ 'proximity' , 'autocomplete' , 'fuzzyMatch' , 'bbox' ] : [ ] ) ,
710+ ...( this . options . version === 'v6' ? v5Keys : [ ] )
711+ ] ;
712+
713+ unsupportedKeys . forEach ( function ( key ) {
714+ if ( key in config ) {
715+ delete config [ key ]
716+ }
717+ } ) ;
718+
660719 return config ;
661720 } ,
662721
@@ -840,7 +899,9 @@ MapboxGeocoder.prototype = {
840899 if ( ! results . features . length ) return ;
841900 var result = results . features [ 0 ] ;
842901 this . _typeahead . selected = result ;
843- this . _inputEl . value = result . place_name ;
902+ this . _inputEl . value = this . options . version === 'v6' ?
903+ ( result . properties . name + ( result . properties . place_formatted ? `, ${ result . properties . place_formatted } ` : "" ) ) :
904+ result . place_name ;
844905 this . _onChange ( ) ;
845906 } ,
846907
@@ -1177,7 +1238,7 @@ MapboxGeocoder.prototype = {
11771238 */
11781239 setOrigin : function ( origin ) {
11791240 this . options . origin = origin ;
1180- this . geocoderService = mbxGeocoder (
1241+ this . geocoderService = this . geocoderFactory (
11811242 MapboxClient ( {
11821243 accessToken : this . options . accessToken ,
11831244 origin : this . options . origin
@@ -1201,7 +1262,7 @@ MapboxGeocoder.prototype = {
12011262 */
12021263 setAccessToken : function ( accessToken ) {
12031264 this . options . accessToken = accessToken ;
1204- this . geocoderService = mbxGeocoder (
1265+ this . geocoderService = this . geocoderFactory (
12051266 MapboxClient ( {
12061267 accessToken : this . options . accessToken ,
12071268 origin : this . options . origin
0 commit comments