diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..9d08a1a8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.eslintrc.yaml b/.eslintrc.yaml new file mode 100644 index 00000000..3c25a463 --- /dev/null +++ b/.eslintrc.yaml @@ -0,0 +1,15 @@ +extends: + - eslint:recommended + +plugins: + - prettier + +env: + browser: true + es6: true + +parserOptions: + sourceType: module + +rules: + prettier/prettier: warn diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 051eb890..00000000 --- a/.jshintrc +++ /dev/null @@ -1,54 +0,0 @@ -{ - /* - * ENVIRONMENTS - * ================= - */ - - // Define globals exposed by modern browsers. - "browser": true, - - "node": true, - - "globals": {}, - - /* - * ENFORCING OPTIONS - * ================= - */ - - // Force all variable names to use either camelCase style or UPPER_CASE - // with underscores. - "camelcase": true, - - // Prohibit use of == and != in favor of === and !==. - "eqeqeq": true, - - // Suppress warnings about == null comparisons. - "eqnull": true, - - // Enforce tab width of 2 spaces. - "indent": 2, - - "smarttabs": true, - - // Prohibit use of a variable before it is defined. - "latedef": true, - - // Require capitalized names for constructor functions. - "newcap": true, - - // Enforce use of single quotation marks for strings. - "quotmark": "single", - - // Prohibit trailing whitespace. - "trailing": true, - - // Prohibit use of explicitly undeclared variables. - "undef": true, - - // Warn when variables are defined but never used. - "unused": true, - - // All loops and conditionals should have braces. - "curly": true -} diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 00000000..7c1575a5 --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,2 @@ +printWidth: 100 +singleQuote: true diff --git a/Control.Geocoder.css b/Control.Geocoder.css index f89d72eb..00c32255 100644 --- a/Control.Geocoder.css +++ b/Control.Geocoder.css @@ -1,123 +1,126 @@ .leaflet-control-geocoder { - border-radius: 4px; - background: white; - min-width: 26px; - min-height: 26px; + border-radius: 4px; + background: white; + min-width: 26px; + min-height: 26px; } .leaflet-touch .leaflet-control-geocoder { - min-width: 30px; - min-height: 30px; + min-width: 30px; + min-height: 30px; } -.leaflet-control-geocoder a, .leaflet-control-geocoder .leaflet-control-geocoder-icon { - border-bottom: none; - display: inline-block; +.leaflet-control-geocoder a, +.leaflet-control-geocoder .leaflet-control-geocoder-icon { + border-bottom: none; + display: inline-block; } .leaflet-control-geocoder .leaflet-control-geocoder-alternatives a { - width: inherit; - height: inherit; - line-height: inherit; + width: inherit; + height: inherit; + line-height: inherit; } -.leaflet-control-geocoder a:hover, .leaflet-control-geocoder .leaflet-control-geocoder-icon:hover { - border-bottom: none; - display: inline-block; +.leaflet-control-geocoder a:hover, +.leaflet-control-geocoder .leaflet-control-geocoder-icon:hover { + border-bottom: none; + display: inline-block; } .leaflet-control-geocoder-form { - display: none; - vertical-align: middle; + display: none; + vertical-align: middle; } .leaflet-control-geocoder-expanded .leaflet-control-geocoder-form { - display: inline-block; + display: inline-block; } .leaflet-control-geocoder-form input { - font-size: 120%; - border: 0; - background-color: transparent; - width: 246px; + font-size: 120%; + border: 0; + background-color: transparent; + width: 246px; } .leaflet-control-geocoder-icon { - border-radius: 4px; - width: 26px; - height: 26px; - border: none; - background-color: white; - background-image: url(images/geocoder.png); - background-repeat: no-repeat; - background-position: center; - cursor: pointer; + border-radius: 4px; + width: 26px; + height: 26px; + border: none; + background-color: white; + background-image: url(images/geocoder.png); + background-repeat: no-repeat; + background-position: center; + cursor: pointer; } .leaflet-touch .leaflet-control-geocoder-icon { - width: 30px; - height: 30px; + width: 30px; + height: 30px; } .leaflet-control-geocoder-throbber .leaflet-control-geocoder-icon { - background-image: url(images/throbber.gif); + background-image: url(images/throbber.gif); } .leaflet-control-geocoder-form-no-error { - display: none; + display: none; } .leaflet-control-geocoder-form input:focus { - outline: none; + outline: none; } .leaflet-control-geocoder-form button { - display: none; + display: none; } .leaflet-control-geocoder-error { - margin-top: 8px; - margin-left: 8px; - display: block; - color: #444; + margin-top: 8px; + margin-left: 8px; + display: block; + color: #444; } .leaflet-control-geocoder-alternatives { - display: block; - width: 272px; - list-style: none; - padding: 0; - margin: 0; + display: block; + width: 272px; + list-style: none; + padding: 0; + margin: 0; } .leaflet-control-geocoder-alternatives-minimized { - display: none; - height: 0; + display: none; + height: 0; } .leaflet-control-geocoder-alternatives li { - white-space: nowrap; - display: block; - overflow: hidden; - padding: 5px 8px; - text-overflow: ellipsis; - border-bottom: 1px solid #ccc; - cursor: pointer; + white-space: nowrap; + display: block; + overflow: hidden; + padding: 5px 8px; + text-overflow: ellipsis; + border-bottom: 1px solid #ccc; + cursor: pointer; } -.leaflet-control-geocoder-alternatives li a, .leaflet-control-geocoder-alternatives li a:hover { - width: inherit; - height: inherit; - line-height: inherit; - background: inherit; - border-radius: inherit; - text-align: left; +.leaflet-control-geocoder-alternatives li a, +.leaflet-control-geocoder-alternatives li a:hover { + width: inherit; + height: inherit; + line-height: inherit; + background: inherit; + border-radius: inherit; + text-align: left; } .leaflet-control-geocoder-alternatives li:last-child { - border-bottom: none; + border-bottom: none; } -.leaflet-control-geocoder-alternatives li:hover, .leaflet-control-geocoder-selected { - background-color: #f5f5f5; +.leaflet-control-geocoder-alternatives li:hover, +.leaflet-control-geocoder-selected { + background-color: #f5f5f5; } .leaflet-control-geocoder-address-detail { - } .leaflet-control-geocoder-address-context { - color: #666; -} \ No newline at end of file + color: #666; +} diff --git a/package.json b/package.json index 558e82b1..b02c6540 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,10 @@ "build:js": "rollup --output.format=iife --name=L.Control.Geocoder --globals=leaflet:L src/index.js --output.file=dist/Control.Geocoder.js --sourcemap", "build:css": "cpr Control.Geocoder.css dist/ --overwrite", "build:img": "cpr images/ dist/images/ --overwrite", + "test": "npm run lint", + "lint": "npm run lint:js && npm run lint:css", + "lint:js": "eslint 'src/**'", + "lint:css": "prettier --list-different '*.css'", "publish": "sh ./scripts/publish.sh", "postpublish": "sh ./scripts/postpublish.sh" }, @@ -38,6 +42,9 @@ "dependencies": {}, "devDependencies": { "cpr": "^3.0.1", + "eslint": "^4.15.0", + "eslint-plugin-prettier": "^2.4.0", + "prettier": "^1.9.2", "rollup": "^0.53.2" } } diff --git a/src/control.js b/src/control.js index 33fc77e0..8aa0c81e 100644 --- a/src/control.js +++ b/src/control.js @@ -2,302 +2,345 @@ import L from 'leaflet'; import Nominatim from './geocoders/nominatim'; export default { - class: L.Control.extend({ - options: { - showResultIcons: false, - collapsed: true, - expand: 'touch', // options: touch, click, anythingelse - position: 'topright', - placeholder: 'Search...', - errorMessage: 'Nothing found.', - suggestMinLength: 3, - suggestTimeout: 250, - defaultMarkGeocode: true - }, - - includes: L.Evented.prototype || L.Mixin.Events, - - initialize: function (options) { - L.Util.setOptions(this, options); - if (!this.options.geocoder) { - this.options.geocoder = new Nominatim.class(); - } - - this._requestCount = 0; - }, - - onAdd: function (map) { - var className = 'leaflet-control-geocoder', - container = L.DomUtil.create('div', className + ' leaflet-bar'), - icon = L.DomUtil.create('button', className + '-icon', container), - form = this._form = L.DomUtil.create('div', className + '-form', container), - input; - - this._map = map; - this._container = container; - - icon.innerHTML = ' '; - icon.type = 'button'; - - input = this._input = L.DomUtil.create('input', '', form); - input.type = 'text'; - input.placeholder = this.options.placeholder; - - this._errorElement = L.DomUtil.create('div', className + '-form-no-error', container); - this._errorElement.innerHTML = this.options.errorMessage; - - this._alts = L.DomUtil.create('ul', - className + '-alternatives leaflet-control-geocoder-alternatives-minimized', - container); - L.DomEvent.disableClickPropagation(this._alts); - - L.DomEvent.addListener(input, 'keydown', this._keydown, this); - if (this.options.geocoder.suggest) { - L.DomEvent.addListener(input, 'input', this._change, this); - } - L.DomEvent.addListener(input, 'blur', function() { - if (this.options.collapsed && !this._preventBlurCollapse) { - this._collapse(); - } - this._preventBlurCollapse = false; - }, this); - - - if (this.options.collapsed) { - if (this.options.expand === 'click') { - L.DomEvent.addListener(container, 'click', function(e) { - if (e.button === 0 && e.detail !== 2) { - this._toggle(); - } - }, this); - } - else if (L.Browser.touch && this.options.expand === 'touch') { - L.DomEvent.addListener(container, 'touchstart mousedown', function(e) { - this._toggle(); - e.preventDefault(); // mobile: clicking focuses the icon, so UI expands and immediately collapses - e.stopPropagation(); - }, this); - } - else { - L.DomEvent.addListener(container, 'mouseenter', this._expand, this); - L.DomEvent.addListener(container, 'mouseleave', this._collapse, this); - this._map.on('movestart', this._collapse, this); - } - } else { - this._expand(); - if (L.Browser.touch) { - L.DomEvent.addListener(container, 'touchstart', function(e) { - this._geocode(); - }, this); - } - else { - L.DomEvent.addListener(container, 'click', function(e) { - this._geocode(); - }, this); - } - } - - if (this.options.defaultMarkGeocode) { - this.on('markgeocode', this.markGeocode, this); - } - - this.on('startgeocode', function() { - L.DomUtil.addClass(this._container, 'leaflet-control-geocoder-throbber'); - }, this); - this.on('finishgeocode', function() { - L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-throbber'); - }, this); - - L.DomEvent.disableClickPropagation(container); - - return container; - }, - - _geocodeResult: function (results, suggest) { - if (!suggest && results.length === 1) { - this._geocodeResultSelected(results[0]); - } else if (results.length > 0) { - this._alts.innerHTML = ''; - this._results = results; - L.DomUtil.removeClass(this._alts, 'leaflet-control-geocoder-alternatives-minimized'); - for (var i = 0; i < results.length; i++) { - this._alts.appendChild(this._createAlt(results[i], i)); - } - } else { - L.DomUtil.addClass(this._errorElement, 'leaflet-control-geocoder-error'); - } - }, - - markGeocode: function(result) { - result = result.geocode || result; - - this._map.fitBounds(result.bbox); - - if (this._geocodeMarker) { - this._map.removeLayer(this._geocodeMarker); - } - - this._geocodeMarker = new L.Marker(result.center) - .bindPopup(result.html || result.name) - .addTo(this._map) - .openPopup(); - - return this; - }, - - _geocode: function(suggest) { - var requestCount = ++this._requestCount, - mode = suggest ? 'suggest' : 'geocode', - eventData = {input: this._input.value}; - - this._lastGeocode = this._input.value; - if (!suggest) { - this._clearResults(); - } - - this.fire('start' + mode, eventData); - this.options.geocoder[mode](this._input.value, function(results) { - if (requestCount === this._requestCount) { - eventData.results = results; - this.fire('finish' + mode, eventData); - this._geocodeResult(results, suggest); - } - }, this); - }, - - _geocodeResultSelected: function(result) { - this.fire('markgeocode', {geocode: result}); - }, - - _toggle: function() { - if (L.DomUtil.hasClass(this._container, 'leaflet-control-geocoder-expanded')) { - this._collapse(); - } else { - this._expand(); - } - }, - - _expand: function () { - L.DomUtil.addClass(this._container, 'leaflet-control-geocoder-expanded'); - this._input.select(); - this.fire('expand'); - }, - - _collapse: function () { - 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'); - this._input.blur(); // mobile: keyboard shouldn't stay expanded - this.fire('collapse'); - }, - - _clearResults: function () { - L.DomUtil.addClass(this._alts, 'leaflet-control-geocoder-alternatives-minimized'); - this._selection = null; - L.DomUtil.removeClass(this._errorElement, 'leaflet-control-geocoder-error'); - }, - - _createAlt: function(result, index) { - var li = L.DomUtil.create('li', ''), - a = L.DomUtil.create('a', '', li), - icon = this.options.showResultIcons && result.icon ? L.DomUtil.create('img', '', a) : null, - text = result.html ? undefined : document.createTextNode(result.name), - mouseDownHandler = function mouseDownHandler(e) { - // In some browsers, a click will fire on the map if the control is - // collapsed directly after mousedown. To work around this, we - // wait until the click is completed, and _then_ collapse the - // control. Messy, but this is the workaround I could come up with - // for #142. - this._preventBlurCollapse = true; - L.DomEvent.stop(e); - this._geocodeResultSelected(result); - L.DomEvent.on(li, 'click', function() { - if (this.options.collapsed) { - this._collapse(); - } else { - this._clearResults(); - } - }, this); - }; - - if (icon) { - icon.src = result.icon; - } - - li.setAttribute('data-result-index', index); - - if (result.html) { - a.innerHTML = a.innerHTML + result.html; - } else { - a.appendChild(text); - } - - // Use mousedown and not click, since click will fire _after_ blur, - // causing the control to have collapsed and removed the items - // before the click can fire. - L.DomEvent.addListener(li, 'mousedown touchstart', mouseDownHandler, this); - - return li; - }, - - _keydown: function(e) { - var _this = this, - select = function select(dir) { - if (_this._selection) { - L.DomUtil.removeClass(_this._selection, 'leaflet-control-geocoder-selected'); - _this._selection = _this._selection[dir > 0 ? 'nextSibling' : 'previousSibling']; - } - if (!_this._selection) { - _this._selection = _this._alts[dir > 0 ? 'firstChild' : 'lastChild']; - } - - if (_this._selection) { - L.DomUtil.addClass(_this._selection, 'leaflet-control-geocoder-selected'); - } - }; - - switch (e.keyCode) { - // Escape - case 27: - if (this.options.collapsed) { - this._collapse(); - } - break; - // Up - case 38: - select(-1); - break; - // Up - case 40: - select(1); - break; - // Enter - case 13: - if (this._selection) { - var index = parseInt(this._selection.getAttribute('data-result-index'), 10); - this._geocodeResultSelected(this._results[index]); - this._clearResults(); - } else { - this._geocode(); - } - break; - } - }, - _change: function(e) { - var v = this._input.value; - if (v !== this._lastGeocode) { - clearTimeout(this._suggestTimeout); - if (v.length >= this.options.suggestMinLength) { - this._suggestTimeout = setTimeout(L.bind(function() { - this._geocode(true); - }, this), this.options.suggestTimeout); - } else { - this._clearResults(); - } - } - } - }), - factory: function(options) { - return new L.Control.Geocoder(options); - } + class: L.Control.extend({ + options: { + showResultIcons: false, + collapsed: true, + expand: 'touch', // options: touch, click, anythingelse + position: 'topright', + placeholder: 'Search...', + errorMessage: 'Nothing found.', + suggestMinLength: 3, + suggestTimeout: 250, + defaultMarkGeocode: true + }, + + includes: L.Evented.prototype || L.Mixin.Events, + + initialize: function(options) { + L.Util.setOptions(this, options); + if (!this.options.geocoder) { + this.options.geocoder = new Nominatim.class(); + } + + this._requestCount = 0; + }, + + onAdd: function(map) { + var className = 'leaflet-control-geocoder', + container = L.DomUtil.create('div', className + ' leaflet-bar'), + icon = L.DomUtil.create('button', className + '-icon', container), + form = (this._form = L.DomUtil.create('div', className + '-form', container)), + input; + + this._map = map; + this._container = container; + + icon.innerHTML = ' '; + icon.type = 'button'; + + input = this._input = L.DomUtil.create('input', '', form); + input.type = 'text'; + input.placeholder = this.options.placeholder; + + this._errorElement = L.DomUtil.create('div', className + '-form-no-error', container); + this._errorElement.innerHTML = this.options.errorMessage; + + this._alts = L.DomUtil.create( + 'ul', + className + '-alternatives leaflet-control-geocoder-alternatives-minimized', + container + ); + L.DomEvent.disableClickPropagation(this._alts); + + L.DomEvent.addListener(input, 'keydown', this._keydown, this); + if (this.options.geocoder.suggest) { + L.DomEvent.addListener(input, 'input', this._change, this); + } + L.DomEvent.addListener( + input, + 'blur', + function() { + if (this.options.collapsed && !this._preventBlurCollapse) { + this._collapse(); + } + this._preventBlurCollapse = false; + }, + this + ); + + if (this.options.collapsed) { + if (this.options.expand === 'click') { + L.DomEvent.addListener( + container, + 'click', + function(e) { + if (e.button === 0 && e.detail !== 2) { + this._toggle(); + } + }, + this + ); + } else if (L.Browser.touch && this.options.expand === 'touch') { + L.DomEvent.addListener( + container, + 'touchstart mousedown', + function(e) { + this._toggle(); + e.preventDefault(); // mobile: clicking focuses the icon, so UI expands and immediately collapses + e.stopPropagation(); + }, + this + ); + } else { + L.DomEvent.addListener(container, 'mouseover', this._expand, this); + L.DomEvent.addListener(container, 'mouseout', this._collapse, this); + this._map.on('movestart', this._collapse, this); + } + } else { + this._expand(); + if (L.Browser.touch) { + L.DomEvent.addListener( + container, + 'touchstart', + function() { + this._geocode(); + }, + this + ); + } else { + L.DomEvent.addListener( + container, + 'click', + function() { + this._geocode(); + }, + this + ); + } + } + + if (this.options.defaultMarkGeocode) { + this.on('markgeocode', this.markGeocode, this); + } + + this.on( + 'startgeocode', + function() { + L.DomUtil.addClass(this._container, 'leaflet-control-geocoder-throbber'); + }, + this + ); + this.on( + 'finishgeocode', + function() { + L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-throbber'); + }, + this + ); + + L.DomEvent.disableClickPropagation(container); + + return container; + }, + + _geocodeResult: function(results, suggest) { + if (!suggest && results.length === 1) { + this._geocodeResultSelected(results[0]); + } else if (results.length > 0) { + this._alts.innerHTML = ''; + this._results = results; + L.DomUtil.removeClass(this._alts, 'leaflet-control-geocoder-alternatives-minimized'); + for (var i = 0; i < results.length; i++) { + this._alts.appendChild(this._createAlt(results[i], i)); + } + } else { + L.DomUtil.addClass(this._errorElement, 'leaflet-control-geocoder-error'); + } + }, + + markGeocode: function(result) { + result = result.geocode || result; + + this._map.fitBounds(result.bbox); + + if (this._geocodeMarker) { + this._map.removeLayer(this._geocodeMarker); + } + + this._geocodeMarker = new L.Marker(result.center) + .bindPopup(result.html || result.name) + .addTo(this._map) + .openPopup(); + + return this; + }, + + _geocode: function(suggest) { + var requestCount = ++this._requestCount, + mode = suggest ? 'suggest' : 'geocode', + eventData = { input: this._input.value }; + + this._lastGeocode = this._input.value; + if (!suggest) { + this._clearResults(); + } + + this.fire('start' + mode, eventData); + this.options.geocoder[mode]( + this._input.value, + function(results) { + if (requestCount === this._requestCount) { + eventData.results = results; + this.fire('finish' + mode, eventData); + this._geocodeResult(results, suggest); + } + }, + this + ); + }, + + _geocodeResultSelected: function(result) { + this.fire('markgeocode', { geocode: result }); + }, + + _toggle: function() { + if (L.DomUtil.hasClass(this._container, 'leaflet-control-geocoder-expanded')) { + this._collapse(); + } else { + this._expand(); + } + }, + + _expand: function() { + L.DomUtil.addClass(this._container, 'leaflet-control-geocoder-expanded'); + this._input.select(); + this.fire('expand'); + }, + + _collapse: function() { + 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'); + this._input.blur(); // mobile: keyboard shouldn't stay expanded + this.fire('collapse'); + }, + + _clearResults: function() { + L.DomUtil.addClass(this._alts, 'leaflet-control-geocoder-alternatives-minimized'); + this._selection = null; + L.DomUtil.removeClass(this._errorElement, 'leaflet-control-geocoder-error'); + }, + + _createAlt: function(result, index) { + var li = L.DomUtil.create('li', ''), + a = L.DomUtil.create('a', '', li), + icon = this.options.showResultIcons && result.icon ? L.DomUtil.create('img', '', a) : null, + text = result.html ? undefined : document.createTextNode(result.name), + mouseDownHandler = function mouseDownHandler(e) { + // In some browsers, a click will fire on the map if the control is + // collapsed directly after mousedown. To work around this, we + // wait until the click is completed, and _then_ collapse the + // control. Messy, but this is the workaround I could come up with + // for #142. + this._preventBlurCollapse = true; + L.DomEvent.stop(e); + this._geocodeResultSelected(result); + L.DomEvent.on( + li, + 'click', + function() { + if (this.options.collapsed) { + this._collapse(); + } else { + this._clearResults(); + } + }, + this + ); + }; + + if (icon) { + icon.src = result.icon; + } + + li.setAttribute('data-result-index', index); + + if (result.html) { + a.innerHTML = a.innerHTML + result.html; + } else { + a.appendChild(text); + } + + // Use mousedown and not click, since click will fire _after_ blur, + // causing the control to have collapsed and removed the items + // before the click can fire. + L.DomEvent.addListener(li, 'mousedown touchstart', mouseDownHandler, this); + + return li; + }, + + _keydown: function(e) { + var _this = this, + select = function select(dir) { + if (_this._selection) { + L.DomUtil.removeClass(_this._selection, 'leaflet-control-geocoder-selected'); + _this._selection = _this._selection[dir > 0 ? 'nextSibling' : 'previousSibling']; + } + if (!_this._selection) { + _this._selection = _this._alts[dir > 0 ? 'firstChild' : 'lastChild']; + } + + if (_this._selection) { + L.DomUtil.addClass(_this._selection, 'leaflet-control-geocoder-selected'); + } + }; + + switch (e.keyCode) { + // Escape + case 27: + if (this.options.collapsed) { + this._collapse(); + } + break; + // Up + case 38: + select(-1); + break; + // Up + case 40: + select(1); + break; + // Enter + case 13: + if (this._selection) { + var index = parseInt(this._selection.getAttribute('data-result-index'), 10); + this._geocodeResultSelected(this._results[index]); + this._clearResults(); + } else { + this._geocode(); + } + break; + } + }, + _change: function() { + var v = this._input.value; + if (v !== this._lastGeocode) { + clearTimeout(this._suggestTimeout); + if (v.length >= this.options.suggestMinLength) { + this._suggestTimeout = setTimeout( + L.bind(function() { + this._geocode(true); + }, this), + this.options.suggestTimeout + ); + } else { + this._clearResults(); + } + } + } + }), + factory: function(options) { + return new L.Control.Geocoder(options); + } }; diff --git a/src/geocoders/arcgis.js b/src/geocoders/arcgis.js index afb87e5d..8a64e7f9 100644 --- a/src/geocoders/arcgis.js +++ b/src/geocoders/arcgis.js @@ -1,83 +1,86 @@ import L from 'leaflet'; -import {getJSON} from '../util'; +import { getJSON } from '../util'; export default { - class: L.Class.extend({ - options: { - service_url: 'http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer' - }, + class: L.Class.extend({ + options: { + service_url: 'http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer' + }, - initialize: function(accessToken, options) { - L.setOptions(this, options); - this._accessToken = accessToken; - }, + initialize: function(accessToken, options) { + L.setOptions(this, options); + this._accessToken = accessToken; + }, - geocode: function(query, cb, context) { - var params = { - SingleLine: query, - outFields: 'Addr_Type', - forStorage: false, - maxLocations: 10, - f: 'json' - }; + geocode: function(query, cb, context) { + var params = { + SingleLine: query, + outFields: 'Addr_Type', + forStorage: false, + maxLocations: 10, + f: 'json' + }; - if (this._key && this._key.length) { - params.token = this._key; - } + if (this._key && this._key.length) { + params.token = this._key; + } - getJSON(this.options.service_url + '/findAddressCandidates', params, function(data) { - var results = [], - loc, - latLng, - latLngBounds; + getJSON(this.options.service_url + '/findAddressCandidates', params, function(data) { + var results = [], + loc, + latLng, + latLngBounds; - if (data.candidates && data.candidates.length) { - for (var i = 0; i <= data.candidates.length - 1; i++) { - loc = data.candidates[i]; - latLng = L.latLng(loc.location.y, loc.location.x); - latLngBounds = L.latLngBounds(L.latLng(loc.extent.ymax, loc.extent.xmax), L.latLng(loc.extent.ymin, loc.extent.xmin)); - results[i] = { - name: loc.address, - bbox: latLngBounds, - center: latLng - }; - } - } + if (data.candidates && data.candidates.length) { + for (var i = 0; i <= data.candidates.length - 1; i++) { + loc = data.candidates[i]; + latLng = L.latLng(loc.location.y, loc.location.x); + latLngBounds = L.latLngBounds( + L.latLng(loc.extent.ymax, loc.extent.xmax), + L.latLng(loc.extent.ymin, loc.extent.xmin) + ); + results[i] = { + name: loc.address, + bbox: latLngBounds, + center: latLng + }; + } + } - cb.call(context, results); - }); - }, + cb.call(context, results); + }); + }, - suggest: function(query, cb, context) { - return this.geocode(query, cb, context); - }, + suggest: function(query, cb, context) { + return this.geocode(query, cb, context); + }, - reverse: function(location, scale, cb, context) { - var params = { - location: encodeURIComponent(location.lng) + ',' + encodeURIComponent(location.lat), - distance: 100, - f: 'json' - }; + reverse: function(location, scale, cb, context) { + var params = { + location: encodeURIComponent(location.lng) + ',' + encodeURIComponent(location.lat), + distance: 100, + f: 'json' + }; - getJSON(this.options.service_url + '/reverseGeocode', params, function(data) { - var result = [], - loc; + getJSON(this.options.service_url + '/reverseGeocode', params, function(data) { + var result = [], + loc; - if (data && !data.error) { - loc = L.latLng(data.location.y, data.location.x); - result.push({ - name: data.address.Match_addr, - center: loc, - bounds: L.latLngBounds(loc, loc) - }); - } + if (data && !data.error) { + loc = L.latLng(data.location.y, data.location.x); + result.push({ + name: data.address.Match_addr, + center: loc, + bounds: L.latLngBounds(loc, loc) + }); + } - cb.call(context, result); - }); - } - }), + cb.call(context, result); + }); + } + }), - factory: function(accessToken, options) { - return new L.Control.Geocoder.ArcGis(accessToken, options); - } + factory: function(accessToken, options) { + return new L.Control.Geocoder.ArcGis(accessToken, options); + } }; diff --git a/src/geocoders/bing.js b/src/geocoders/bing.js index fc147004..4e1dc6c9 100644 --- a/src/geocoders/bing.js +++ b/src/geocoders/bing.js @@ -1,53 +1,65 @@ import L from 'leaflet'; -import {jsonp} from '../util'; +import { jsonp } from '../util'; export default { - class: L.Class.extend({ - initialize: function(key) { - this.key = key; - }, + class: L.Class.extend({ + initialize: function(key) { + this.key = key; + }, - geocode : function (query, cb, context) { - jsonp('https://dev.virtualearth.net/REST/v1/Locations', { - query: query, - key : this.key - }, function(data) { - var results = []; - if( data.resourceSets.length > 0 ){ - for (var i = data.resourceSets[0].resources.length - 1; i >= 0; i--) { - var resource = data.resourceSets[0].resources[i], - bbox = resource.bbox; - results[i] = { - name: resource.name, - bbox: L.latLngBounds([bbox[0], bbox[1]], [bbox[2], bbox[3]]), - center: L.latLng(resource.point.coordinates) - }; - } - } - cb.call(context, results); - }, this, 'jsonp'); - }, + geocode: function(query, cb, context) { + jsonp( + 'https://dev.virtualearth.net/REST/v1/Locations', + { + query: query, + key: this.key + }, + function(data) { + var results = []; + if (data.resourceSets.length > 0) { + for (var i = data.resourceSets[0].resources.length - 1; i >= 0; i--) { + var resource = data.resourceSets[0].resources[i], + bbox = resource.bbox; + results[i] = { + name: resource.name, + bbox: L.latLngBounds([bbox[0], bbox[1]], [bbox[2], bbox[3]]), + center: L.latLng(resource.point.coordinates) + }; + } + } + cb.call(context, results); + }, + this, + 'jsonp' + ); + }, - reverse: function(location, scale, cb, context) { - jsonp('//dev.virtualearth.net/REST/v1/Locations/' + location.lat + ',' + location.lng, { - key : this.key - }, function(data) { - var results = []; - for (var i = data.resourceSets[0].resources.length - 1; i >= 0; i--) { - var resource = data.resourceSets[0].resources[i], - bbox = resource.bbox; - results[i] = { - name: resource.name, - bbox: L.latLngBounds([bbox[0], bbox[1]], [bbox[2], bbox[3]]), - center: L.latLng(resource.point.coordinates) - }; - } - cb.call(context, results); - }, this, 'jsonp'); - } - }), + reverse: function(location, scale, cb, context) { + jsonp( + '//dev.virtualearth.net/REST/v1/Locations/' + location.lat + ',' + location.lng, + { + key: this.key + }, + function(data) { + var results = []; + for (var i = data.resourceSets[0].resources.length - 1; i >= 0; i--) { + var resource = data.resourceSets[0].resources[i], + bbox = resource.bbox; + results[i] = { + name: resource.name, + bbox: L.latLngBounds([bbox[0], bbox[1]], [bbox[2], bbox[3]]), + center: L.latLng(resource.point.coordinates) + }; + } + cb.call(context, results); + }, + this, + 'jsonp' + ); + } + }), - factory: function(key) { - return new L.Control.Geocoder.Bing(key); - } + factory: function(key) { + return new L.Control.Geocoder.Bing(key); + } }; diff --git a/src/geocoders/google.js b/src/geocoders/google.js index 8995c535..eeb1d9dd 100644 --- a/src/geocoders/google.js +++ b/src/geocoders/google.js @@ -1,89 +1,95 @@ import L from 'leaflet'; -import {getJSON} from '../util'; +import { getJSON } from '../util'; export default { - class: L.Class.extend({ - options: { - serviceUrl: 'https://maps.googleapis.com/maps/api/geocode/json', - geocodingQueryParams: {}, - reverseQueryParams: {} - }, + class: L.Class.extend({ + options: { + serviceUrl: 'https://maps.googleapis.com/maps/api/geocode/json', + geocodingQueryParams: {}, + reverseQueryParams: {} + }, - initialize: function(key, options) { - this._key = key; - L.setOptions(this, options); - // Backwards compatibility - this.options.serviceUrl = this.options.service_url || this.options.serviceUrl; - }, + initialize: function(key, options) { + this._key = key; + L.setOptions(this, options); + // Backwards compatibility + this.options.serviceUrl = this.options.service_url || this.options.serviceUrl; + }, - geocode: function(query, cb, context) { - var params = { - address: query, - }; + geocode: function(query, cb, context) { + var params = { + address: query + }; - if (this._key && this._key.length) { - params.key = this._key; - } + if (this._key && this._key.length) { + params.key = this._key; + } - params = L.Util.extend(params, this.options.geocodingQueryParams); + params = L.Util.extend(params, this.options.geocodingQueryParams); - getJSON(this.options.serviceUrl, params, function(data) { - var results = [], - loc, - latLng, - latLngBounds; - if (data.results && data.results.length) { - for (var i = 0; i <= data.results.length - 1; i++) { - loc = data.results[i]; - latLng = L.latLng(loc.geometry.location); - latLngBounds = L.latLngBounds(L.latLng(loc.geometry.viewport.northeast), L.latLng(loc.geometry.viewport.southwest)); - results[i] = { - name: loc.formatted_address, - bbox: latLngBounds, - center: latLng, - properties: loc.address_components - }; - } - } + getJSON(this.options.serviceUrl, params, function(data) { + var results = [], + loc, + latLng, + latLngBounds; + if (data.results && data.results.length) { + for (var i = 0; i <= data.results.length - 1; i++) { + loc = data.results[i]; + latLng = L.latLng(loc.geometry.location); + latLngBounds = L.latLngBounds( + L.latLng(loc.geometry.viewport.northeast), + L.latLng(loc.geometry.viewport.southwest) + ); + results[i] = { + name: loc.formatted_address, + bbox: latLngBounds, + center: latLng, + properties: loc.address_components + }; + } + } - cb.call(context, results); - }); - }, + cb.call(context, results); + }); + }, - reverse: function(location, scale, cb, context) { - var params = { - latlng: encodeURIComponent(location.lat) + ',' + encodeURIComponent(location.lng) - }; - params = L.Util.extend(params, this.options.reverseQueryParams); - if (this._key && this._key.length) { - params.key = this._key; - } + reverse: function(location, scale, cb, context) { + var params = { + latlng: encodeURIComponent(location.lat) + ',' + encodeURIComponent(location.lng) + }; + params = L.Util.extend(params, this.options.reverseQueryParams); + if (this._key && this._key.length) { + params.key = this._key; + } - getJSON(this.options.serviceUrl, params, function(data) { - var results = [], - loc, - latLng, - latLngBounds; - if (data.results && data.results.length) { - for (var i = 0; i <= data.results.length - 1; i++) { - loc = data.results[i]; - latLng = L.latLng(loc.geometry.location); - latLngBounds = L.latLngBounds(L.latLng(loc.geometry.viewport.northeast), L.latLng(loc.geometry.viewport.southwest)); - results[i] = { - name: loc.formatted_address, - bbox: latLngBounds, - center: latLng, - properties: loc.address_components - }; - } - } + getJSON(this.options.serviceUrl, params, function(data) { + var results = [], + loc, + latLng, + latLngBounds; + if (data.results && data.results.length) { + for (var i = 0; i <= data.results.length - 1; i++) { + loc = data.results[i]; + latLng = L.latLng(loc.geometry.location); + latLngBounds = L.latLngBounds( + L.latLng(loc.geometry.viewport.northeast), + L.latLng(loc.geometry.viewport.southwest) + ); + results[i] = { + name: loc.formatted_address, + bbox: latLngBounds, + center: latLng, + properties: loc.address_components + }; + } + } - cb.call(context, results); - }); - } - }), + cb.call(context, results); + }); + } + }), - factory: function(key, options) { - return new L.Control.Geocoder.Google(key, options); - } + factory: function(key, options) { + return new L.Control.Geocoder.Google(key, options); + } }; diff --git a/src/geocoders/here.js b/src/geocoders/here.js index 7e8068c8..9af011ad 100755 --- a/src/geocoders/here.js +++ b/src/geocoders/here.js @@ -1,70 +1,73 @@ -import L from 'leaflet'; -import {getJSON} from '../util'; - -export default { - class: L.Class.extend({ - options: { - geocodeUrl: 'http://geocoder.api.here.com/6.2/geocode.json', - reverseGeocodeUrl: 'http://reverse.geocoder.api.here.com/6.2/reversegeocode.json', - app_id: '', - app_code: '', - geocodingQueryParams: {}, - reverseQueryParams: {} - }, - - initialize: function(options) { - L.setOptions(this, options); - }, - - geocode: function(query, cb, context) { - var params = { - searchtext: query, - gen: 9, - app_id: this.options.app_id, - app_code: this.options.app_code, - jsonattributes: 1 - }; - params = L.Util.extend(params, this.options.geocodingQueryParams); - this.getJSON(this.options.geocodeUrl, params, cb, context); - }, - - reverse: function(location, scale, cb, context) { - var params = { - prox: encodeURIComponent(location.lat) + ',' + encodeURIComponent(location.lng), - mode: 'retrieveAddresses', - app_id: this.options.app_id, - app_code: this.options.app_code, - gen: 9, - jsonattributes: 1 - }; - params = L.Util.extend(params, this.options.reverseQueryParams); - this.getJSON(this.options.reverseGeocodeUrl, params, cb, context); - }, - - getJSON: function(url, params, cb, context) { - getJSON(url, params, function(data) { - var results = [], - loc, - latLng, - latLngBounds; - if (data.response.view && data.response.view.length) { - for (var i = 0; i <= data.response.view[0].result.length - 1; i++) { - loc = data.response.view[0].result[i].location; - latLng = L.latLng(loc.displayPosition.latitude, loc.displayPosition.longitude); - latLngBounds = L.latLngBounds(L.latLng(loc.mapView.topLeft.latitude, loc.mapView.topLeft.longitude), L.latLng(loc.mapView.bottomRight.latitude, loc.mapView.bottomRight.longitude)); - results[i] = { - name: loc.address.label, - bbox: latLngBounds, - center: latLng - }; - } - } - cb.call(context, results); - }) - } - }), - - factory: function(options) { - return new L.Control.Geocoder.HERE(options); - } -}; +import L from 'leaflet'; +import { getJSON } from '../util'; + +export default { + class: L.Class.extend({ + options: { + geocodeUrl: 'http://geocoder.api.here.com/6.2/geocode.json', + reverseGeocodeUrl: 'http://reverse.geocoder.api.here.com/6.2/reversegeocode.json', + app_id: '', + app_code: '', + geocodingQueryParams: {}, + reverseQueryParams: {} + }, + + initialize: function(options) { + L.setOptions(this, options); + }, + + geocode: function(query, cb, context) { + var params = { + searchtext: query, + gen: 9, + app_id: this.options.app_id, + app_code: this.options.app_code, + jsonattributes: 1 + }; + params = L.Util.extend(params, this.options.geocodingQueryParams); + this.getJSON(this.options.geocodeUrl, params, cb, context); + }, + + reverse: function(location, scale, cb, context) { + var params = { + prox: encodeURIComponent(location.lat) + ',' + encodeURIComponent(location.lng), + mode: 'retrieveAddresses', + app_id: this.options.app_id, + app_code: this.options.app_code, + gen: 9, + jsonattributes: 1 + }; + params = L.Util.extend(params, this.options.reverseQueryParams); + this.getJSON(this.options.reverseGeocodeUrl, params, cb, context); + }, + + getJSON: function(url, params, cb, context) { + getJSON(url, params, function(data) { + var results = [], + loc, + latLng, + latLngBounds; + if (data.response.view && data.response.view.length) { + for (var i = 0; i <= data.response.view[0].result.length - 1; i++) { + loc = data.response.view[0].result[i].location; + latLng = L.latLng(loc.displayPosition.latitude, loc.displayPosition.longitude); + latLngBounds = L.latLngBounds( + L.latLng(loc.mapView.topLeft.latitude, loc.mapView.topLeft.longitude), + L.latLng(loc.mapView.bottomRight.latitude, loc.mapView.bottomRight.longitude) + ); + results[i] = { + name: loc.address.label, + bbox: latLngBounds, + center: latLng + }; + } + } + cb.call(context, results); + }); + } + }), + + factory: function(options) { + return new L.Control.Geocoder.HERE(options); + } +}; diff --git a/src/geocoders/mapbox.js b/src/geocoders/mapbox.js index 253f8b31..b8ef4a5b 100644 --- a/src/geocoders/mapbox.js +++ b/src/geocoders/mapbox.js @@ -1,94 +1,104 @@ import L from 'leaflet'; -import {getJSON} from '../util'; +import { getJSON } from '../util'; export default { - class: L.Class.extend({ - options: { - serviceUrl: 'https://api.tiles.mapbox.com/v4/geocode/mapbox.places-v1/', - geocodingQueryParams: {}, - reverseQueryParams: {} - }, + class: L.Class.extend({ + options: { + serviceUrl: 'https://api.tiles.mapbox.com/v4/geocode/mapbox.places-v1/', + geocodingQueryParams: {}, + reverseQueryParams: {} + }, - initialize: function(accessToken, options) { - L.setOptions(this, options); - this.options.geocodingQueryParams.access_token = accessToken; - this.options.reverseQueryParams.access_token = accessToken; - }, + initialize: function(accessToken, options) { + L.setOptions(this, options); + this.options.geocodingQueryParams.access_token = accessToken; + this.options.reverseQueryParams.access_token = accessToken; + }, - geocode: function(query, cb, context) { - var params = this.options.geocodingQueryParams; - if (typeof params.proximity !== 'undefined' - && params.proximity.hasOwnProperty('lat') - && params.proximity.hasOwnProperty('lng')) - { - params.proximity = params.proximity.lng + ',' + params.proximity.lat; - } - getJSON(this.options.serviceUrl + encodeURIComponent(query) + '.json', params, function(data) { - var results = [], - loc, - latLng, - latLngBounds; - if (data.features && data.features.length) { - for (var i = 0; i <= data.features.length - 1; i++) { - loc = data.features[i]; - latLng = L.latLng(loc.center.reverse()); - if (loc.hasOwnProperty('bbox')) - { - latLngBounds = L.latLngBounds(L.latLng(loc.bbox.slice(0, 2).reverse()), L.latLng(loc.bbox.slice(2, 4).reverse())); - } - else - { - latLngBounds = L.latLngBounds(latLng, latLng); - } - results[i] = { - name: loc.place_name, - bbox: latLngBounds, - center: latLng - }; - } - } + geocode: function(query, cb, context) { + var params = this.options.geocodingQueryParams; + if ( + typeof params.proximity !== 'undefined' && + params.proximity.hasOwnProperty('lat') && + params.proximity.hasOwnProperty('lng') + ) { + params.proximity = params.proximity.lng + ',' + params.proximity.lat; + } + getJSON(this.options.serviceUrl + encodeURIComponent(query) + '.json', params, function( + data + ) { + var results = [], + loc, + latLng, + latLngBounds; + if (data.features && data.features.length) { + for (var i = 0; i <= data.features.length - 1; i++) { + loc = data.features[i]; + latLng = L.latLng(loc.center.reverse()); + if (loc.hasOwnProperty('bbox')) { + latLngBounds = L.latLngBounds( + L.latLng(loc.bbox.slice(0, 2).reverse()), + L.latLng(loc.bbox.slice(2, 4).reverse()) + ); + } else { + latLngBounds = L.latLngBounds(latLng, latLng); + } + results[i] = { + name: loc.place_name, + bbox: latLngBounds, + center: latLng + }; + } + } - cb.call(context, results); - }); - }, + cb.call(context, results); + }); + }, - suggest: function(query, cb, context) { - return this.geocode(query, cb, context); - }, + suggest: function(query, cb, context) { + return this.geocode(query, cb, context); + }, - reverse: function(location, scale, cb, context) { - getJSON(this.options.serviceUrl + encodeURIComponent(location.lng) + ',' + encodeURIComponent(location.lat) + '.json', this.options.reverseQueryParams, function(data) { - var results = [], - loc, - latLng, - latLngBounds; - if (data.features && data.features.length) { - for (var i = 0; i <= data.features.length - 1; i++) { - loc = data.features[i]; - latLng = L.latLng(loc.center.reverse()); - if (loc.hasOwnProperty('bbox')) - { - latLngBounds = L.latLngBounds(L.latLng(loc.bbox.slice(0, 2).reverse()), L.latLng(loc.bbox.slice(2, 4).reverse())); - } - else - { - latLngBounds = L.latLngBounds(latLng, latLng); - } - results[i] = { - name: loc.place_name, - bbox: latLngBounds, - center: latLng - }; - } - } + reverse: function(location, scale, cb, context) { + getJSON( + this.options.serviceUrl + + encodeURIComponent(location.lng) + + ',' + + encodeURIComponent(location.lat) + + '.json', + this.options.reverseQueryParams, + function(data) { + var results = [], + loc, + latLng, + latLngBounds; + if (data.features && data.features.length) { + for (var i = 0; i <= data.features.length - 1; i++) { + loc = data.features[i]; + latLng = L.latLng(loc.center.reverse()); + if (loc.hasOwnProperty('bbox')) { + latLngBounds = L.latLngBounds( + L.latLng(loc.bbox.slice(0, 2).reverse()), + L.latLng(loc.bbox.slice(2, 4).reverse()) + ); + } else { + latLngBounds = L.latLngBounds(latLng, latLng); + } + results[i] = { + name: loc.place_name, + bbox: latLngBounds, + center: latLng + }; + } + } - cb.call(context, results); - }); - } - }), + cb.call(context, results); + } + ); + } + }), - factory: function(accessToken, options) { - return new L.Control.Geocoder.Mapbox(accessToken, options); - } + factory: function(accessToken, options) { + return new L.Control.Geocoder.Mapbox(accessToken, options); + } }; - diff --git a/src/geocoders/mapquest.js b/src/geocoders/mapquest.js index 097ef406..29237f36 100644 --- a/src/geocoders/mapquest.js +++ b/src/geocoders/mapquest.js @@ -1,85 +1,93 @@ import L from 'leaflet'; -import {getJSON} from '../util'; +import { getJSON } from '../util'; export default { - class: L.Class.extend({ - options: { - serviceUrl: 'https://www.mapquestapi.com/geocoding/v1' - }, + class: L.Class.extend({ + options: { + serviceUrl: 'https://www.mapquestapi.com/geocoding/v1' + }, - initialize: function(key, options) { - // MapQuest seems to provide URI encoded API keys, - // so to avoid encoding them twice, we decode them here - this._key = decodeURIComponent(key); + initialize: function(key, options) { + // MapQuest seems to provide URI encoded API keys, + // so to avoid encoding them twice, we decode them here + this._key = decodeURIComponent(key); - L.Util.setOptions(this, options); - }, + L.Util.setOptions(this, options); + }, - _formatName: function() { - var r = [], - i; - for (i = 0; i < arguments.length; i++) { - if (arguments[i]) { - r.push(arguments[i]); - } - } + _formatName: function() { + var r = [], + i; + for (i = 0; i < arguments.length; i++) { + if (arguments[i]) { + r.push(arguments[i]); + } + } - return r.join(', '); - }, + return r.join(', '); + }, - geocode: function(query, cb, context) { - getJSON(this.options.serviceUrl + '/address', { - key: this._key, - location: query, - limit: 5, - outFormat: 'json' - }, L.bind(function(data) { - var results = [], - loc, - latLng; - if (data.results && data.results[0].locations) { - for (var i = data.results[0].locations.length - 1; i >= 0; i--) { - loc = data.results[0].locations[i]; - latLng = L.latLng(loc.latLng); - results[i] = { - name: this._formatName(loc.street, loc.adminArea4, loc.adminArea3, loc.adminArea1), - bbox: L.latLngBounds(latLng, latLng), - center: latLng - }; - } - } + geocode: function(query, cb, context) { + getJSON( + this.options.serviceUrl + '/address', + { + key: this._key, + location: query, + limit: 5, + outFormat: 'json' + }, + L.bind(function(data) { + var results = [], + loc, + latLng; + if (data.results && data.results[0].locations) { + for (var i = data.results[0].locations.length - 1; i >= 0; i--) { + loc = data.results[0].locations[i]; + latLng = L.latLng(loc.latLng); + results[i] = { + name: this._formatName(loc.street, loc.adminArea4, loc.adminArea3, loc.adminArea1), + bbox: L.latLngBounds(latLng, latLng), + center: latLng + }; + } + } - cb.call(context, results); - }, this)); - }, + cb.call(context, results); + }, this) + ); + }, - reverse: function(location, scale, cb, context) { - getJSON(this.options.serviceUrl + '/reverse', { - key: this._key, - location: location.lat + ',' + location.lng, - outputFormat: 'json' - }, L.bind(function(data) { - var results = [], - loc, - latLng; - if (data.results && data.results[0].locations) { - for (var i = data.results[0].locations.length - 1; i >= 0; i--) { - loc = data.results[0].locations[i]; - latLng = L.latLng(loc.latLng); - results[i] = { - name: this._formatName(loc.street, loc.adminArea4, loc.adminArea3, loc.adminArea1), - bbox: L.latLngBounds(latLng, latLng), - center: latLng - }; - } - } + reverse: function(location, scale, cb, context) { + getJSON( + this.options.serviceUrl + '/reverse', + { + key: this._key, + location: location.lat + ',' + location.lng, + outputFormat: 'json' + }, + L.bind(function(data) { + var results = [], + loc, + latLng; + if (data.results && data.results[0].locations) { + for (var i = data.results[0].locations.length - 1; i >= 0; i--) { + loc = data.results[0].locations[i]; + latLng = L.latLng(loc.latLng); + results[i] = { + name: this._formatName(loc.street, loc.adminArea4, loc.adminArea3, loc.adminArea1), + bbox: L.latLngBounds(latLng, latLng), + center: latLng + }; + } + } - cb.call(context, results); - }, this)); - } - }), + cb.call(context, results); + }, this) + ); + } + }), - factory: function(key, options) { - return new L.Control.Geocoder.MapQuest(key, options); - } + factory: function(key, options) { + return new L.Control.Geocoder.MapQuest(key, options); + } }; diff --git a/src/geocoders/mapzen.js b/src/geocoders/mapzen.js index cb8166b3..c1c02b64 100644 --- a/src/geocoders/mapzen.js +++ b/src/geocoders/mapzen.js @@ -1,85 +1,106 @@ import L from 'leaflet'; -import {getJSON} from '../util'; +import { getJSON } from '../util'; export default { - class: L.Class.extend({ - options: { - serviceUrl: 'https://search.mapzen.com/v1', - geocodingQueryParams: {}, - reverseQueryParams: {} - }, + class: L.Class.extend({ + options: { + serviceUrl: 'https://search.mapzen.com/v1', + geocodingQueryParams: {}, + reverseQueryParams: {} + }, - initialize: function(apiKey, options) { - L.Util.setOptions(this, options); - this._apiKey = apiKey; - this._lastSuggest = 0; - }, + initialize: function(apiKey, options) { + L.Util.setOptions(this, options); + this._apiKey = apiKey; + this._lastSuggest = 0; + }, - geocode: function(query, cb, context) { - var _this = this; - getJSON(this.options.serviceUrl + "/search", L.extend({ - 'api_key': this._apiKey, - 'text': query - }, this.options.geocodingQueryParams), function(data) { - cb.call(context, _this._parseResults(data, "bbox")); - }); - }, + geocode: function(query, cb, context) { + var _this = this; + getJSON( + this.options.serviceUrl + '/search', + L.extend( + { + api_key: this._apiKey, + text: query + }, + this.options.geocodingQueryParams + ), + function(data) { + cb.call(context, _this._parseResults(data, 'bbox')); + } + ); + }, - suggest: function(query, cb, context) { - var _this = this; - getJSON(this.options.serviceUrl + "/autocomplete", L.extend({ - 'api_key': this._apiKey, - 'text': query - }, this.options.geocodingQueryParams), L.bind(function(data) { - if (data.geocoding.timestamp > this._lastSuggest) { - this._lastSuggest = data.geocoding.timestamp; - cb.call(context, _this._parseResults(data, "bbox")); - } - }, this)); - }, + suggest: function(query, cb, context) { + var _this = this; + getJSON( + this.options.serviceUrl + '/autocomplete', + L.extend( + { + api_key: this._apiKey, + text: query + }, + this.options.geocodingQueryParams + ), + L.bind(function(data) { + if (data.geocoding.timestamp > this._lastSuggest) { + this._lastSuggest = data.geocoding.timestamp; + cb.call(context, _this._parseResults(data, 'bbox')); + } + }, this) + ); + }, - reverse: function(location, scale, cb, context) { - var _this = this; - getJSON(this.options.serviceUrl + "/reverse", L.extend({ - 'api_key': this._apiKey, - 'point.lat': location.lat, - 'point.lon': location.lng - }, this.options.reverseQueryParams), function(data) { - cb.call(context, _this._parseResults(data, "bounds")); - }); - }, + reverse: function(location, scale, cb, context) { + var _this = this; + getJSON( + this.options.serviceUrl + '/reverse', + L.extend( + { + api_key: this._apiKey, + 'point.lat': location.lat, + 'point.lon': location.lng + }, + this.options.reverseQueryParams + ), + function(data) { + cb.call(context, _this._parseResults(data, 'bounds')); + } + ); + }, - _parseResults: function(data, bboxname) { - var results = []; - L.geoJson(data, { - pointToLayer: function (feature, latlng) { - return L.circleMarker(latlng); - }, - onEachFeature: function(feature, layer) { - var result = {}, - bbox, - center; + _parseResults: function(data, bboxname) { + var results = []; + L.geoJson(data, { + pointToLayer: function(feature, latlng) { + return L.circleMarker(latlng); + }, + onEachFeature: function(feature, layer) { + var result = {}, + bbox, + center; - if (layer.getBounds) { - bbox = layer.getBounds(); - center = bbox.getCenter(); - } else { - center = layer.getLatLng(); - bbox = L.latLngBounds(center, center); - } + if (layer.getBounds) { + bbox = layer.getBounds(); + center = bbox.getCenter(); + } else { + center = layer.getLatLng(); + bbox = L.latLngBounds(center, center); + } - result.name = layer.feature.properties.label; - result.center = center; - result[bboxname] = bbox; - result.properties = layer.feature.properties; - results.push(result); - } - }); - return results; - } - }), + result.name = layer.feature.properties.label; + result.center = center; + result[bboxname] = bbox; + result.properties = layer.feature.properties; + results.push(result); + } + }); + return results; + } + }), - factory: function(apiKey, options) { - return new L.Control.Geocoder.Mapzen(apiKey, options); - } + factory: function(apiKey, options) { + return new L.Control.Geocoder.Mapzen(apiKey, options); + } }; diff --git a/src/geocoders/nominatim.js b/src/geocoders/nominatim.js index a89b8612..ba5aafb0 100644 --- a/src/geocoders/nominatim.js +++ b/src/geocoders/nominatim.js @@ -1,94 +1,109 @@ import L from 'leaflet'; -import {template, getJSON} from '../util'; +import { template, getJSON } from '../util'; export default { - class: L.Class.extend({ - options: { - serviceUrl: 'https://nominatim.openstreetmap.org/', - geocodingQueryParams: {}, - reverseQueryParams: {}, - htmlTemplate: function(r) { - var a = r.address, - parts = []; - if (a.road || a.building) { - parts.push('{building} {road} {house_number}'); - } + class: L.Class.extend({ + options: { + serviceUrl: 'https://nominatim.openstreetmap.org/', + geocodingQueryParams: {}, + reverseQueryParams: {}, + htmlTemplate: function(r) { + var a = r.address, + parts = []; + if (a.road || a.building) { + parts.push('{building} {road} {house_number}'); + } - if (a.city || a.town || a.village || a.hamlet) { - parts.push('{postcode} {city} {town} {village} {hamlet}'); - } + if (a.city || a.town || a.village || a.hamlet) { + parts.push( + '{postcode} {city} {town} {village} {hamlet}' + ); + } - if (a.state || a.country) { - parts.push('{state} {country}'); - } + if (a.state || a.country) { + parts.push( + '{state} {country}' + ); + } - return template(parts.join('
'), a, true); - } - }, + return template(parts.join('
'), a, true); + } + }, - initialize: function(options) { - L.Util.setOptions(this, options); - }, + initialize: function(options) { + L.Util.setOptions(this, options); + }, - geocode: function(query, cb, context) { - getJSON(this.options.serviceUrl + 'search', L.extend({ - q: query, - limit: 5, - format: 'json', - addressdetails: 1 - }, this.options.geocodingQueryParams), - L.bind(function(data) { - var results = []; - for (var i = data.length - 1; i >= 0; i--) { - var bbox = data[i].boundingbox; - for (var j = 0; j < 4; j++) bbox[j] = parseFloat(bbox[j]); - results[i] = { - icon: data[i].icon, - name: data[i].display_name, - html: this.options.htmlTemplate ? - this.options.htmlTemplate(data[i]) - : undefined, - bbox: L.latLngBounds([bbox[0], bbox[2]], [bbox[1], bbox[3]]), - center: L.latLng(data[i].lat, data[i].lon), - properties: data[i] - }; - } - cb.call(context, results); - }, this)); - }, + geocode: function(query, cb, context) { + getJSON( + this.options.serviceUrl + 'search', + L.extend( + { + q: query, + limit: 5, + format: 'json', + addressdetails: 1 + }, + this.options.geocodingQueryParams + ), + L.bind(function(data) { + var results = []; + for (var i = data.length - 1; i >= 0; i--) { + var bbox = data[i].boundingbox; + for (var j = 0; j < 4; j++) bbox[j] = parseFloat(bbox[j]); + results[i] = { + icon: data[i].icon, + name: data[i].display_name, + html: this.options.htmlTemplate ? this.options.htmlTemplate(data[i]) : undefined, + bbox: L.latLngBounds([bbox[0], bbox[2]], [bbox[1], bbox[3]]), + center: L.latLng(data[i].lat, data[i].lon), + properties: data[i] + }; + } + cb.call(context, results); + }, this) + ); + }, - reverse: function(location, scale, cb, context) { - getJSON(this.options.serviceUrl + 'reverse', L.extend({ - lat: location.lat, - lon: location.lng, - zoom: Math.round(Math.log(scale / 256) / Math.log(2)), - addressdetails: 1, - format: 'json' - }, this.options.reverseQueryParams), L.bind(function(data) { - var result = [], - loc; + reverse: function(location, scale, cb, context) { + getJSON( + this.options.serviceUrl + 'reverse', + L.extend( + { + lat: location.lat, + lon: location.lng, + zoom: Math.round(Math.log(scale / 256) / Math.log(2)), + addressdetails: 1, + format: 'json' + }, + this.options.reverseQueryParams + ), + L.bind(function(data) { + var result = [], + loc; - if (data && data.lat && data.lon) { - loc = L.latLng(data.lat, data.lon); - result.push({ - name: data.display_name, - html: this.options.htmlTemplate ? - this.options.htmlTemplate(data) - : undefined, - center: loc, - bounds: L.latLngBounds(loc, loc), - properties: data - }); - } + if (data && data.lat && data.lon) { + loc = L.latLng(data.lat, data.lon); + result.push({ + name: data.display_name, + html: this.options.htmlTemplate ? this.options.htmlTemplate(data) : undefined, + center: loc, + bounds: L.latLngBounds(loc, loc), + properties: data + }); + } - cb.call(context, result); - }, this)); - } - }), + cb.call(context, result); + }, this) + ); + } + }), - factory: function(options) { - return new L.Control.Geocoder.Nominatim(options); - } + factory: function(options) { + return new L.Control.Geocoder.Nominatim(options); + } }; diff --git a/src/geocoders/photon.js b/src/geocoders/photon.js index ceb57bb9..d077ec0f 100644 --- a/src/geocoders/photon.js +++ b/src/geocoders/photon.js @@ -1,102 +1,103 @@ import L from 'leaflet'; -import {getJSON} from '../util'; +import { getJSON } from '../util'; export default { - class: L.Class.extend({ - options: { - serviceUrl: 'https://photon.komoot.de/api/', - reverseUrl: 'https://photon.komoot.de/reverse/', - nameProperties: [ - 'name', - 'street', - 'suburb', - 'hamlet', - 'town', - 'city', - 'state', - 'country' - ] - }, - - initialize: function(options) { - L.setOptions(this, options); - }, - - geocode: function(query, cb, context) { - var params = L.extend({ - q: query, - }, this.options.geocodingQueryParams); - - getJSON(this.options.serviceUrl, params, L.bind(function(data) { - cb.call(context, this._decodeFeatures(data)); - }, this)); - }, - - suggest: function(query, cb, context) { - return this.geocode(query, cb, context); - }, - - reverse: function(latLng, scale, cb, context) { - var params = L.extend({ - lat: latLng.lat, - lon: latLng.lng - }, this.options.geocodingQueryParams); - - getJSON(this.options.reverseUrl, params, L.bind(function(data) { - cb.call(context, this._decodeFeatures(data)); - }, this)); - }, - - _decodeFeatures: function(data) { - var results = [], - i, - f, - c, - latLng, - extent, - bbox; - - if (data && data.features) { - for (i = 0; i < data.features.length; i++) { - f = data.features[i]; - c = f.geometry.coordinates; - latLng = L.latLng(c[1], c[0]); - extent = f.properties.extent; - - if (extent) { - bbox = L.latLngBounds([extent[1], extent[0]], [extent[3], extent[2]]); - } else { - bbox = L.latLngBounds(latLng, latLng); - } - - results.push({ - name: this._deocodeFeatureName(f), - html: this.options.htmlTemplate ? - this.options.htmlTemplate(f) - : undefined, - center: latLng, - bbox: bbox, - properties: f.properties - }); - } - } - - return results; - }, - - _deocodeFeatureName: function(f) { - var j, - name; - for (j = 0; !name && j < this.options.nameProperties.length; j++) { - name = f.properties[this.options.nameProperties[j]]; - } - - return name; - } - }), - - factory: function(options) { - return new L.Control.Geocoder.Photon(options); - } + class: L.Class.extend({ + options: { + serviceUrl: 'https://photon.komoot.de/api/', + reverseUrl: 'https://photon.komoot.de/reverse/', + nameProperties: ['name', 'street', 'suburb', 'hamlet', 'town', 'city', 'state', 'country'] + }, + + initialize: function(options) { + L.setOptions(this, options); + }, + + geocode: function(query, cb, context) { + var params = L.extend( + { + q: query + }, + this.options.geocodingQueryParams + ); + + getJSON( + this.options.serviceUrl, + params, + L.bind(function(data) { + cb.call(context, this._decodeFeatures(data)); + }, this) + ); + }, + + suggest: function(query, cb, context) { + return this.geocode(query, cb, context); + }, + + reverse: function(latLng, scale, cb, context) { + var params = L.extend( + { + lat: latLng.lat, + lon: latLng.lng + }, + this.options.geocodingQueryParams + ); + + getJSON( + this.options.reverseUrl, + params, + L.bind(function(data) { + cb.call(context, this._decodeFeatures(data)); + }, this) + ); + }, + + _decodeFeatures: function(data) { + var results = [], + i, + f, + c, + latLng, + extent, + bbox; + + if (data && data.features) { + for (i = 0; i < data.features.length; i++) { + f = data.features[i]; + c = f.geometry.coordinates; + latLng = L.latLng(c[1], c[0]); + extent = f.properties.extent; + + if (extent) { + bbox = L.latLngBounds([extent[1], extent[0]], [extent[3], extent[2]]); + } else { + bbox = L.latLngBounds(latLng, latLng); + } + + results.push({ + name: this._deocodeFeatureName(f), + html: this.options.htmlTemplate ? this.options.htmlTemplate(f) : undefined, + center: latLng, + bbox: bbox, + properties: f.properties + }); + } + } + + return results; + }, + + _deocodeFeatureName: function(f) { + var j, name; + for (j = 0; !name && j < this.options.nameProperties.length; j++) { + name = f.properties[this.options.nameProperties[j]]; + } + + return name; + } + }), + + factory: function(options) { + return new L.Control.Geocoder.Photon(options); + } }; - diff --git a/src/geocoders/what3words.js b/src/geocoders/what3words.js index 675c7b47..24c9fe09 100644 --- a/src/geocoders/what3words.js +++ b/src/geocoders/what3words.js @@ -1,62 +1,74 @@ import L from 'leaflet'; -import {getJSON} from '../util'; +import { getJSON } from '../util'; export default { - class: L.Class.extend({ - options: { - serviceUrl: 'https://api.what3words.com/v2/' - }, + class: L.Class.extend({ + options: { + serviceUrl: 'https://api.what3words.com/v2/' + }, - initialize: function(accessToken) { - this._accessToken = accessToken; - }, + initialize: function(accessToken) { + this._accessToken = accessToken; + }, - geocode: function(query, cb, context) { - //get three words and make a dot based string - getJSON(this.options.serviceUrl +'forward', { - key: this._accessToken, - addr: query.split(/\s+/).join('.'), - }, function(data) { - var results = [], loc, latLng, latLngBounds; - if (data.hasOwnProperty('geometry')) { - latLng = L.latLng(data.geometry['lat'],data.geometry['lng']); - latLngBounds = L.latLngBounds(latLng, latLng); - results[0] = { - name: data.words, - bbox: latLngBounds, - center: latLng - }; - } + geocode: function(query, cb, context) { + //get three words and make a dot based string + getJSON( + this.options.serviceUrl + 'forward', + { + key: this._accessToken, + addr: query.split(/\s+/).join('.') + }, + function(data) { + var results = [], + latLng, + latLngBounds; + if (data.hasOwnProperty('geometry')) { + latLng = L.latLng(data.geometry['lat'], data.geometry['lng']); + latLngBounds = L.latLngBounds(latLng, latLng); + results[0] = { + name: data.words, + bbox: latLngBounds, + center: latLng + }; + } - cb.call(context, results); - }); - }, + cb.call(context, results); + } + ); + }, - suggest: function(query, cb, context) { - return this.geocode(query, cb, context); - }, + suggest: function(query, cb, context) { + return this.geocode(query, cb, context); + }, - reverse: function(location, scale, cb, context) { - getJSON(this.options.serviceUrl +'reverse', { - key: this._accessToken, - coords: [location.lat,location.lng].join(',') - }, function(data) { - var results = [],loc,latLng,latLngBounds; - if (data.status.status == 200) { - latLng = L.latLng(data.geometry['lat'],data.geometry['lng']); - latLngBounds = L.latLngBounds(latLng, latLng); - results[0] = { - name: data.words, - bbox: latLngBounds, - center: latLng - }; - } - cb.call(context, results); - }); - } - }), + reverse: function(location, scale, cb, context) { + getJSON( + this.options.serviceUrl + 'reverse', + { + key: this._accessToken, + coords: [location.lat, location.lng].join(',') + }, + function(data) { + var results = [], + latLng, + latLngBounds; + if (data.status.status == 200) { + latLng = L.latLng(data.geometry['lat'], data.geometry['lng']); + latLngBounds = L.latLngBounds(latLng, latLng); + results[0] = { + name: data.words, + bbox: latLngBounds, + center: latLng + }; + } + cb.call(context, results); + } + ); + } + }), - factory: function(accessToken) { - return new L.Control.Geocoder.What3Words(accessToken); - } + factory: function(accessToken) { + return new L.Control.Geocoder.What3Words(accessToken); + } }; diff --git a/src/index.js b/src/index.js index 0ef89381..5168b2bd 100755 --- a/src/index.js +++ b/src/index.js @@ -12,31 +12,31 @@ import ArcGis from './geocoders/arcgis'; import HERE from './geocoders/here'; var Geocoder = L.Util.extend(Control.class, { - Nominatim: Nominatim.class, - nominatim: Nominatim.factory, - Bing: Bing.class, - bing: Bing.factory, - MapQuest: MapQuest.class, - mapQuest: MapQuest.factory, - Mapbox: Mapbox.class, - mapbox: Mapbox.factory, - What3Words: What3Words.class, - what3words: What3Words.factory, - Google: Google.class, - google: Google.factory, - Photon: Photon.class, - photon: Photon.factory, - Mapzen: Mapzen.class, - mapzen: Mapzen.factory, - ArcGis: ArcGis.class, - arcgis: ArcGis.factory, - HERE: HERE.class, - here: HERE.factory + Nominatim: Nominatim.class, + nominatim: Nominatim.factory, + Bing: Bing.class, + bing: Bing.factory, + MapQuest: MapQuest.class, + mapQuest: MapQuest.factory, + Mapbox: Mapbox.class, + mapbox: Mapbox.factory, + What3Words: What3Words.class, + what3words: What3Words.factory, + Google: Google.class, + google: Google.factory, + Photon: Photon.class, + photon: Photon.factory, + Mapzen: Mapzen.class, + mapzen: Mapzen.factory, + ArcGis: ArcGis.class, + arcgis: ArcGis.factory, + HERE: HERE.class, + here: HERE.factory }); export default Geocoder; L.Util.extend(L.Control, { - Geocoder: Geocoder, - geocoder: Control.factory + Geocoder: Geocoder, + geocoder: Control.factory }); diff --git a/src/util.js b/src/util.js index ded9c90e..c3c46ceb 100644 --- a/src/util.js +++ b/src/util.js @@ -1,77 +1,77 @@ import L from 'leaflet'; var lastCallbackId = 0; - // Adapted from handlebars.js - // https://github.com/wycats/handlebars.js/ - var badChars = /[&<>"'`]/g; - var possible = /[&<>"'`]/; - var escape = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - '\'': ''', - '`': '`' - }; +// Adapted from handlebars.js +// https://github.com/wycats/handlebars.js/ +var badChars = /[&<>"'`]/g; +var possible = /[&<>"'`]/; +var escape = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' +}; - function escapeChar(chr) { - return escape[chr]; - } +function escapeChar(chr) { + return escape[chr]; +} - export function htmlEscape(string) { - if (string == null) { - return ''; - } else if (!string) { - return string + ''; - } +export function htmlEscape(string) { + if (string == null) { + return ''; + } else if (!string) { + return string + ''; + } - // Force a string conversion as this will be done by the append regardless and - // the regex test will do this transparently behind the scenes, causing issues if - // an object's to string has escaped characters in it. - string = '' + string; + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = '' + string; - if (!possible.test(string)) { - return string; - } - return string.replace(badChars, escapeChar); - } + if (!possible.test(string)) { + return string; + } + return string.replace(badChars, escapeChar); +} - export function jsonp(url, params, callback, context, jsonpParam) { - var callbackId = '_l_geocoder_' + (lastCallbackId++); - params[jsonpParam || 'callback'] = callbackId; - window[callbackId] = L.Util.bind(callback, context); - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = url + L.Util.getParamString(params); - script.id = callbackId; - document.getElementsByTagName('head')[0].appendChild(script); - } +export function jsonp(url, params, callback, context, jsonpParam) { + var callbackId = '_l_geocoder_' + lastCallbackId++; + params[jsonpParam || 'callback'] = callbackId; + window[callbackId] = L.Util.bind(callback, context); + var script = document.createElement('script'); + script.type = 'text/javascript'; + script.src = url + L.Util.getParamString(params); + script.id = callbackId; + document.getElementsByTagName('head')[0].appendChild(script); +} - export function getJSON(url, params, callback) { - var xmlHttp = new XMLHttpRequest(); - xmlHttp.onreadystatechange = function () { - if (xmlHttp.readyState !== 4){ - return; - } - if (xmlHttp.status !== 200 && xmlHttp.status !== 304){ - callback(''); - return; - } - callback(JSON.parse(xmlHttp.response)); - }; - xmlHttp.open('GET', url + L.Util.getParamString(params), true); - xmlHttp.setRequestHeader('Accept', 'application/json'); - xmlHttp.send(null); - } +export function getJSON(url, params, callback) { + var xmlHttp = new XMLHttpRequest(); + xmlHttp.onreadystatechange = function() { + if (xmlHttp.readyState !== 4) { + return; + } + if (xmlHttp.status !== 200 && xmlHttp.status !== 304) { + callback(''); + return; + } + callback(JSON.parse(xmlHttp.response)); + }; + xmlHttp.open('GET', url + L.Util.getParamString(params), true); + xmlHttp.setRequestHeader('Accept', 'application/json'); + xmlHttp.send(null); +} - export function template(str, data) { - return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) { - var value = data[key]; - if (value === undefined) { - value = ''; - } else if (typeof value === 'function') { - value = value(data); - } - return htmlEscape(value); - }); - } +export function template(str, data) { + return str.replace(/\{ *([\w_]+) *\}/g, function(str, key) { + var value = data[key]; + if (value === undefined) { + value = ''; + } else if (typeof value === 'function') { + value = value(data); + } + return htmlEscape(value); + }); +}