UNPKG

mobility-toolbox-js

Version:

Toolbox for JavaScript applications in the domains of mobility and logistics.

130 lines (129 loc) 5.25 kB
import { StopsAPI } from '../../api'; /** * A class representing a stop finder control to display on map. * This class only draw the html elements. * The geographic logic must be implemented by subclasses. * * @private */ class StopFinderControlCommon { /** * Constructor. * * @param {Object} options Options * @param {HTMLElement} options.element HTML element where to attach input and suggestions. * @param {string} options.apiKey Access key for [geOps services](https://developer.geops.io/). See StopsAPI. * @param {string} [options.url='https://api.geops.io/stops/v1/'] Stops service url. See StopsAPI. * @param {string} [options.placeholder='Search for a stop...'] Input field placeholder. * @param {StopsSearchParams} [options.apiParams={ limit: 20 }] Request parameters. See [Stops service documentation](https://developer.geops.io/apis/5dcbd702a256d90001cf1361/). */ constructor(options) { const { apiKey, apiParams, placeholder, url } = options || {}; this.apiParams = Object.assign({ limit: 20 }, (apiParams || {})); this.placeholder = placeholder || 'Search for a stop...'; const apiOptions = { apiKey }; if (url) { apiOptions.url = url; } this.api = new StopsAPI(apiOptions); this.abortController = new AbortController(); this.createElement(options); this.options = options; } /** * Clear the search field and close the control. */ clear() { if (!this.suggestionsElt || !this.inputElt || !this.clearElt) { return; } this.inputElt.value = ''; this.suggestionsElt.innerHTML = ''; this.clearElt.style.display = 'none'; } createElement({ element }) { // Create input element this.inputElt = document.createElement('input'); this.inputElt.type = 'text'; this.inputElt.placeholder = this.placeholder; this.inputElt.autocomplete = 'off'; this.inputElt.onkeyup = (evt) => { var _a; (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.abort(); this.abortController = new AbortController(); void this.search(evt.target.value, this.abortController); }; Object.assign(this.inputElt.style, { padding: '10px 30px 10px 10px', }); element.appendChild(this.inputElt); // Create suggestions list element this.suggestionsElt = document.createElement('div'); Object.assign(this.suggestionsElt.style, { backgroundColor: 'white', cursor: 'pointer', overflowY: 'auto', }); element.appendChild(this.suggestionsElt); this.clearElt = document.createElement('div'); Object.assign(this.clearElt.style, { cursor: 'pointer', display: 'none', fontSize: '200%', padding: '0 10px', position: 'absolute', right: '0', }); this.clearElt.innerHTML = '×'; this.clearElt.onclick = () => { return this.clear(); }; element.appendChild(this.clearElt); } render(featureCollection) { var _a; const suggestions = (_a = featureCollection === null || featureCollection === void 0 ? void 0 : featureCollection.features) !== null && _a !== void 0 ? _a : []; if (!this.suggestionsElt) { return; } this.suggestionsElt.style.display = suggestions.length ? 'block' : 'none'; this.suggestionsElt.innerHTML = ''; suggestions.forEach((suggestion) => { var _a, _b; const suggElt = document.createElement('div'); suggElt.innerHTML = ((_a = suggestion === null || suggestion === void 0 ? void 0 : suggestion.properties) === null || _a === void 0 ? void 0 : _a.name) || ''; suggElt.onclick = (evt) => { var _a, _b; (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.onSuggestionClick) === null || _b === void 0 ? void 0 : _b.call(_a, suggestion, evt); }; Object.assign(suggElt.style, { padding: '5px 12px', }); (_b = this.suggestionsElt) === null || _b === void 0 ? void 0 : _b.appendChild(suggElt); }); } /** * Launch a search. * * @param {String} q The query to search for. * @param {AbortController} abortController Abort controller used to cancel the request. * @return {Promise<Array<GeoJSONFeature>>} An array of GeoJSON features with coordinates in [EPSG:4326](http://epsg.io/4326). */ search(q, abortController) { if (q !== undefined || q !== null) { this.apiParams.q = q; } if (this.clearElt) { this.clearElt.style.display = 'block'; } return this.api .search(this.apiParams, abortController && { signal: abortController.signal }) .then((data) => { this.render(data); }) .catch(() => { this.render(); }); } } export default StopFinderControlCommon;