UNPKG

leaflet-routing-machine

Version:
212 lines (182 loc) 6.04 kB
(function() { 'use strict'; var L = require('leaflet'); module.exports = L.Class.extend({ options: { timeout: 500, blurTimeout: 100, noResultsMessage: 'No results found.' }, initialize: function(elem, callback, context, options) { L.setOptions(this, options); this._elem = elem; this._resultFn = options.resultFn ? L.Util.bind(options.resultFn, options.resultContext) : null; this._autocomplete = options.autocompleteFn ? L.Util.bind(options.autocompleteFn, options.autocompleteContext) : null; this._selectFn = L.Util.bind(callback, context); this._container = L.DomUtil.create('div', 'leaflet-routing-geocoder-result'); this._resultTable = L.DomUtil.create('table', '', this._container); // TODO: looks a bit like a kludge to register same for input and keypress - // browsers supporting both will get duplicate events; just registering // input will not catch enter, though. L.DomEvent.addListener(this._elem, 'input', this._keyPressed, this); L.DomEvent.addListener(this._elem, 'keypress', this._keyPressed, this); L.DomEvent.addListener(this._elem, 'keydown', this._keyDown, this); L.DomEvent.addListener(this._elem, 'blur', function() { if (this._isOpen) { this.close(); } }, this); }, close: function() { L.DomUtil.removeClass(this._container, 'leaflet-routing-geocoder-result-open'); this._isOpen = false; }, _open: function() { var rect = this._elem.getBoundingClientRect(); if (!this._container.parentElement) { // See notes section under https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollX // This abomination is required to support all flavors of IE var scrollX = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft; var scrollY = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop; this._container.style.left = (rect.left + scrollX) + 'px'; this._container.style.top = (rect.bottom + scrollY) + 'px'; this._container.style.width = (rect.right - rect.left) + 'px'; document.body.appendChild(this._container); } L.DomUtil.addClass(this._container, 'leaflet-routing-geocoder-result-open'); this._isOpen = true; }, _setResults: function(results) { var i, tr, td, text; delete this._selection; this._results = results; while (this._resultTable.firstChild) { this._resultTable.removeChild(this._resultTable.firstChild); } for (i = 0; i < results.length; i++) { tr = L.DomUtil.create('tr', '', this._resultTable); tr.setAttribute('data-result-index', i); td = L.DomUtil.create('td', '', tr); text = document.createTextNode(results[i].name); td.appendChild(text); // mousedown + click because: // http://stackoverflow.com/questions/10652852/jquery-fire-click-before-blur-event L.DomEvent.addListener(td, 'mousedown', L.DomEvent.preventDefault); L.DomEvent.addListener(td, 'click', this._createClickListener(results[i])); } if (!i) { tr = L.DomUtil.create('tr', '', this._resultTable); td = L.DomUtil.create('td', 'leaflet-routing-geocoder-no-results', tr); td.innerHTML = this.options.noResultsMessage; } this._open(); if (results.length > 0) { // Select the first entry this._select(1); } }, _createClickListener: function(r) { var resultSelected = this._resultSelected(r); return L.bind(function() { this._elem.blur(); resultSelected(); }, this); }, _resultSelected: function(r) { return L.bind(function() { this.close(); this._elem.value = r.name; this._lastCompletedText = r.name; this._selectFn(r); }, this); }, _keyPressed: function(e) { var index; if (this._isOpen && e.keyCode === 13 && this._selection) { index = parseInt(this._selection.getAttribute('data-result-index'), 10); this._resultSelected(this._results[index])(); L.DomEvent.preventDefault(e); return; } if (e.keyCode === 13) { L.DomEvent.preventDefault(e); this._complete(this._resultFn, true); return; } if (this._autocomplete && document.activeElement === this._elem) { if (this._timer) { clearTimeout(this._timer); } this._timer = setTimeout(L.Util.bind(function() { this._complete(this._autocomplete); }, this), this.options.timeout); return; } this._unselect(); }, _select: function(dir) { var sel = this._selection; if (sel) { L.DomUtil.removeClass(sel.firstChild, 'leaflet-routing-geocoder-selected'); sel = sel[dir > 0 ? 'nextSibling' : 'previousSibling']; } if (!sel) { sel = this._resultTable[dir > 0 ? 'firstChild' : 'lastChild']; } if (sel) { L.DomUtil.addClass(sel.firstChild, 'leaflet-routing-geocoder-selected'); this._selection = sel; } }, _unselect: function() { if (this._selection) { L.DomUtil.removeClass(this._selection.firstChild, 'leaflet-routing-geocoder-selected'); } delete this._selection; }, _keyDown: function(e) { if (this._isOpen) { switch (e.keyCode) { // Escape case 27: this.close(); L.DomEvent.preventDefault(e); return; // Up case 38: this._select(-1); L.DomEvent.preventDefault(e); return; // Down case 40: this._select(1); L.DomEvent.preventDefault(e); return; } } }, _complete: function(completeFn, trySelect) { var v = this._elem.value; function completeResults(results) { this._lastCompletedText = v; if (trySelect && results.length === 1) { this._resultSelected(results[0])(); } else { this._setResults(results); } } if (!v) { return; } if (v !== this._lastCompletedText) { completeFn(v, completeResults, this); } else if (trySelect) { completeResults.call(this, this._results); } } }); })();