diff --git a/.gitignore b/.gitignore index ca4b008a..d7231eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ bundle.js demo-*/package-lock.json dist/ +docs/ node_modules/ diff --git a/README.md b/README.md index 4bad0847..ec2b232a 100755 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ The plugin supports many different data providers: - [HERE Geocoder API](https://developer.here.com/documentation/geocoder/topics/introduction.html) - [Neutrino API](https://www.neutrinoapi.com/api/geocode-address/) - [Plus codes](https://plus.codes/) (formerly OpenLocationCode) (requires [open-location-code](https://www.npmjs.com/package/open-location-code)) +- [ArcGIS](https://developers.arcgis.com/features/geocoding/) The plugin can easily be extended to support other providers. Current extensions: @@ -84,147 +85,4 @@ var geocoder = L.Control.geocoder({ This will add a polygon representing the result's boundingbox when a result is selected. # API - -## L.Control.Geocoder - -This is the geocoder control. It works like any other Leaflet control, and is added to the map. - -### Constructor - -This plugin supports the standard JavaScript constructor (to be invoked using `new`) as well as the [class factory methods](https://leafletjs.com/reference.html#class-class-factories) known from Leaflet: - -```js -new L.Control.Geocoder(options); -// or -L.Control.geocoder(options); -``` - -### Options - -| Option | Type | Default | Description | -| ------------------ | --------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------- | -| `collapsed` | Boolean | `true` | Collapse control unless hovered/clicked | -| `expand` | String | `"touch"` | How to expand a collapsed control: `touch` or `click` or `hover` | -| `position` | String | `"topright"` | Control [position](https://leafletjs.com/reference.html#control-positions) | -| `placeholder` | String | `"Search..."` | Placeholder text for text input | -| `errorMessage` | String | `"Nothing found."` | Message when no result found / geocoding error occurs | -| `iconLabel` | String | `"Initiate a new search"` | Accessibility label for the search icon used by screen readers | -| `geocoder` | IGeocoder | `new L.Control.Geocoder.Nominatim()` | Object to perform the actual geocoding queries | -| `showUniqueResult` | Boolean | `true` | Immediately show the unique result without prompting for alternatives | -| `showResultIcons` | Boolean | `false` | Show icons for geocoding results (if available); supported by Nominatim | -| `suggestMinLength` | Number | `3` | Minimum number characters before suggest functionality is used (if available from geocoder) | -| `suggestTimeout` | Number | `250` | Number of milliseconds after typing stopped before suggest functionality is used (if available from geocoder) | -| `query` | String | `""` | Initial query string for text input | -| `queryMinLength` | Number | `1` | Minimum number of characters in search text before performing a query | - -### Methods - -| Method | Returns | Description | -| --------------------------------------- | ------- | --------------------------------------- | -| `markGeocode( result)` | `this` | Marks a geocoding result on the map | -| `setQuery( query)` | `this` | Sets the query string on the text input | - -## L.Control.Geocoder.Nominatim - -Uses [Nominatim](https://wiki.openstreetmap.org/wiki/Nominatim) to respond to geocoding queries. This is the default -geocoding service used by the control, unless otherwise specified in the options. Implements `IGeocoder`. - -Unless using your own Nominatim installation, please refer to the [Nominatim usage policy](https://operations.osmfoundation.org/policies/nominatim/). - -### Constructor - -```js -new L.Control.Geocoder.Nominatim(options); -// or -L.Control.Geocoder.nominatim(options); -``` - -### Options - -| Option | Type | Default | Description | -| ---------------------- | -------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `serviceUrl` | String | `"https://nominatim.openstreetmap.org/"` | URL of the service | -| `geocodingQueryParams` | Object | `{}` | Additional URL parameters (strings) that will be added to geocoding requests; can be used to restrict results to a specific country for example, by providing the [`countrycodes`](https://wiki.openstreetmap.org/wiki/Nominatim#Parameters) parameter to Nominatim | -| `reverseQueryParams` | Object | `{}` | Additional URL parameters (strings) that will be added to reverse geocoding requests | -| `htmlTemplate` | function | special | A function that takes an GeocodingResult as argument and returns an HTML formatted string that represents the result. Default function breaks up address in parts from most to least specific, in attempt to increase readability compared to Nominatim's naming | - -## L.Control.Geocoder.Bing - -Uses [Bing Locations API](http://msdn.microsoft.com/en-us/library/ff701715.aspx) to respond to geocoding queries. Implements `IGeocoder`. - -Note that you need an API key to use this service. - -### Constructor - -```ts -new L.Control.Geocoder.Bing(options); -// or -L.Control.Geocoder.bing(options); -``` - -## L.Control.Geocoder.OpenCage - -Uses [OpenCage Data API](https://opencagedata.com/) to respond to geocoding queries. Implements `IGeocoder`. - -Note that you need an API key to use this service. - -### Constructor - -```ts -new L.Control.Geocoder.OpenCage(options); -// or -L.Control.Geocoder.opencage(options); -``` - -### Options - -| Option | Type | Default | Description | -| ---------------------- | ------ | ------------------------------------------------ | ------------------------------------------------------------------------------------ | -| `serviceUrl` | String | `"https://api.opencagedata.com/geocode/v1/json"` | URL of the service | -| `geocodingQueryParams` | Object | `{}` | Additional URL parameters (strings) that will be added to geocoding requests | -| `reverseQueryParams` | Object | `{}` | Additional URL parameters (strings) that will be added to reverse geocoding requests | - -## L.Control.Geocoder.LatLng - -Parses basic latitude/longitude strings such as `'50.06773 14.37742'`, `'N50.06773 W14.37742'`, `'S 50° 04.064 E 014° 22.645'`, or `'S 50° 4′ 03.828″, W 14° 22′ 38.712″'`. - -### Constructor - -```ts -new L.Control.Geocoder.LatLng(options); -// or -L.Control.Geocoder.latLng(options); -``` - -### Options - -| Option | Type | Default | Description | -| -------------- | --------- | ------- | --------------------------------------------------------- | -| `next` | IGeocoder | | The next geocoder to use for non-supported queries. | -| `sizeInMeters` | Number | 10000 | The size in meters used for passing to `LatLng.toBounds`. | - -## IGeocoder - -An interface implemented to respond to geocoding queries. - -### Methods - -| Method | Returns | Description | -| ----------------------------------------------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -| `geocode( query, callback, context)` | `GeocodingResult[]` | Performs a geocoding query and returns the results to the callback in the provided context | -| `suggest( query, callback, context)` | `GeocodingResult[]` | Performs a geocoding query suggestion (this happens while typing) and returns the results to the callback in the provided context | -| `reverse( location, scale, callback, context)` | `GeocodingResult[]` | Performs a reverse geocoding query and returns the results to the callback in the provided context | - -## GeocodingResult - -An object that represents a result from a geocoding query. - -### Properties - -| Property | Type | Description | -| -------- | -------------- | ---------------------------------------------------- | -| `name` | String | Name of found location | -| `bbox` | L.LatLngBounds | The bounds of the location | -| `center` | L.LatLng | The center coordinate of the location | -| `icon` | String | URL for icon representing result; optional | -| `html` | String | (optional) HTML formatted representation of the name | +→ docs/ diff --git a/package-lock.json b/package-lock.json index d52fb522..72243424 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1514,6 +1514,12 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -3114,6 +3120,26 @@ "map-cache": "^0.2.2" } }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + } + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3653,6 +3679,12 @@ } } }, + "highlight.js": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.4.0.tgz", + "integrity": "sha512-EfrUGcQ63oLJbj0J0RI9ebX6TAITbsDBLbsjr881L/X5fMO9+oadKzEF21C7R3ULKG6Gv3uoab2HiqVJa/4+oA==", + "dev": true + }, "hosted-git-info": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", @@ -5384,6 +5416,24 @@ } } }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -5534,6 +5584,12 @@ "signal-exit": "^3.0.0" } }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -5579,6 +5635,12 @@ "object-visit": "^1.0.0" } }, + "marked": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.5.tgz", + "integrity": "sha512-2AlqgYnVPOc9WDyWu7S5DJaEZsfk6dNh/neatQ3IHUW4QLutM/VPSH9lG7bif+XjFWc9K9XR3QvR+fXuECmfdA==", + "dev": true + }, "meow": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz", @@ -7885,6 +7947,45 @@ "is-typedarray": "^1.0.0" } }, + "typedoc": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.19.2.tgz", + "integrity": "sha512-oDEg1BLEzi1qvgdQXc658EYgJ5qJLVSeZ0hQ57Eq4JXy6Vj2VX4RVo18qYxRWz75ifAaYuYNBUCnbhjd37TfOg==", + "dev": true, + "requires": { + "fs-extra": "^9.0.1", + "handlebars": "^4.7.6", + "highlight.js": "^10.2.0", + "lodash": "^4.17.20", + "lunr": "^2.3.9", + "marked": "^1.1.1", + "minimatch": "^3.0.0", + "progress": "^2.0.3", + "semver": "^7.3.2", + "shelljs": "^0.8.4", + "typedoc-default-themes": "^0.11.4" + }, + "dependencies": { + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + } + } + }, + "typedoc-default-themes": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.11.4.tgz", + "integrity": "sha512-Y4Lf+qIb9NTydrexlazAM46SSLrmrQRqWiD52593g53SsmUFioAsMWt8m834J6qsp+7wHRjxCXSZeiiW5cMUdw==", + "dev": true + }, "typescript": { "version": "3.9.7", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", @@ -7910,6 +8011,12 @@ "set-value": "^2.0.1" } }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", diff --git a/package.json b/package.json index 7cdd74cc..645abbb7 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "build:demo-rollup": "cd demo-rollup && npm install && npm run build", "build:demo-webpack": "cd demo-rollup && npm install && npm run build", "changelog": "conventional-changelog --infile CHANGELOG.md --same-file --output-unreleased", + "doc": "typedoc --excludePrivate --stripInternal --moduleResolution node --out docs/ src/", "test": "jest", "lint": "eslint --ext .js,.ts ." }, @@ -74,6 +75,7 @@ "rollup-plugin-terser": "^5.3.0", "ts-jest": "^26.4.4", "tslib": "^1.11.1", + "typedoc": "^0.19.2", "typescript": "^3.8.3" }, "optionalDependencies": { diff --git a/src/control.ts b/src/control.ts index 3565f40d..ceb84814 100644 --- a/src/control.ts +++ b/src/control.ts @@ -3,27 +3,69 @@ import { Nominatim } from './geocoders/index'; import { IGeocoder, GeocodingResult } from './geocoders/api'; export interface GeocoderControlOptions extends L.ControlOptions { + /** + * Collapse control unless hovered/clicked + */ collapsed: boolean; - expand: string; + /** + * How to expand a collapsed control: `touch` or `click` or `hover` + */ + expand: 'touch' | 'click' | 'hover'; + /** + * Placeholder text for text input + */ placeholder: string; + /** + * Message when no result found / geocoding error occurs + */ errorMessage: string; + /** + * Accessibility label for the search icon used by screen readers + */ iconLabel: string; + /** + * Object to perform the actual geocoding queries + */ geocoder?: IGeocoder; + /** + * Immediately show the unique result without prompting for alternatives + */ showUniqueResult: boolean; + /** + * Show icons for geocoding results (if available); supported by Nominatim + */ showResultIcons: boolean; + /** + * Minimum number characters before suggest functionality is used (if available from geocoder) + */ suggestMinLength: number; + /** + * Number of milliseconds after typing stopped before suggest functionality is used (if available from geocoder) + */ suggestTimeout: number; + /** + * Initial query string for text input + */ query: string; + /** + * Minimum number of characters in search text before performing a query + */ queryMinLength: number; + /** + * Whether to mark a geocoding result on the map by default + */ defaultMarkGeocode: boolean; } +/** + * This is the geocoder control. It works like any other [Leaflet control](https://leafletjs.com/reference.html#control), and is added to the map. + */ export class GeocoderControl extends L.Control { options: GeocoderControlOptions = { showUniqueResult: true, showResultIcons: false, collapsed: true, - expand: 'touch', // options: touch, click, anythingelse + expand: 'touch', position: 'topright', placeholder: 'Search...', errorMessage: 'Nothing found.', @@ -49,6 +91,10 @@ export class GeocoderControl extends L.Control { private _selection: any; private _suggestTimeout: any; + /** + * Instantiates a geocoder control (to be invoked using `new`) + * @param options the options + */ constructor(options?: Partial) { super(options); L.Util.setOptions(this, options); @@ -57,16 +103,37 @@ export class GeocoderControl extends L.Control { } } + /** + * Adds a listener function to a particular event type of the object. + * @param type the event type + * @param fn the listener function + * @param context the this listener function context + * @see https://leafletjs.com/reference.html#evented-on + */ on(type: string, fn: L.LeafletEventHandlerFn, context?: any): this { L.Evented.prototype.on(type, fn, context); return this; } + /** + * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. + * @param type the event type + * @param fn the listener function + * @param context the this listener function context + * @see https://leafletjs.com/reference.html#evented-off + */ off(type: string, fn?: L.LeafletEventHandlerFn, context?: any): this { L.Evented.prototype.off(type, fn, context); return this; } + /** + * Fires an event of the specified type. You can optionally provide an data object. + * @param type the event type + * @param data the event data object + * @param propagate whether to propagate to event parents + * @see https://leafletjs.com/reference.html#evented-fire + */ fire(type: string, data?: any, propagate?: boolean): this { L.Evented.prototype.fire(type, data, propagate); return this; @@ -80,6 +147,11 @@ export class GeocoderControl extends L.Control { L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-throbber'); } + /** + * Returns the container DOM element for the control and add listeners on relevant map events. + * @param map the map instance + * @see https://leafletjs.com/reference.html#control-onadd + */ onAdd(map: L.Map) { const className = 'leaflet-control-geocoder'; const container = L.DomUtil.create('div', className + ' leaflet-bar') as HTMLDivElement; @@ -174,12 +246,16 @@ export class GeocoderControl extends L.Control { return container; } + /** + * Sets the query string on the text input + * @param string the query string + */ setQuery(string: string): this { this._input.value = string; return this; } - _geocodeResult(results: GeocodingResult[], suggest: boolean) { + private _geocodeResult(results: GeocodingResult[], suggest: boolean) { if (!suggest && this.options.showUniqueResult && results.length === 1) { this._geocodeResultSelected(results[0]); } else if (results.length > 0) { @@ -196,6 +272,10 @@ export class GeocoderControl extends L.Control { } } + /** + * Marks a geocoding result on the map + * @param result the geocoding result + */ markGeocode(result: GeocodingResult) { result = (result as any).geocode || result; @@ -213,7 +293,7 @@ export class GeocoderControl extends L.Control { return this; } - _geocode(suggest?: boolean) { + private _geocode(suggest?: boolean) { const value = this._input.value; if (!suggest && value.length < this.options.queryMinLength) { return; @@ -240,11 +320,11 @@ export class GeocoderControl extends L.Control { } } - _geocodeResultSelected(result: GeocodingResult) { + private _geocodeResultSelected(result: GeocodingResult) { this.fire('markgeocode', { geocode: result }); } - _toggle() { + private _toggle() { if (L.DomUtil.hasClass(this._container, 'leaflet-control-geocoder-expanded')) { this._collapse(); } else { @@ -252,13 +332,13 @@ export class GeocoderControl extends L.Control { } } - _expand() { + private _expand() { L.DomUtil.addClass(this._container, 'leaflet-control-geocoder-expanded'); this._input.select(); this.fire('expand'); } - _collapse() { + private _collapse() { L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-expanded'); L.DomUtil.addClass(this._alts, 'leaflet-control-geocoder-alternatives-minimized'); L.DomUtil.removeClass(this._errorElement, 'leaflet-control-geocoder-error'); @@ -268,7 +348,7 @@ export class GeocoderControl extends L.Control { this.fire('collapse'); } - _clearResults() { + private _clearResults() { L.DomUtil.addClass(this._alts, 'leaflet-control-geocoder-alternatives-minimized'); this._selection = null; L.DomUtil.removeClass(this._errorElement, 'leaflet-control-geocoder-error'); @@ -276,7 +356,7 @@ export class GeocoderControl extends L.Control { L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-options-error'); } - _createAlt(result: GeocodingResult, index: number) { + private _createAlt(result: GeocodingResult, index: number) { const li = L.DomUtil.create('li', ''), a = L.DomUtil.create('a', '', li), icon = @@ -322,7 +402,7 @@ export class GeocoderControl extends L.Control { return li; } - _keydown(e: KeyboardEvent) { + private _keydown(e: KeyboardEvent) { const select = (dir: number) => { if (this._selection) { L.DomUtil.removeClass(this._selection, 'leaflet-control-geocoder-selected'); @@ -371,7 +451,7 @@ export class GeocoderControl extends L.Control { L.DomEvent.preventDefault(e); } - _change() { + private _change() { const v = this._input.value; if (v !== this._lastGeocode) { clearTimeout(this._suggestTimeout); @@ -384,6 +464,10 @@ export class GeocoderControl extends L.Control { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link GeocoderControl} + * @param options the options + */ export function geocoder(options?: Partial) { return new GeocoderControl(options); } diff --git a/src/geocoders/api.ts b/src/geocoders/api.ts index 5413ea1e..c8220527 100644 --- a/src/geocoders/api.ts +++ b/src/geocoders/api.ts @@ -1,41 +1,110 @@ import * as L from 'leaflet'; +/** + * An object that represents a result from a geocoding query + */ export interface GeocodingResult { + /** + * Name of found location + */ name: string; + /** + * The bounds of the location + */ bbox: L.LatLngBounds; + /** + * The center coordinate of the location + */ center: L.LatLng; + /** + * URL for icon representing result; optional + */ icon?: string; + /** + * HTML formatted representation of the name + */ html?: string; + /** + * Additional properties returned by the geocoder + */ properties?: any; } +/** + * An object that represents a result from a reverse geocoding query + */ export interface ReverseGeocodingResult extends GeocodingResult { /** + * @see {@link bbox} * @deprecated */ bounds: L.LatLngBounds; } +/** + * A callback function used in {@link IGeocoder.geocode} and {@link IGeocoder.suggest} + */ export type GeocodingCallback = (result: GeocodingResult[]) => void; +/** + * A callback function used in {@link IGeocoder.reverse} + */ +export type ReverseGeocodingCallback = (result: ReverseGeocodingResult[]) => void; +/** + * An interface implemented to respond to geocoding queries + */ export interface IGeocoder { + /** + * Performs a geocoding query and returns the results to the callback in the provided context + * @param query the query + * @param cb the callback function + * @param context the `this` context in the callback + */ geocode(query: string, cb: GeocodingCallback, context?: any): void; + /** + * Performs a geocoding query suggestion (this happens while typing) and returns the results to the callback in the provided context + * @param query the query + * @param cb the callback function + * @param context the `this` context in the callback + */ suggest?(query: string, cb: GeocodingCallback, context?: any): void; + /** + * Performs a reverse geocoding query and returns the results to the callback in the provided context + * @param location the coordinate to reverse geocode + * @param scale the map scale possibly used for reverse geocoding + * @param cb the callback function + * @param context the `this` context in the callback + */ reverse?( location: L.LatLngLiteral, scale: number, - cb: (result: any) => void, + cb: ReverseGeocodingCallback, context?: any ): void; } export interface GeocoderOptions { + /** + * URL of the service + */ serviceUrl: string; + /** + * Additional URL parameters (strings) that will be added to geocoding requests + */ geocodingQueryParams?: Record; + /** + * Additional URL parameters (strings) that will be added to reverse geocoding requests + */ reverseQueryParams?: Record; + /** + * API key to use this service + */ apiKey?: string; } +/** + * @internal + */ export function geocodingParams( options: GeocoderOptions, params: Record @@ -43,6 +112,9 @@ export function geocodingParams( return L.Util.extend(params, options.geocodingQueryParams); } +/** + * @internal + */ export function reverseParams( options: GeocoderOptions, params: Record diff --git a/src/geocoders/arcgis.ts b/src/geocoders/arcgis.ts index ebee8b45..4472fa14 100644 --- a/src/geocoders/arcgis.ts +++ b/src/geocoders/arcgis.ts @@ -12,6 +12,9 @@ import { export interface ArcGisOptions extends GeocoderOptions {} +/** + * Implementation of the [ArcGIS geocoder](https://developers.arcgis.com/features/geocoding/) + */ export class ArcGis implements IGeocoder { options: ArcGisOptions = { serviceUrl: 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer', @@ -87,6 +90,10 @@ export class ArcGis implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link ArcGis} + * @param options the options + */ export function arcgis(options?: Partial) { return new ArcGis(options); } diff --git a/src/geocoders/bing.ts b/src/geocoders/bing.ts index dc981f61..2c8e5102 100644 --- a/src/geocoders/bing.ts +++ b/src/geocoders/bing.ts @@ -11,6 +11,9 @@ import { export interface BingOptions extends GeocoderOptions {} +/** + * Implementation of the [Bing Locations API](https://docs.microsoft.com/en-us/bingmaps/rest-services/locations/) + */ export class Bing implements IGeocoder { options: BingOptions = { serviceUrl: 'https://dev.virtualearth.net/REST/v1/Locations' @@ -79,6 +82,10 @@ export class Bing implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link Bing} + * @param options the options + */ export function bing(options?: Partial) { return new Bing(options); } diff --git a/src/geocoders/google.ts b/src/geocoders/google.ts index 13730a5e..4c516c6c 100644 --- a/src/geocoders/google.ts +++ b/src/geocoders/google.ts @@ -9,6 +9,9 @@ import { reverseParams } from './api'; +/** + * Implementation of the [Google Geocoding API](https://developers.google.com/maps/documentation/geocoding/) + */ export interface GoogleOptions extends GeocoderOptions {} export class Google implements IGeocoder { @@ -82,6 +85,10 @@ export class Google implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link Google} + * @param options the options + */ export function google(options?: Partial) { return new Google(options); } diff --git a/src/geocoders/here.ts b/src/geocoders/here.ts index 986ad448..c4a466d6 100755 --- a/src/geocoders/here.ts +++ b/src/geocoders/here.ts @@ -15,6 +15,9 @@ export interface HereOptions extends GeocoderOptions { reverseGeocodeProxRadius: null; } +/** + * Implementation of the [HERE Geocoder API](https://developer.here.com/documentation/geocoder/topics/introduction.html) + */ export class HERE implements IGeocoder { options: HereOptions = { serviceUrl: 'https://geocoder.api.here.com/6.2/', @@ -84,6 +87,10 @@ export class HERE implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link HERE} + * @param options the options + */ export function here(options?: Partial) { return new HERE(options); } diff --git a/src/geocoders/latlng.ts b/src/geocoders/latlng.ts index 8192b730..84f70436 100644 --- a/src/geocoders/latlng.ts +++ b/src/geocoders/latlng.ts @@ -3,12 +3,20 @@ import { IGeocoder, GeocodingCallback, GeocodingResult } from './api'; export interface LatLngOptions { /** - * The next geocoder to use + * The next geocoder to use for non-supported queries */ next?: IGeocoder; + /** + * The size in meters used for passing to `LatLng.toBounds` + */ sizeInMeters: number; } +/** + * Parses basic latitude/longitude strings such as `'50.06773 14.37742'`, `'N50.06773 W14.37742'`, `'S 50° 04.064 E 014° 22.645'`, or `'S 50° 4′ 03.828″, W 14° 22′ 38.712″'` + * @param query the latitude/longitude string to parse + * @returns the parsed latitude/longitude + */ export function parseLatLng(query: string): L.LatLng | undefined { let match; // regex from https://github.com/openstreetmap/openstreetmap-website/blob/master/app/controllers/geocoder_controller.rb @@ -75,6 +83,9 @@ export function parseLatLng(query: string): L.LatLng | undefined { } } +/** + * Parses basic latitude/longitude strings such as `'50.06773 14.37742'`, `'N50.06773 W14.37742'`, `'S 50° 04.064 E 014° 22.645'`, or `'S 50° 4′ 03.828″, W 14° 22′ 38.712″'` + */ export class LatLng implements IGeocoder { options: LatLngOptions = { next: undefined, @@ -102,6 +113,10 @@ export class LatLng implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link LatLng} + * @param options the options + */ export function latLng(options?: Partial) { return new LatLng(options); } diff --git a/src/geocoders/mapbox.ts b/src/geocoders/mapbox.ts index 64da06eb..f0205588 100644 --- a/src/geocoders/mapbox.ts +++ b/src/geocoders/mapbox.ts @@ -11,6 +11,9 @@ import { export interface MapboxOptions extends GeocoderOptions {} +/** + * Implementation of the [Mapbox Geocoding](https://www.mapbox.com/api-documentation/#geocoding) + */ export class Mapbox implements IGeocoder { options: MapboxOptions = { serviceUrl: 'https://api.mapbox.com/geocoding/v5/mapbox.places/' @@ -128,6 +131,10 @@ export class Mapbox implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link Mapbox} + * @param options the options + */ export function mapbox(options?: Partial) { return new Mapbox(options); } diff --git a/src/geocoders/mapquest.ts b/src/geocoders/mapquest.ts index f56aeb2e..3196e624 100644 --- a/src/geocoders/mapquest.ts +++ b/src/geocoders/mapquest.ts @@ -11,6 +11,9 @@ import { export interface MapQuestOptions extends GeocoderOptions {} +/** + * Implementation of the [MapQuest Geocoding API](http://developer.mapquest.com/web/products/dev-services/geocoding-ws) + */ export class MapQuest implements IGeocoder { options: MapQuestOptions = { serviceUrl: 'https://www.mapquestapi.com/geocoding/v1' @@ -90,6 +93,10 @@ export class MapQuest implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link MapQuest} + * @param options the options + */ export function mapQuest(options?: Partial) { return new MapQuest(options); } diff --git a/src/geocoders/neutrino.ts b/src/geocoders/neutrino.ts index 3ffcc6fe..96c617a5 100644 --- a/src/geocoders/neutrino.ts +++ b/src/geocoders/neutrino.ts @@ -13,6 +13,9 @@ export interface NeutrinoOptions extends GeocoderOptions { userId: string; } +/** + * Implementation of the [Neutrino API](https://www.neutrinoapi.com/api/geocode-address/) + */ export class Neutrino implements IGeocoder { options: NeutrinoOptions = { userId: undefined, @@ -82,6 +85,10 @@ export class Neutrino implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link Neutrino} + * @param options the options + */ export function neutrino(options?: Partial) { return new Neutrino(options); } diff --git a/src/geocoders/nominatim.ts b/src/geocoders/nominatim.ts index 6db0f9fc..9e60a8e9 100644 --- a/src/geocoders/nominatim.ts +++ b/src/geocoders/nominatim.ts @@ -45,9 +45,23 @@ export interface Address { } export interface NominatimOptions extends GeocoderOptions { + /** + * Additional URL parameters (strings) that will be added to geocoding requests; can be used to restrict results to a specific country for example, by providing the [`countrycodes`](https://wiki.openstreetmap.org/wiki/Nominatim#Parameters) parameter to Nominatim + */ + geocodingQueryParams?: Record; + /** + * A function that takes an GeocodingResult as argument and returns an HTML formatted string that represents the result. Default function breaks up address in parts from most to least specific, in attempt to increase readability compared to Nominatim's naming + */ htmlTemplate: (r: NominatimResult) => string; } +/** + * Implementation of the [Nominatim](https://wiki.openstreetmap.org/wiki/Nominatim) geocoder. + * + * This is the default geocoding service used by the control, unless otherwise specified in the options. + * + * Unless using your own Nominatim installation, please refer to the [Nominatim usage policy](https://operations.osmfoundation.org/policies/nominatim/). + */ export class Nominatim implements IGeocoder { options: NominatimOptions = { serviceUrl: 'https://nominatim.openstreetmap.org/', @@ -131,6 +145,10 @@ export class Nominatim implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link Nominatim} + * @param options the options + */ export function nominatim(options?: Partial) { return new Nominatim(options); } diff --git a/src/geocoders/open-location-code.ts b/src/geocoders/open-location-code.ts index 6fb0a382..c342f215 100644 --- a/src/geocoders/open-location-code.ts +++ b/src/geocoders/open-location-code.ts @@ -21,6 +21,9 @@ export interface CodeArea { codeLength: number; } +/** + * Implementation of the [Plus codes](https://plus.codes/) (formerly OpenLocationCode) (requires [open-location-code](https://www.npmjs.com/package/open-location-code)) + */ export class OpenLocationCode implements IGeocoder { options: OpenLocationCodeOptions; constructor(options?: Partial) { @@ -67,6 +70,10 @@ export class OpenLocationCode implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link OpenLocationCode} + * @param options the options + */ export function openLocationCode(options?: Partial) { return new OpenLocationCode(options); } diff --git a/src/geocoders/opencage.ts b/src/geocoders/opencage.ts index 28d25fa7..d46edc31 100644 --- a/src/geocoders/opencage.ts +++ b/src/geocoders/opencage.ts @@ -11,6 +11,9 @@ import { export interface OpenCageOptions extends GeocoderOptions {} +/** + * Implementation of the [OpenCage Data API](https://opencagedata.com/) + */ export class OpenCage implements IGeocoder { options: OpenCageOptions = { serviceUrl: 'https://api.opencagedata.com/geocode/v1/json' diff --git a/src/geocoders/pelias.ts b/src/geocoders/pelias.ts index 8a93d4e9..0a30b417 100644 --- a/src/geocoders/pelias.ts +++ b/src/geocoders/pelias.ts @@ -11,6 +11,9 @@ import { export interface PeliasOptions extends GeocoderOptions {} +/** + * Implementation of the [Pelias](https://pelias.io/), [geocode.earth](https://geocode.earth/) geocoder (formerly Mapzen Search) + */ export class Pelias implements IGeocoder { options: PeliasOptions = { serviceUrl: 'https://api.geocode.earth/v1' @@ -97,16 +100,32 @@ export class Pelias implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link Pelias} + * @param options the options + */ export function pelias(options?: Partial) { return new Pelias(options); } + export const GeocodeEarth = Pelias; export const geocodeEarth = pelias; -export const Mapzen = Pelias; // r.i.p. +/** + * r.i.p. + * @deprecated + */ +export const Mapzen = Pelias; +/** + * r.i.p. + * @deprecated + */ export const mapzen = pelias; -export class Openrouteservice extends Mapzen { +/** + * Implementation of the [Openrouteservice](https://openrouteservice.org/dev/#/api-docs/geocode) geocoder + */ +export class Openrouteservice extends Pelias { constructor(options?: Partial) { super( L.Util.extend( @@ -118,6 +137,11 @@ export class Openrouteservice extends Mapzen { ); } } + +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link Openrouteservice} + * @param options the options + */ export function openrouteservice(options?: Partial) { return new Openrouteservice(options); } diff --git a/src/geocoders/photon.ts b/src/geocoders/photon.ts index a2cb6ea0..0dd03772 100644 --- a/src/geocoders/photon.ts +++ b/src/geocoders/photon.ts @@ -15,6 +15,9 @@ export interface PhotonOptions extends GeocoderOptions { htmlTemplate?: (r: any) => string; } +/** + * Implementation of the [Photon](http://photon.komoot.de/) geocoder + */ export class Photon implements IGeocoder { options: PhotonOptions = { serviceUrl: 'https://photon.komoot.io/api/', @@ -94,6 +97,10 @@ export class Photon implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link Photon} + * @param options the options + */ export function photon(options?: Partial) { return new Photon(options); } diff --git a/src/geocoders/what3words.ts b/src/geocoders/what3words.ts index fa8d7701..6f71a185 100644 --- a/src/geocoders/what3words.ts +++ b/src/geocoders/what3words.ts @@ -11,6 +11,9 @@ import { export interface What3WordsOptions extends GeocoderOptions {} +/** + * Implementation of the What3Words service + */ export class What3Words implements IGeocoder { options: What3WordsOptions = { serviceUrl: 'https://api.what3words.com/v2/' @@ -78,6 +81,10 @@ export class What3Words implements IGeocoder { } } +/** + * [Class factory method](https://leafletjs.com/reference.html#class-class-factories) for {@link What3Words} + * @param options the options + */ export function what3words(options: Partial) { return new What3Words(options); } diff --git a/src/util.ts b/src/util.ts index 7e360841..022d7880 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,10 +1,22 @@ import * as L from 'leaflet'; +/** + * @internal + */ let lastCallbackId = 0; // Adapted from handlebars.js // https://github.com/wycats/handlebars.js/ +/** + * @internal + */ const badChars = /[&<>"'`]/g; +/** + * @internal + */ const possible = /[&<>"'`]/; +/** + * @internal + */ const escape: Record = { '&': '&', '<': '<', @@ -14,10 +26,16 @@ const escape: Record = { '`': '`' }; +/** + * @internal + */ function escapeChar(chr: string) { return escape[chr]; } +/** + * @internal + */ export function htmlEscape(string?: string): string { if (string == null) { return ''; @@ -36,6 +54,9 @@ export function htmlEscape(string?: string): string { return string.replace(badChars, escapeChar); } +/** + * @internal + */ export function jsonp( url: string, params: Record, @@ -53,6 +74,9 @@ export function jsonp( document.getElementsByTagName('head')[0].appendChild(script); } +/** + * @internal + */ export function getJSON( url: string, params: Record, @@ -85,6 +109,9 @@ export function getJSON( xmlHttp.send(null); } +/** + * @internal + */ export function template(str: string, data: Record): string { return str.replace(/\{ *([\w_]+) *\}/g, (str, key) => { let value = data[key]; @@ -97,6 +124,9 @@ export function template(str: string, data: Record): string { }); } +/** + * @internal + */ export function getParamString( obj: Record, existingUrl?: string,