From dcae136678170f72f793790a8b2c35abf0deedb7 Mon Sep 17 00:00:00 2001 From: john gravois Date: Thu, 14 Jun 2018 07:38:12 -0700 Subject: [PATCH] build 2.2.12 --- dist/esri-leaflet-geocoder-debug.js | 1218 +++++++++++++++++++++++++++ dist/esri-leaflet-geocoder.css | 1 + dist/esri-leaflet-geocoder.js | 4 + dist/img/loading.gif | Bin 0 -> 1276 bytes dist/img/loading@2x.gif | Bin 0 -> 3973 bytes dist/img/search-disabled.png | Bin 0 -> 386 bytes dist/img/search.png | Bin 0 -> 425 bytes dist/img/search@2x-disabled.png | Bin 0 -> 386 bytes dist/img/search@2x.png | Bin 0 -> 772 bytes 9 files changed, 1223 insertions(+) create mode 100644 dist/esri-leaflet-geocoder-debug.js create mode 100644 dist/esri-leaflet-geocoder.css create mode 100644 dist/esri-leaflet-geocoder.js create mode 100644 dist/img/loading.gif create mode 100644 dist/img/loading@2x.gif create mode 100644 dist/img/search-disabled.png create mode 100644 dist/img/search.png create mode 100644 dist/img/search@2x-disabled.png create mode 100644 dist/img/search@2x.png diff --git a/dist/esri-leaflet-geocoder-debug.js b/dist/esri-leaflet-geocoder-debug.js new file mode 100644 index 0000000..b51393b --- /dev/null +++ b/dist/esri-leaflet-geocoder-debug.js @@ -0,0 +1,1218 @@ +/* esri-leaflet-geocoder - v2.2.12 - Thu Jun 14 2018 07:37:43 GMT-0700 (PDT) + * Copyright (c) 2018 Environmental Systems Research Institute, Inc. + * Apache-2.0 */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('leaflet'), require('esri-leaflet')) : + typeof define === 'function' && define.amd ? define(['exports', 'leaflet', 'esri-leaflet'], factory) : + (factory((global.L = global.L || {}, global.L.esri = global.L.esri || {}, global.L.esri.Geocoding = {}),global.L,global.L.esri)); +}(this, (function (exports,leaflet,esriLeaflet) { 'use strict'; + +var version = "2.2.12"; + +var Geocode$$1 = esriLeaflet.Task.extend({ + path: 'findAddressCandidates', + + params: { + outSr: 4326, + forStorage: false, + outFields: '*', + maxLocations: 20 + }, + + setters: { + 'address': 'address', + 'neighborhood': 'neighborhood', + 'city': 'city', + 'subregion': 'subregion', + 'region': 'region', + 'postal': 'postal', + 'country': 'country', + 'text': 'singleLine', + 'category': 'category', + 'token': 'token', + 'key': 'magicKey', + 'fields': 'outFields', + 'forStorage': 'forStorage', + 'maxLocations': 'maxLocations' + }, + + initialize: function (options) { + options = options || {}; + options.url = options.url || WorldGeocodingServiceUrl; + esriLeaflet.Task.prototype.initialize.call(this, options); + }, + + within: function (bounds) { + bounds = leaflet.latLngBounds(bounds); + this.params.searchExtent = esriLeaflet.Util.boundsToExtent(bounds); + return this; + }, + + nearby: function (coords, radius) { + var centroid = leaflet.latLng(coords); + this.params.location = centroid.lng + ',' + centroid.lat; + this.params.distance = Math.min(Math.max(radius, 2000), 50000); + return this; + }, + + run: function (callback, context) { + if (this.options.customParam) { + this.params[this.options.customParam] = this.params.singleLine; + delete this.params.singleLine; + } + + return this.request(function (error, response) { + var processor = this._processGeocoderResponse; + var results = (!error) ? processor(response) : undefined; + callback.call(context, error, { results: results }, response); + }, this); + }, + + _processGeocoderResponse: function (response) { + var results = []; + + for (var i = 0; i < response.candidates.length; i++) { + var candidate = response.candidates[i]; + if (candidate.extent) { + var bounds = esriLeaflet.Util.extentToBounds(candidate.extent); + } + + results.push({ + text: candidate.address, + bounds: bounds, + score: candidate.score, + latlng: leaflet.latLng(candidate.location.y, candidate.location.x), + properties: candidate.attributes + }); + } + return results; + } +}); + +function geocode$$1 (options) { + return new Geocode$$1(options); +} + +var ReverseGeocode$$1 = esriLeaflet.Task.extend({ + path: 'reverseGeocode', + + params: { + outSR: 4326, + returnIntersection: false + }, + + setters: { + 'distance': 'distance', + 'language': 'langCode', + 'intersection': 'returnIntersection' + }, + + initialize: function (options) { + options = options || {}; + options.url = options.url || WorldGeocodingServiceUrl; + esriLeaflet.Task.prototype.initialize.call(this, options); + }, + + latlng: function (coords) { + var centroid = leaflet.latLng(coords); + this.params.location = centroid.lng + ',' + centroid.lat; + return this; + }, + + run: function (callback, context) { + return this.request(function (error, response) { + var result; + + if (!error) { + result = { + latlng: leaflet.latLng(response.location.y, response.location.x), + address: response.address + }; + } else { + result = undefined; + } + + callback.call(context, error, result, response); + }, this); + } +}); + +function reverseGeocode$$1 (options) { + return new ReverseGeocode$$1(options); +} + +var Suggest$$1 = esriLeaflet.Task.extend({ + path: 'suggest', + + params: {}, + + setters: { + text: 'text', + category: 'category', + countries: 'countryCode', + maxSuggestions: 'maxSuggestions' + }, + + initialize: function (options) { + options = options || {}; + if (!options.url) { + options.url = WorldGeocodingServiceUrl; + options.supportsSuggest = true; + } + esriLeaflet.Task.prototype.initialize.call(this, options); + }, + + within: function (bounds) { + bounds = leaflet.latLngBounds(bounds); + bounds = bounds.pad(0.5); + var center = bounds.getCenter(); + var ne = bounds.getNorthWest(); + this.params.location = center.lng + ',' + center.lat; + this.params.distance = Math.min(Math.max(center.distanceTo(ne), 2000), 50000); + this.params.searchExtent = esriLeaflet.Util.boundsToExtent(bounds); + return this; + }, + + nearby: function (coords, radius) { + var centroid = leaflet.latLng(coords); + this.params.location = centroid.lng + ',' + centroid.lat; + this.params.distance = Math.min(Math.max(radius, 2000), 50000); + return this; + }, + + run: function (callback, context) { + if (this.options.supportsSuggest) { + return this.request(function (error, response) { + callback.call(context, error, response, response); + }, this); + } else { + console.warn('this geocoding service does not support asking for suggestions'); + } + } + +}); + +function suggest$$1 (options) { + return new Suggest$$1(options); +} + +var GeocodeService$$1 = esriLeaflet.Service.extend({ + initialize: function (options) { + options = options || {}; + if (options.url) { + esriLeaflet.Service.prototype.initialize.call(this, options); + this._confirmSuggestSupport(); + } else { + options.url = WorldGeocodingServiceUrl; + options.supportsSuggest = true; + esriLeaflet.Service.prototype.initialize.call(this, options); + } + }, + + geocode: function () { + return geocode$$1(this); + }, + + reverse: function () { + return reverseGeocode$$1(this); + }, + + suggest: function () { + // requires either the Esri World Geocoding Service or a <10.3 ArcGIS Server Geocoding Service that supports suggest. + return suggest$$1(this); + }, + + _confirmSuggestSupport: function () { + this.metadata(function (error, response) { + if (error) { return; } + // pre 10.3 geocoding services dont list capabilities (and dont support maxLocations) + // only SOME individual services have been configured to support asking for suggestions + if (!response.capabilities) { + this.options.supportsSuggest = false; + } else if (response.capabilities.indexOf('Suggest') > -1) { + this.options.supportsSuggest = true; + } else { + this.options.supportsSuggest = false; + } + // whether the service supports suggest or not, utilize the metadata response to determine the appropriate parameter name for single line geocoding requests + this.options.customParam = response.singleLineAddressField.name; + }, this); + } +}); + +function geocodeService$$1 (options) { + return new GeocodeService$$1(options); +} + +var GeosearchCore = leaflet.Evented.extend({ + + options: { + zoomToResult: true, + useMapBounds: 12, + searchBounds: null + }, + + initialize: function (control, options) { + leaflet.Util.setOptions(this, options); + this._control = control; + + if (!options || !options.providers || !options.providers.length) { + throw new Error('You must specify at least one provider'); + } + + this._providers = options.providers; + }, + + _geocode: function (text, key, provider) { + var activeRequests = 0; + var allResults = []; + var bounds; + + var callback = leaflet.Util.bind(function (error, results) { + activeRequests--; + if (error) { + return; + } + + if (results) { + allResults = allResults.concat(results); + } + + if (activeRequests <= 0) { + bounds = this._boundsFromResults(allResults); + + this.fire('results', { + results: allResults, + bounds: bounds, + latlng: (bounds) ? bounds.getCenter() : undefined, + text: text + }, true); + + if (this.options.zoomToResult && bounds) { + this._control._map.fitBounds(bounds); + } + + this.fire('load'); + } + }, this); + + if (key) { + activeRequests++; + provider.results(text, key, this._searchBounds(), callback); + } else { + for (var i = 0; i < this._providers.length; i++) { + activeRequests++; + this._providers[i].results(text, key, this._searchBounds(), callback); + } + } + }, + + _suggest: function (text) { + var activeRequests = this._providers.length; + + var createCallback = leaflet.Util.bind(function (text, provider) { + return leaflet.Util.bind(function (error, suggestions) { + if (error) { return; } + + var i; + + activeRequests = activeRequests - 1; + + if (text.length < 2) { + this._suggestions.innerHTML = ''; + this._suggestions.style.display = 'none'; + return; + } + + if (suggestions.length) { + for (i = 0; i < suggestions.length; i++) { + suggestions[i].provider = provider; + } + } else { + // we still need to update the UI + this._control._renderSuggestions(suggestions); + } + + if (provider._lastRender !== text && provider.nodes) { + for (i = 0; i < provider.nodes.length; i++) { + if (provider.nodes[i].parentElement) { + this._control._suggestions.removeChild(provider.nodes[i]); + } + } + + provider.nodes = []; + } + + if (suggestions.length && this._control._input.value === text) { + this._control.clearSuggestions(provider.nodes); + + provider._lastRender = text; + provider.nodes = this._control._renderSuggestions(suggestions); + this._control._nodes = []; + } + }, this); + }, this); + + this._pendingSuggestions = []; + + for (var i = 0; i < this._providers.length; i++) { + var provider = this._providers[i]; + var request = provider.suggestions(text, this._searchBounds(), createCallback(text, provider)); + this._pendingSuggestions.push(request); + } + }, + + _searchBounds: function () { + if (this.options.searchBounds !== null) { + return this.options.searchBounds; + } + + if (this.options.useMapBounds === false) { + return null; + } + + if (this.options.useMapBounds === true) { + return this._control._map.getBounds(); + } + + if (this.options.useMapBounds <= this._control._map.getZoom()) { + return this._control._map.getBounds(); + } + + return null; + }, + + _boundsFromResults: function (results) { + if (!results.length) { + return; + } + + var nullIsland = leaflet.latLngBounds([0, 0], [0, 0]); + var resultBounds = []; + var resultLatlngs = []; + + // collect the bounds and center of each result + for (var i = results.length - 1; i >= 0; i--) { + var result = results[i]; + + resultLatlngs.push(result.latlng); + + // make sure bounds are valid and not 0,0. sometimes bounds are incorrect or not present + if (result.bounds && result.bounds.isValid() && !result.bounds.equals(nullIsland)) { + resultBounds.push(result.bounds); + } + } + + // form a bounds object containing all center points + var bounds = leaflet.latLngBounds(resultLatlngs); + + // and extend it to contain all bounds objects + for (var j = 0; j < resultBounds.length; j++) { + bounds.extend(resultBounds[j]); + } + + return bounds; + }, + + _getAttribution: function () { + var attribs = []; + var providers = this._providers; + + for (var i = 0; i < providers.length; i++) { + if (providers[i].options.attribution) { + attribs.push(providers[i].options.attribution); + } + } + + return attribs.join(', '); + } + +}); + +function geosearchCore (control, options) { + return new GeosearchCore(control, options); +} + +var ArcgisOnlineProvider = GeocodeService$$1.extend({ + options: { + label: 'Places and Addresses', + maxResults: 5 + }, + + suggestions: function (text, bounds, callback) { + var request = this.suggest().text(text); + + if (bounds) { + request.within(bounds); + } + + if (this.options.countries) { + request.countries(this.options.countries); + } + + if (this.options.categories) { + request.category(this.options.categories); + } + + // 15 is the maximum number of suggestions that can be returned + request.maxSuggestions(this.options.maxResults); + + return request.run(function (error, results, response) { + var suggestions = []; + if (!error) { + while (response.suggestions.length && suggestions.length <= (this.options.maxResults - 1)) { + var suggestion = response.suggestions.shift(); + if (!suggestion.isCollection) { + suggestions.push({ + text: suggestion.text, + unformattedText: suggestion.text, + magicKey: suggestion.magicKey + }); + } + } + } + callback(error, suggestions); + }, this); + }, + + results: function (text, key, bounds, callback) { + var request = this.geocode().text(text); + + if (key) { + request.key(key); + } + // in the future Address/StreetName geocoding requests that include a magicKey will always only return one match + request.maxLocations(this.options.maxResults); + + if (bounds) { + request.within(bounds); + } + + if (this.options.forStorage) { + request.forStorage(true); + } + + return request.run(function (error, response) { + callback(error, response.results); + }, this); + } +}); + +function arcgisOnlineProvider (options) { + return new ArcgisOnlineProvider(options); +} + +var Geosearch = leaflet.Control.extend({ + includes: leaflet.Evented.prototype, + + options: { + position: 'topleft', + collapseAfterResult: true, + expanded: false, + allowMultipleResults: true, + placeholder: 'Search for places or addresses', + title: 'Location Search' + }, + + initialize: function (options) { + leaflet.Util.setOptions(this, options); + + if (!options || !options.providers || !options.providers.length) { + if (!options) { + options = {}; + } + options.providers = [ arcgisOnlineProvider() ]; + } + + // instantiate the underlying class and pass along options + this._geosearchCore = geosearchCore(this, options); + this._geosearchCore._providers = options.providers; + + // bubble each providers events to the control + this._geosearchCore.addEventParent(this); + for (var i = 0; i < this._geosearchCore._providers.length; i++) { + this._geosearchCore._providers[i].addEventParent(this); + } + + this._geosearchCore._pendingSuggestions = []; + + leaflet.Control.prototype.initialize.call(options); + }, + + _renderSuggestions: function (suggestions) { + var currentGroup; + + if (suggestions.length > 0) { + this._suggestions.style.display = 'block'; + } + // set the maxHeight of the suggestions box to + // map height + // - suggestions offset (distance from top of suggestions to top of control) + // - control offset (distance from top of control to top of map) + // - 10 (extra padding) + this._suggestions.style.maxHeight = (this._map.getSize().y - this._suggestions.offsetTop - this._wrapper.offsetTop - 10) + 'px'; + + var nodes = []; + var list; + var header; + var suggestionTextArray = []; + + for (var i = 0; i < suggestions.length; i++) { + var suggestion = suggestions[i]; + if (!header && this._geosearchCore._providers.length > 1 && currentGroup !== suggestion.provider.options.label) { + header = leaflet.DomUtil.create('span', 'geocoder-control-header', this._suggestions); + header.textContent = suggestion.provider.options.label; + header.innerText = suggestion.provider.options.label; + currentGroup = suggestion.provider.options.label; + nodes.push(header); + } + + if (!list) { + list = leaflet.DomUtil.create('ul', 'geocoder-control-list', this._suggestions); + } + + if (suggestionTextArray.indexOf(suggestion.text) === -1) { + var suggestionItem = leaflet.DomUtil.create('li', 'geocoder-control-suggestion', list); + + suggestionItem.innerHTML = suggestion.text; + suggestionItem.provider = suggestion.provider; + suggestionItem['data-magic-key'] = suggestion.magicKey; + suggestionItem.unformattedText = suggestion.unformattedText; + } else { + for (var j = 0; j < list.childNodes.length; j++) { + // if the same text already appears in the list of suggestions, append an additional ObjectID to its magicKey instead + if (list.childNodes[j].innerHTML === suggestion.text) { + list.childNodes[j]['data-magic-key'] += ',' + suggestion.magicKey; + } + } + } + suggestionTextArray.push(suggestion.text); + } + + leaflet.DomUtil.removeClass(this._input, 'geocoder-control-loading'); + + nodes.push(list); + + return nodes; + }, + + _boundsFromResults: function (results) { + if (!results.length) { + return; + } + + var nullIsland = leaflet.latLngBounds([0, 0], [0, 0]); + var resultBounds = []; + var resultLatlngs = []; + + // collect the bounds and center of each result + for (var i = results.length - 1; i >= 0; i--) { + var result = results[i]; + + resultLatlngs.push(result.latlng); + + // make sure bounds are valid and not 0,0. sometimes bounds are incorrect or not present + if (result.bounds && result.bounds.isValid() && !result.bounds.equals(nullIsland)) { + resultBounds.push(result.bounds); + } + } + + // form a bounds object containing all center points + var bounds = leaflet.latLngBounds(resultLatlngs); + + // and extend it to contain all bounds objects + for (var j = 0; j < resultBounds.length; j++) { + bounds.extend(resultBounds[j]); + } + + return bounds; + }, + + clear: function () { + this._suggestions.innerHTML = ''; + this._suggestions.style.display = 'none'; + this._input.value = ''; + + if (this.options.collapseAfterResult) { + this._input.placeholder = ''; + leaflet.DomUtil.removeClass(this._wrapper, 'geocoder-control-expanded'); + } + + if (!this._map.scrollWheelZoom.enabled() && this._map.options.scrollWheelZoom) { + this._map.scrollWheelZoom.enable(); + } + }, + + clearSuggestions: function () { + if (this._nodes) { + for (var k = 0; k < this._nodes.length; k++) { + if (this._nodes[k].parentElement) { + this._suggestions.removeChild(this._nodes[k]); + } + } + } + }, + + _setupClick: function () { + leaflet.DomUtil.addClass(this._wrapper, 'geocoder-control-expanded'); + this._input.focus(); + }, + + disable: function () { + this._input.disabled = true; + leaflet.DomUtil.addClass(this._input, 'geocoder-control-input-disabled'); + leaflet.DomEvent.removeListener(this._wrapper, 'click', this._setupClick, this); + }, + + enable: function () { + this._input.disabled = false; + leaflet.DomUtil.removeClass(this._input, 'geocoder-control-input-disabled'); + leaflet.DomEvent.addListener(this._wrapper, 'click', this._setupClick, this); + }, + + getAttribution: function () { + var attribs = []; + + for (var i = 0; i < this._providers.length; i++) { + if (this._providers[i].options.attribution) { + attribs.push(this._providers[i].options.attribution); + } + } + + return attribs.join(', '); + }, + + geocodeSuggestion: function (e) { + var suggestionItem = e.target || e.srcElement; + + // make sure and point at the actual 'geocoder-control-suggestion' + if (suggestionItem.classList.length < 1) { + suggestionItem = suggestionItem.parentNode; + } + + this._geosearchCore._geocode(suggestionItem.unformattedText, suggestionItem['data-magic-key'], suggestionItem.provider); + this.clear(); + }, + + onAdd: function (map) { + // include 'Powered by Esri' in map attribution + esriLeaflet.Util.setEsriAttribution(map); + + this._map = map; + this._wrapper = leaflet.DomUtil.create('div', 'geocoder-control'); + this._input = leaflet.DomUtil.create('input', 'geocoder-control-input leaflet-bar', this._wrapper); + this._input.title = this.options.title; + + if (this.options.expanded) { + leaflet.DomUtil.addClass(this._wrapper, 'geocoder-control-expanded'); + this._input.placeholder = this.options.placeholder; + } + + this._suggestions = leaflet.DomUtil.create('div', 'geocoder-control-suggestions leaflet-bar', this._wrapper); + + var credits = this._geosearchCore._getAttribution(); + + if (map.attributionControl) { + map.attributionControl.addAttribution(credits); + } + + leaflet.DomEvent.addListener(this._input, 'focus', function (e) { + this._input.placeholder = this.options.placeholder; + leaflet.DomUtil.addClass(this._wrapper, 'geocoder-control-expanded'); + }, this); + + leaflet.DomEvent.addListener(this._wrapper, 'click', this._setupClick, this); + + // make sure both click and touch spawn an address/poi search + leaflet.DomEvent.addListener(this._suggestions, 'mousedown', this.geocodeSuggestion, this); + + // for some reason DomEvent.addListener is triggered too early in Chrome. + this._suggestions.addEventListener('touchend', leaflet.Util.bind(this.geocodeSuggestion, this)); + + leaflet.DomEvent.addListener(this._input, 'blur', function (e) { + this.clear(); + }, this); + + leaflet.DomEvent.addListener(this._input, 'keydown', function (e) { + var text = (e.target || e.srcElement).value; + + leaflet.DomUtil.addClass(this._wrapper, 'geocoder-control-expanded'); + + var list = this._suggestions.querySelectorAll('.' + 'geocoder-control-suggestion'); + var selected = this._suggestions.querySelectorAll('.' + 'geocoder-control-selected')[0]; + var selectedPosition; + + for (var i = 0; i < list.length; i++) { + if (list[i] === selected) { + selectedPosition = i; + break; + } + } + + switch (e.keyCode) { + case 13: + /* + if an item has been selected, geocode it + if focus is on the input textbox, geocode only if multiple results are allowed and more than two characters are present, or if a single suggestion is displayed. + if less than two characters have been typed, abort the geocode + */ + if (selected) { + this._geosearchCore._geocode(selected.unformattedText, selected['data-magic-key'], selected.provider); + this.clear(); + } else if (this.options.allowMultipleResults && text.length >= 2) { + this._geosearchCore._geocode(this._input.value, undefined); + this.clear(); + } else { + if (list.length === 1) { + leaflet.DomUtil.addClass(list[0], 'geocoder-control-selected'); + this._geosearchCore._geocode(list[0].innerHTML, list[0]['data-magic-key'], list[0].provider); + } else { + this.clear(); + this._input.blur(); + } + } + leaflet.DomEvent.preventDefault(e); + break; + case 38: + if (selected) { + leaflet.DomUtil.removeClass(selected, 'geocoder-control-selected'); + } + + var previousItem = list[selectedPosition - 1]; + + if (selected && previousItem) { + leaflet.DomUtil.addClass(previousItem, 'geocoder-control-selected'); + } else { + leaflet.DomUtil.addClass(list[list.length - 1], 'geocoder-control-selected'); + } + leaflet.DomEvent.preventDefault(e); + break; + case 40: + if (selected) { + leaflet.DomUtil.removeClass(selected, 'geocoder-control-selected'); + } + + var nextItem = list[selectedPosition + 1]; + + if (selected && nextItem) { + leaflet.DomUtil.addClass(nextItem, 'geocoder-control-selected'); + } else { + leaflet.DomUtil.addClass(list[0], 'geocoder-control-selected'); + } + leaflet.DomEvent.preventDefault(e); + break; + default: + // when the input changes we should cancel all pending suggestion requests if possible to avoid result collisions + for (var x = 0; x < this._geosearchCore._pendingSuggestions.length; x++) { + var request = this._geosearchCore._pendingSuggestions[x]; + if (request && request.abort && !request.id) { + request.abort(); + } + } + break; + } + }, this); + + leaflet.DomEvent.addListener(this._input, 'keyup', leaflet.Util.throttle(function (e) { + var key = e.which || e.keyCode; + var text = (e.target || e.srcElement).value; + + // require at least 2 characters for suggestions + if (text.length < 2) { + this._suggestions.innerHTML = ''; + this._suggestions.style.display = 'none'; + leaflet.DomUtil.removeClass(this._input, 'geocoder-control-loading'); + return; + } + + // if this is the escape key it will clear the input so clear suggestions + if (key === 27) { + this._suggestions.innerHTML = ''; + this._suggestions.style.display = 'none'; + return; + } + + // if this is NOT the up/down arrows or enter make a suggestion + if (key !== 13 && key !== 38 && key !== 40) { + if (this._input.value !== this._lastValue) { + this._lastValue = this._input.value; + leaflet.DomUtil.addClass(this._input, 'geocoder-control-loading'); + this._geosearchCore._suggest(text); + } + } + }, 50, this), this); + + leaflet.DomEvent.disableClickPropagation(this._wrapper); + + // when mouse moves over suggestions disable scroll wheel zoom if its enabled + leaflet.DomEvent.addListener(this._suggestions, 'mouseover', function (e) { + if (map.scrollWheelZoom.enabled() && map.options.scrollWheelZoom) { + map.scrollWheelZoom.disable(); + } + }); + + // when mouse moves leaves suggestions enable scroll wheel zoom if its disabled + leaflet.DomEvent.addListener(this._suggestions, 'mouseout', function (e) { + if (!map.scrollWheelZoom.enabled() && map.options.scrollWheelZoom) { + map.scrollWheelZoom.enable(); + } + }); + + this._geosearchCore.on('load', function (e) { + leaflet.DomUtil.removeClass(this._input, 'geocoder-control-loading'); + this.clear(); + this._input.blur(); + }, this); + + return this._wrapper; + } +}); + +function geosearch (options) { + return new Geosearch(options); +} + +var FeatureLayerProvider = esriLeaflet.FeatureLayerService.extend({ + options: { + label: 'Feature Layer', + maxResults: 5, + bufferRadius: 1000, + formatSuggestion: function (feature) { + return feature.properties[this.options.searchFields[0]]; + } + }, + + initialize: function (options) { + esriLeaflet.FeatureLayerService.prototype.initialize.call(this, options); + if (typeof this.options.searchFields === 'string') { + this.options.searchFields = [this.options.searchFields]; + } + this._suggestionsQuery = this.query(); + this._resultsQuery = this.query(); + }, + + suggestions: function (text, bounds, callback) { + var query = this._suggestionsQuery.where(this._buildQuery(text)) + .returnGeometry(false); + + if (bounds) { + query.intersects(bounds); + } + + if (this.options.idField) { + query.fields([this.options.idField].concat(this.options.searchFields)); + } + + var request = query.run(function (error, results, raw) { + if (error) { + callback(error, []); + } else { + this.options.idField = raw.objectIdFieldName; + var suggestions = []; + for (var i = results.features.length - 1; i >= 0; i--) { + var feature = results.features[i]; + suggestions.push({ + text: this.options.formatSuggestion.call(this, feature), + unformattedText: feature.properties[this.options.searchFields[0]], + magicKey: feature.id + }); + } + callback(error, suggestions.slice(0, this.options.maxResults)); + } + }, this); + + return request; + }, + + results: function (text, key, bounds, callback) { + var query = this._resultsQuery; + + if (key) { + delete query.params.where; + query.featureIds([key]); + } else { + query.where(this._buildQuery(text)); + } + + if (bounds) { + query.within(bounds); + } + + return query.run(leaflet.Util.bind(function (error, features) { + var results = []; + for (var i = 0; i < features.features.length; i++) { + var feature = features.features[i]; + if (feature) { + var bounds = this._featureBounds(feature); + + var result = { + latlng: bounds.getCenter(), + bounds: bounds, + text: this.options.formatSuggestion.call(this, feature), + properties: feature.properties, + geojson: feature + }; + + results.push(result); + + // clear query parameters for the next search + delete this._resultsQuery.params['objectIds']; + } + } + callback(error, results); + }, this)); + }, + + orderBy: function (fieldName, order) { + this._suggestionsQuery.orderBy(fieldName, order); + }, + + _buildQuery: function (text) { + var queryString = []; + + for (var i = this.options.searchFields.length - 1; i >= 0; i--) { + var field = 'upper("' + this.options.searchFields[i] + '")'; + + queryString.push(field + " LIKE upper('%" + text + "%')"); + } + + if (this.options.where) { + return this.options.where + ' AND (' + queryString.join(' OR ') + ')'; + } else { + return queryString.join(' OR '); + } + }, + + _featureBounds: function (feature) { + var geojson = leaflet.geoJson(feature); + if (feature.geometry.type === 'Point') { + var center = geojson.getBounds().getCenter(); + var lngRadius = ((this.options.bufferRadius / 40075017) * 360) / Math.cos((180 / Math.PI) * center.lat); + var latRadius = (this.options.bufferRadius / 40075017) * 360; + return leaflet.latLngBounds([center.lat - latRadius, center.lng - lngRadius], [center.lat + latRadius, center.lng + lngRadius]); + } else { + return geojson.getBounds(); + } + } +}); + +function featureLayerProvider (options) { + return new FeatureLayerProvider(options); +} + +var MapServiceProvider = esriLeaflet.MapService.extend({ + options: { + layers: [0], + label: 'Map Service', + bufferRadius: 1000, + maxResults: 5, + formatSuggestion: function (feature) { + return feature.properties[feature.displayFieldName] + ' ' + feature.layerName + ''; + } + }, + + initialize: function (options) { + esriLeaflet.MapService.prototype.initialize.call(this, options); + this._getIdFields(); + }, + + suggestions: function (text, bounds, callback) { + var request = this.find().text(text).fields(this.options.searchFields).returnGeometry(false).layers(this.options.layers); + + return request.run(function (error, results, raw) { + var suggestions = []; + if (!error) { + var count = Math.min(this.options.maxResults, results.features.length); + raw.results = raw.results.reverse(); + for (var i = 0; i < count; i++) { + var feature = results.features[i]; + var result = raw.results[i]; + var layer = result.layerId; + var idField = this._idFields[layer]; + feature.layerId = layer; + feature.layerName = this._layerNames[layer]; + feature.displayFieldName = this._displayFields[layer]; + if (idField) { + suggestions.push({ + text: this.options.formatSuggestion.call(this, feature), + unformattedText: feature.properties[feature.displayFieldName], + magicKey: result.attributes[idField] + ':' + layer + }); + } + } + } + callback(error, suggestions.reverse()); + }, this); + }, + + results: function (text, key, bounds, callback) { + var results = []; + var request; + + if (key) { + var featureId = key.split(':')[0]; + var layer = key.split(':')[1]; + request = this.query().layer(layer).featureIds(featureId); + } else { + request = this.find().text(text).fields(this.options.searchFields).layers(this.options.layers); + } + + return request.run(function (error, features, response) { + if (!error) { + if (response.results) { + response.results = response.results.reverse(); + } + for (var i = 0; i < features.features.length; i++) { + var feature = features.features[i]; + layer = layer || response.results[i].layerId; + + if (feature && layer !== undefined) { + var bounds = this._featureBounds(feature); + feature.layerId = layer; + feature.layerName = this._layerNames[layer]; + feature.displayFieldName = this._displayFields[layer]; + + var result = { + latlng: bounds.getCenter(), + bounds: bounds, + text: this.options.formatSuggestion.call(this, feature), + properties: feature.properties, + geojson: feature + }; + + results.push(result); + } + } + } + callback(error, results.reverse()); + }, this); + }, + + _featureBounds: function (feature) { + var geojson = leaflet.geoJson(feature); + if (feature.geometry.type === 'Point') { + var center = geojson.getBounds().getCenter(); + var lngRadius = ((this.options.bufferRadius / 40075017) * 360) / Math.cos((180 / Math.PI) * center.lat); + var latRadius = (this.options.bufferRadius / 40075017) * 360; + return leaflet.latLngBounds([center.lat - latRadius, center.lng - lngRadius], [center.lat + latRadius, center.lng + lngRadius]); + } else { + return geojson.getBounds(); + } + }, + + _layerMetadataCallback: function (layerid) { + return leaflet.Util.bind(function (error, metadata) { + if (error) { return; } + this._displayFields[layerid] = metadata.displayField; + this._layerNames[layerid] = metadata.name; + for (var i = 0; i < metadata.fields.length; i++) { + var field = metadata.fields[i]; + if (field.type === 'esriFieldTypeOID') { + this._idFields[layerid] = field.name; + break; + } + } + }, this); + }, + + _getIdFields: function () { + this._idFields = {}; + this._displayFields = {}; + this._layerNames = {}; + for (var i = 0; i < this.options.layers.length; i++) { + var layer = this.options.layers[i]; + this.get(layer, {}, this._layerMetadataCallback(layer)); + } + } +}); + +function mapServiceProvider (options) { + return new MapServiceProvider(options); +} + +var GeocodeServiceProvider = GeocodeService$$1.extend({ + options: { + label: 'Geocode Server', + maxResults: 5 + }, + + suggestions: function (text, bounds, callback) { + if (this.options.supportsSuggest) { + var request = this.suggest().text(text); + if (bounds) { + request.within(bounds); + } + + return request.run(function (error, results, response) { + var suggestions = []; + if (!error) { + while (response.suggestions.length && suggestions.length <= (this.options.maxResults - 1)) { + var suggestion = response.suggestions.shift(); + if (!suggestion.isCollection) { + suggestions.push({ + text: suggestion.text, + unformattedText: suggestion.text, + magicKey: suggestion.magicKey + }); + } + } + } + callback(error, suggestions); + }, this); + } else { + callback(undefined, []); + return false; + } + }, + + results: function (text, key, bounds, callback) { + var request = this.geocode().text(text); + + if (key) { + request.key(key); + } + + request.maxLocations(this.options.maxResults); + + if (bounds) { + request.within(bounds); + } + + return request.run(function (error, response) { + callback(error, response.results); + }, this); + } +}); + +function geocodeServiceProvider (options) { + return new GeocodeServiceProvider(options); +} + +var WorldGeocodingServiceUrl = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/'; + +exports.WorldGeocodingServiceUrl = WorldGeocodingServiceUrl; +exports.VERSION = version; +exports.Geocode = Geocode$$1; +exports.geocode = geocode$$1; +exports.ReverseGeocode = ReverseGeocode$$1; +exports.reverseGeocode = reverseGeocode$$1; +exports.Suggest = Suggest$$1; +exports.suggest = suggest$$1; +exports.GeocodeService = GeocodeService$$1; +exports.geocodeService = geocodeService$$1; +exports.Geosearch = Geosearch; +exports.geosearch = geosearch; +exports.GeosearchCore = GeosearchCore; +exports.geosearchCore = geosearchCore; +exports.ArcgisOnlineProvider = ArcgisOnlineProvider; +exports.arcgisOnlineProvider = arcgisOnlineProvider; +exports.FeatureLayerProvider = FeatureLayerProvider; +exports.featureLayerProvider = featureLayerProvider; +exports.MapServiceProvider = MapServiceProvider; +exports.mapServiceProvider = mapServiceProvider; +exports.GeocodeServiceProvider = GeocodeServiceProvider; +exports.geocodeServiceProvider = geocodeServiceProvider; + +Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/dist/esri-leaflet-geocoder.css b/dist/esri-leaflet-geocoder.css new file mode 100644 index 0000000..eb2b1d7 --- /dev/null +++ b/dist/esri-leaflet-geocoder.css @@ -0,0 +1 @@ +.geocoder-control-input{position:absolute;left:0;top:0;background-color:white;background-repeat:no-repeat;background-image:url("img/search.png");background-size:26px;border:none;padding:0;text-indent:6px;font-size:13px;line-height:normal;height:auto;padding-top:5px;padding-bottom:5px;width:100%;background-position:right center;cursor:pointer;box-sizing:border-box}.geocoder-control-input-disabled{background-color:#f4f4f4;background-image:url("img/search-disabled.png")}.geocoder-control{width:26px;height:26px;-webkit-transition:width .175s ease-in;-moz-transition:width .175s ease-in;-ms-transition:width .175s ease-in;-o-transition:width .175s ease-in;transition:width .175s ease-in}.geocoder-control-expanded,.leaflet-touch .geocoder-control-expanded{width:275px}.geocoder-control-input.geocoder-control-loading{background-image:url("img/loading.gif");background-size:26px}@media only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2 / 1), only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2){.geocoder-control-input{background-image:url("img/search@2x.png")}.geocoder-control-input-disabled{background-image:url("img/search@2x-disabled.png")}.geocoder-control-input.geocoder-control-loading{background-image:url("img/loading@2x.gif")}}.geocoder-control-input:focus{outline:none;cursor:text}.geocoder-control-input::-ms-clear{display:none}.geocoder-control-suggestions{width:100%;position:absolute;top:26px;left:0;margin-top:10px;overflow:auto;display:none}.geocoder-control-list+.geocoder-control-header{border-top:1px solid #d5d5d5}.geocoder-control-header{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:#444;background:#F2F2F2;border-bottom:1px solid #d5d5d5;display:block;padding:.5em}.geocoder-control-list{list-style:none;margin:0;padding:0}.geocoder-control-suggestions .geocoder-control-suggestion{font-size:13px;padding:7px;background:white;border-top:1px solid #f1f1f1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}.geocoder-control-suggestions .geocoder-control-suggestion:first-child{border:none}.geocoder-control-suggestions .geocoder-control-suggestion.geocoder-control-selected,.geocoder-control-suggestions .geocoder-control-suggestion:hover{background:#7FDFFF;border-color:#7FDFFF}.leaflet-right .geocoder-control-suggestions{left:auto;right:0}.leaflet-right .geocoder-control-input{left:auto;right:0}.leaflet-touch .geocoder-control{width:34px}.leaflet-touch .geocoder-control.geocoder-control-expanded{width:275px}.leaflet-touch .geocoder-control-input{height:34px;line-height:30px;background-size:30px}.leaflet-touch .geocoder-control-suggestions{top:30px;width:271px}.leaflet-oldie .geocoder-control-input{width:28px;height:28px}.leaflet-oldie .geocoder-control-expanded .geocoder-control-input{width:auto}.leaflet-oldie .geocoder-control-input,.leaflet-oldie .geocoder-control-suggestions{border:1px solid #999} diff --git a/dist/esri-leaflet-geocoder.js b/dist/esri-leaflet-geocoder.js new file mode 100644 index 0000000..641a520 --- /dev/null +++ b/dist/esri-leaflet-geocoder.js @@ -0,0 +1,4 @@ +/* esri-leaflet-geocoder - v2.2.12 - Thu Jun 14 2018 07:37:44 GMT-0700 (PDT) + * Copyright (c) 2018 Environmental Systems Research Institute, Inc. + * Apache-2.0 */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("leaflet"),require("esri-leaflet")):"function"==typeof define&&define.amd?define(["exports","leaflet","esri-leaflet"],t):t((e.L=e.L||{},e.L.esri=e.L.esri||{},e.L.esri.Geocoding={}),e.L,e.L.esri)}(this,function(e,t,s){"use strict";function i(e){return new g(e)}function o(e){return new p(e)}function r(e){return new f(e)}function n(e){return new v(e)}function a(e,t){return new m(e,t)}function l(e){return new _(e)}function u(e){return new y(e)}function d(e){return new b(e)}function h(e){return new x(e)}function c(e){return new S(e)}var g=s.Task.extend({path:"findAddressCandidates",params:{outSr:4326,forStorage:!1,outFields:"*",maxLocations:20},setters:{address:"address",neighborhood:"neighborhood",city:"city",subregion:"subregion",region:"region",postal:"postal",country:"country",text:"singleLine",category:"category",token:"token",key:"magicKey",fields:"outFields",forStorage:"forStorage",maxLocations:"maxLocations"},initialize:function(e){e=e||{},e.url=e.url||C,s.Task.prototype.initialize.call(this,e)},within:function(e){return e=t.latLngBounds(e),this.params.searchExtent=s.Util.boundsToExtent(e),this},nearby:function(e,s){var i=t.latLng(e);return this.params.location=i.lng+","+i.lat,this.params.distance=Math.min(Math.max(s,2e3),5e4),this},run:function(e,t){return this.options.customParam&&(this.params[this.options.customParam]=this.params.singleLine,delete this.params.singleLine),this.request(function(s,i){var o=this._processGeocoderResponse,r=s?void 0:o(i);e.call(t,s,{results:r},i)},this)},_processGeocoderResponse:function(e){for(var i=[],o=0;o-1?this.options.supportsSuggest=!0:this.options.supportsSuggest=!1,this.options.customParam=t.singleLineAddressField.name)},this)}}),m=t.Evented.extend({options:{zoomToResult:!0,useMapBounds:12,searchBounds:null},initialize:function(e,s){if(t.Util.setOptions(this,s),this._control=e,!s||!s.providers||!s.providers.length)throw new Error("You must specify at least one provider");this._providers=s.providers},_geocode:function(e,s,i){var o,r=0,n=[],a=t.Util.bind(function(t,s){r--,t||(s&&(n=n.concat(s)),r<=0&&(o=this._boundsFromResults(n),this.fire("results",{results:n,bounds:o,latlng:o?o.getCenter():void 0,text:e},!0),this.options.zoomToResult&&o&&this._control._map.fitBounds(o),this.fire("load")))},this);if(s)r++,i.results(e,s,this._searchBounds(),a);else for(var l=0;l=0;r--){var n=e[r];o.push(n.latlng),n.bounds&&n.bounds.isValid()&&!n.bounds.equals(s)&&i.push(n.bounds)}for(var a=t.latLngBounds(o),l=0;l0&&(this._suggestions.style.display="block"),this._suggestions.style.maxHeight=this._map.getSize().y-this._suggestions.offsetTop-this._wrapper.offsetTop-10+"px";for(var i,o,r=[],n=[],a=0;a1&&s!==l.provider.options.label&&(o=t.DomUtil.create("span","geocoder-control-header",this._suggestions),o.textContent=l.provider.options.label,o.innerText=l.provider.options.label,s=l.provider.options.label,r.push(o)),i||(i=t.DomUtil.create("ul","geocoder-control-list",this._suggestions)),-1===n.indexOf(l.text)){var u=t.DomUtil.create("li","geocoder-control-suggestion",i);u.innerHTML=l.text,u.provider=l.provider,u["data-magic-key"]=l.magicKey,u.unformattedText=l.unformattedText}else for(var d=0;d=0;r--){var n=e[r];o.push(n.latlng),n.bounds&&n.bounds.isValid()&&!n.bounds.equals(s)&&i.push(n.bounds)}for(var a=t.latLngBounds(o),l=0;l=2?(this._geosearchCore._geocode(this._input.value,void 0),this.clear()):1===o.length?(t.DomUtil.addClass(o[0],"geocoder-control-selected"),this._geosearchCore._geocode(o[0].innerHTML,o[0]["data-magic-key"],o[0].provider)):(this.clear(),this._input.blur()),t.DomEvent.preventDefault(e);break;case 38:r&&t.DomUtil.removeClass(r,"geocoder-control-selected");var a=o[i-1];r&&a?t.DomUtil.addClass(a,"geocoder-control-selected"):t.DomUtil.addClass(o[o.length-1],"geocoder-control-selected"),t.DomEvent.preventDefault(e);break;case 40:r&&t.DomUtil.removeClass(r,"geocoder-control-selected");var l=o[i+1];r&&l?t.DomUtil.addClass(l,"geocoder-control-selected"):t.DomUtil.addClass(o[0],"geocoder-control-selected"),t.DomEvent.preventDefault(e);break;default:for(var u=0;u=0;r--){var n=t.features[r];o.push({text:this.options.formatSuggestion.call(this,n),unformattedText:n.properties[this.options.searchFields[0]],magicKey:n.id})}s(e,o.slice(0,this.options.maxResults))}},this)},results:function(e,s,i,o){var r=this._resultsQuery;return s?(delete r.params.where,r.featureIds([s])):r.where(this._buildQuery(e)),i&&r.within(i),r.run(t.Util.bind(function(e,t){for(var s=[],i=0;i=0;s--){var i='upper("'+this.options.searchFields[s]+'")';t.push(i+" LIKE upper('%"+e+"%')")}return this.options.where?this.options.where+" AND ("+t.join(" OR ")+")":t.join(" OR ")},_featureBounds:function(e){var s=t.geoJson(e);if("Point"===e.geometry.type){var i=s.getBounds().getCenter(),o=this.options.bufferRadius/40075017*360/Math.cos(180/Math.PI*i.lat),r=this.options.bufferRadius/40075017*360;return t.latLngBounds([i.lat-r,i.lng-o],[i.lat+r,i.lng+o])}return s.getBounds()}}),x=s.MapService.extend({options:{layers:[0],label:"Map Service",bufferRadius:1e3,maxResults:5,formatSuggestion:function(e){return e.properties[e.displayFieldName]+" "+e.layerName+""}},initialize:function(e){s.MapService.prototype.initialize.call(this,e),this._getIdFields()},suggestions:function(e,t,s){return this.find().text(e).fields(this.options.searchFields).returnGeometry(!1).layers(this.options.layers).run(function(e,t,i){var o=[];if(!e){var r=Math.min(this.options.maxResults,t.features.length);i.results=i.results.reverse();for(var n=0;nUl;rE{yL9Q&wzjtA%a?!q_U-fM&(+n{U0q%O{{4%MjeYy} zZAnQp64gJbU&mKRhe%geuf`SS7O$2V`@JbwH*D=X{4g9oCbqMn|fMMXvS_V&Mj|Nj2{`}60|U0hsr zbaa0F`0?x4FQDTU|8x7fh6Fo12DlpO889<4Ffb_oWMSoEuxHQ#vVoqIVqjofabSLd zhmKVLi6uoRbFAk3HL=mfed`+{Dr3Gzr3wTtSGFn1-LqtO()R~#p!-N^o*0+*DRE|TAMOc`HhnvT?dAF6R+(a%e1~DEpgOl#T+7?0QgZQ>wbBmOa zi0zMj8u0Sf>o;%TIU*d-#=yqF%fJV8d^XVWD=zZ%>ojc$5U}!by3G6Ohhe?Sgv4*F zTi6ttSRP$yiaErd5`Od&+mgrcOJ#VYIb6K!_B_$AX%ur8E#edx;C0diI^W4smP^)N zLqn3CkzL7NM@p8{o}1gAiCs9?zMtVA#qF^mQiC)*D&8{rfKpGzthsI8S>v z3Fzzo3ujf%l#0x~|I~?t*J*0vBc_!}74(ASbqdjh}f{o2ydXi!5bSFEt4o%GpBrDmGqdB0%iMPMAr(mN*UrWEI z=ZEBfLbANC)vZ|gB&WW*9#~T3g zN!nU~-$@VXM?NVj7DZ;o6647#_N=V-{EFskPKHWO3!S^l1q8~G><1+?NHiw_y{s{j zr~iaQ!VL$$srKB5*^2*ZOp#AM_#(1ZjPKYdS*||8X2nOq_?gka^hR2^7JiOyl zq2r`1XjEm-1oWxBy1G3u)jJz@N!v3s+w;nqS~;uPIn8jgNR^TCL$Q_}Xe}t7vk%-q z|3pBler8Kyn#6=YQ1&Zn^-XU@h&$D|IcFpXO}shKN=aB$dj%1Y_DX}c|SGbnKq7cX&S Gum%9n!NQ>c literal 0 HcmV?d00001 diff --git a/dist/img/loading@2x.gif b/dist/img/loading@2x.gif new file mode 100644 index 0000000000000000000000000000000000000000..ceec3a11aad13fcb1da4d045e277b2f041b9a373 GIT binary patch literal 3973 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 literal 0 HcmV?d00001 diff --git a/dist/img/search-disabled.png b/dist/img/search-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..7f8f5bb39a49d203ca5013704469c3c9e62a2767 GIT binary patch literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^CLqkg1|*MGNWTVBY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPN6Q>xr@S>fsrxni&L zT896{)53(K*NNWA*dBd;t772>FK@%=I!#UtznCsu&Pt8l6)Gyly8El8OQ^P1MpoSJ zSFYW$Q43o-pRPGCGF@hpQ|9WG*B*E_FE%^2Hu>#A&nV9C-ws;u-?mFLfIaoX b+Ce<$ac|_@u-{q0&|>g(^>bP0l+XkK9x<84 literal 0 HcmV?d00001 diff --git a/dist/img/search.png b/dist/img/search.png new file mode 100644 index 0000000000000000000000000000000000000000..0d01c4545e01d6d9773221a7209b6bc86b364cd4 GIT binary patch literal 425 zcmV;a0apHrP)~EiaUMAvsUQr<`5(fS6Ajfg^kM(H9D=zWr_l)bhzTZ_G;Kx*B4No}6 z1@1BUn-P^5`b%+uF6?0+QH*0to=@8d8j+AW%xdikoMIU}$e4mmf879HFrU@_j76EZ z?jR#F1vTOUA3l9Ia&52?bcYty`t-HS_0~pE3guWunbzKhIIeMKV=?SvLl#9R4pE0b z2_F7wKjpHIMlppijG-S#c*iz|Yz3*KV+qZuLIrwpg-RsRWFttgHyN3#3E4k2*vy*4 zKL_b`j!C)iz(T%)RIOu0?x)d{uOL-3IFVC5=j9!w)Tt4Zxq1xWuwjs~z6BTnz+hU1 TvwpQk00000NkvXXu0mjfh5NJY literal 0 HcmV?d00001 diff --git a/dist/img/search@2x-disabled.png b/dist/img/search@2x-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..5ae89b3038066afb800bafcaf50b5688026e498d GIT binary patch literal 386 zcmeAS@N?(olHy`uVBq!ia0vp^CLqkg1|*MGNWTVBY)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmPN6Q>v#kJ+kgs~H#=`8{16Lo)8Yo#o5ds=(9ov~_oZ z#kt21EqK@6I~FkEU%;ZnLWbXxm$j<3MZNyG?4xy@83T&~10#n61Ji^@9e2coz0Usp zY;$sV$T`b1b<3w1ZM7?SUsS$8u7f2<%;RX0vB8|L-irxni&L zT896{)53(K*NNWA*dBd;t772>FK@%=I!#UtznCsu&Pt8l6)Gyly8El8OQ^P1MpoSJ zSFYW$Q43o-pRPGCGF@hpQ|9WG*B*E_FE%^2Hu>#A&nV9C-ws;u-?mFLfIaoX b+Ce<$ac|_@u-{q0&|>g(^>bP0l+XkK58|1+ literal 0 HcmV?d00001 diff --git a/dist/img/search@2x.png b/dist/img/search@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5e96a8b967a018b379a0eb79a475865a92e59ceb GIT binary patch literal 772 zcmV+f1N;1mP)qCJ4=M_RNE5_*tw8#CkPrnwqMq_Wl)fks0<(;Q-l9YZ2@(_`da*V_p@>Mc zDAWY2?SJ4594<4uvo7u#xd(o5@0q!?{AcdH=bXFYSS%J=NR}2_U}gnbK~|6zWCdA4 zR!|acaiRkwk%-r&rC>kE1FOJSFbulEgx}wZMx*m1$i-HJdT@q?m^KCOg9h+L`;^-a z-hzuBV#w0LDew-IY8F%gxJ{xR;6R+?Xjj`M`Y*HydSzq**FeTBW0rv199W&{)}=)dMg2>n zza2cCVUas2&tBnc0plvl2ewX7299&Th`-t$@Ql|-7Ei~soGLl?8eC0wrVvi_C|J}( zD>$wc`g{bvgqL6}ne|XIvTZ8b4uTutkB@QJ`3oM^SPxP3zW{cCo8Xgi{Tt{2N5n?5 zk*nLgV3U?LWZED&&#dE&nilRj#zZ`+fGKbuSQw4ezhdjn3p_z!`aAPRCa zjTRUG6(fNSj3BaV(Bl$L+POpzoFLjH%3XqSW+HJ?%VGT}ZxU17f6sw-I@OuNTx