123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987 |
- /*
- * Leaflet Control Search v2.7.2 - 2017-04-08
- *
- * Copyright 2017 Stefano Cudini
- * stefano.cudini@gmail.com
- * http://labs.easyblog.it/
- *
- * Licensed under the MIT license.
- *
- * Demo:
- * http://labs.easyblog.it/maps/leaflet-search/
- *
- * Source:
- * git@github.com:stefanocudini/leaflet-search.git
- *
- */
- (function (factory) {
- if(typeof define === 'function' && define.amd) {
- //AMD
- define(['leaflet'], factory);
- } else if(typeof module !== 'undefined') {
- // Node/CommonJS
- module.exports = factory(require('leaflet'));
- } else {
- // Browser globals
- if(typeof window.L === 'undefined')
- throw 'Leaflet must be loaded first';
- factory(window.L);
- }
- })(function (L) {
- function _getPath(obj, prop) {
- var parts = prop.split('.'),
- last = parts.pop(),
- len = parts.length,
- cur = parts[0],
- i = 1;
- if(len > 0)
- while((obj = obj[cur]) && i < len)
- cur = parts[i++];
- if(obj)
- return obj[last];
- }
- function _isObject(obj) {
- return Object.prototype.toString.call(obj) === "[object Object]";
- }
- //TODO implement can do research on multiple sources layers and remote
- //TODO history: false, //show latest searches in tooltip
- //FIXME option condition problem {autoCollapse: true, markerLocation: true} not show location
- //FIXME option condition problem {autoCollapse: false }
- //
- //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
- // run one of callbacks search(sourceData,jsonpUrl or options.layer) and run this.showTooltip
- //
- //TODO change structure of _recordsCache
- // like this: _recordsCache = {"text-key1": {loc:[lat,lng], ..other attributes.. }, {"text-key2": {loc:[lat,lng]}...}, ...}
- // in this mode every record can have a free structure of attributes, only 'loc' is required
- //TODO important optimization!!! always append data in this._recordsCache
- // now _recordsCache content is emptied and replaced with new data founded
- // always appending data on _recordsCache give the possibility of caching ajax, jsonp and layersearch!
- //
- //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
- // run one of callbacks search(sourceData,jsonpUrl or options.layer) and run this.showTooltip
- //
- //TODO change structure of _recordsCache
- // like this: _recordsCache = {"text-key1": {loc:[lat,lng], ..other attributes.. }, {"text-key2": {loc:[lat,lng]}...}, ...}
- // in this way every record can have a free structure of attributes, only 'loc' is required
- L.Control.Search = L.Control.extend({
- includes: L.Mixin.Events,
- //
- // Name Data passed Description
- //
- //Managed Events:
- // search:locationfound {latlng, title, layer} fired after moved and show markerLocation
- // search:expanded {} fired after control was expanded
- // search:collapsed {} fired after control was collapsed
- //
- //Public methods:
- // setLayer() L.LayerGroup() set layer search at runtime
- // showAlert() 'Text message' show alert message
- // searchText() 'Text searched' search text by external code
- //
- options: {
- url: '', //url for search by ajax request, ex: "search.php?q={s}". Can be function that returns string for dynamic parameter setting
- layer: null, //layer where search markers(is a L.LayerGroup)
- sourceData: null, //function that fill _recordsCache, passed searching text by first param and callback in second
- //TODO implements uniq option 'sourceData' that recognizes source type: url,array,callback or layer
- jsonpParam: null, //jsonp param name for search by jsonp service, ex: "callback"
- propertyLoc: 'loc', //field for remapping location, using array: ['latname','lonname'] for select double fields(ex. ['lat','lon'] ) support dotted format: 'prop.subprop.title'
- propertyName: 'title', //property in marker.options(or feature.properties for vector layer) trough filter elements in layer,
- formatData: null, //callback for reformat all data from source to indexed data object
- filterData: null, //callback for filtering data from text searched, params: textSearch, allRecords
- moveToLocation: null, //callback run on location found, params: latlng, title, map
- buildTip: null, //function that return row tip html node(or html string), receive text tooltip in first param
- container: '', //container id to insert Search Control
- zoom: null, //default zoom level for move to location
- minLength: 1, //minimal text length for autocomplete
- initial: true, //search elements only by initial text
- casesensitive: false, //search elements in case sensitive text
- autoType: true, //complete input with first suggested result and select this filled-in text.
- delayType: 400, //delay while typing for show tooltip
- tooltipLimit: -1, //limit max results to show in tooltip. -1 for no limit, 0 for no results
- tipAutoSubmit: true, //auto map panTo when click on tooltip
- firstTipSubmit: false, //auto select first result con enter click
- autoResize: true, //autoresize on input change
- collapsed: true, //collapse search control at startup
- autoCollapse: false, //collapse search control after submit(on button or on tips if enabled tipAutoSubmit)
- autoCollapseTime: 1200, //delay for autoclosing alert and collapse after blur
- textErr: 'Location not found', //error message
- textCancel: 'Cancel', //title in cancel button
- textPlaceholder: 'Search...', //placeholder value
- position: 'topleft',
- hideMarkerOnCollapse: false, //remove circle and marker on search control collapsed
- marker: { //custom L.Marker or false for hide
- icon: false, //custom L.Icon for maker location or false for hide
- animate: true, //animate a circle over location found
- circle: { //draw a circle in location found
- radius: 10,
- weight: 3,
- color: '#e03',
- stroke: true,
- fill: false
- }
- }
- },
- initialize: function(options) {
- L.Util.setOptions(this, options || {});
- this._inputMinSize = this.options.textPlaceholder ? this.options.textPlaceholder.length : 10;
- this._layer = this.options.layer || new L.LayerGroup();
- this._filterData = this.options.filterData || this._defaultFilterData;
- this._formatData = this.options.formatData || this._defaultFormatData;
- this._moveToLocation = this.options.moveToLocation || this._defaultMoveToLocation;
- this._autoTypeTmp = this.options.autoType; //useful for disable autoType temporarily in delete/backspace keydown
- this._countertips = 0; //number of tips items
- this._recordsCache = {}; //key,value table! that store locations! format: key,latlng
- this._curReq = null;
- },
- onAdd: function (map) {
- this._map = map;
- this._container = L.DomUtil.create('div', 'leaflet-control-search');
- this._input = this._createInput(this.options.textPlaceholder, 'search-input');
- this._tooltip = this._createTooltip('search-tooltip');
- this._cancel = this._createCancel(this.options.textCancel, 'search-cancel');
- this._button = this._createButton(this.options.textPlaceholder, 'search-button');
- this._alert = this._createAlert('search-alert');
- if(this.options.collapsed===false)
- this.expand(this.options.collapsed);
- if(this.options.marker) {
-
- if(this.options.marker instanceof L.Marker || this.options.marker instanceof L.CircleMarker)
- this._markerSearch = this.options.marker;
- else if(_isObject(this.options.marker))
- this._markerSearch = new L.Control.Search.Marker([0,0], this.options.marker);
- this._markerSearch._isMarkerSearch = true;
- }
- this.setLayer( this._layer );
- map.on({
- // 'layeradd': this._onLayerAddRemove,
- // 'layerremove': this._onLayerAddRemove
- 'resize': this._handleAutoresize
- }, this);
- return this._container;
- },
- addTo: function (map) {
- if(this.options.container) {
- this._container = this.onAdd(map);
- this._wrapper = L.DomUtil.get(this.options.container);
- this._wrapper.style.position = 'relative';
- this._wrapper.appendChild(this._container);
- }
- else
- L.Control.prototype.addTo.call(this, map);
- return this;
- },
- onRemove: function(map) {
- this._recordsCache = {};
- // map.off({
- // 'layeradd': this._onLayerAddRemove,
- // 'layerremove': this._onLayerAddRemove
- // }, this);
- },
- // _onLayerAddRemove: function(e) {
- // //without this, run setLayer also for each Markers!! to optimize!
- // if(e.layer instanceof L.LayerGroup)
- // if( L.stamp(e.layer) != L.stamp(this._layer) )
- // this.setLayer(e.layer);
- // },
- setLayer: function(layer) { //set search layer at runtime
- //this.options.layer = layer; //setting this, run only this._recordsFromLayer()
- this._layer = layer;
- this._layer.addTo(this._map);
- return this;
- },
-
- showAlert: function(text) {
- text = text || this.options.textErr;
- this._alert.style.display = 'block';
- this._alert.innerHTML = text;
- clearTimeout(this.timerAlert);
- var that = this;
- this.timerAlert = setTimeout(function() {
- that.hideAlert();
- },this.options.autoCollapseTime);
- return this;
- },
-
- hideAlert: function() {
- this._alert.style.display = 'none';
- return this;
- },
-
- cancel: function() {
- this._input.value = '';
- this._handleKeypress({ keyCode: 8 });//simulate backspace keypress
- this._input.size = this._inputMinSize;
- this._input.focus();
- this._cancel.style.display = 'none';
- this._hideTooltip();
- return this;
- },
-
- expand: function(toggle) {
- toggle = typeof toggle === 'boolean' ? toggle : true;
- this._input.style.display = 'block';
- L.DomUtil.addClass(this._container, 'search-exp');
- if ( toggle !== false ) {
- this._input.focus();
- this._map.on('dragstart click', this.collapse, this);
- }
- this.fire('search:expanded');
- return this;
- },
- collapse: function() {
- this._hideTooltip();
- this.cancel();
- this._alert.style.display = 'none';
- this._input.blur();
- if(this.options.collapsed)
- {
- this._input.style.display = 'none';
- this._cancel.style.display = 'none';
- L.DomUtil.removeClass(this._container, 'search-exp');
- if (this.options.hideMarkerOnCollapse) {
- this._map.removeLayer(this._markerSearch);
- }
- this._map.off('dragstart click', this.collapse, this);
- }
- this.fire('search:collapsed');
- return this;
- },
-
- collapseDelayed: function() { //collapse after delay, used on_input blur
- if (!this.options.autoCollapse) return this;
- var that = this;
- clearTimeout(this.timerCollapse);
- this.timerCollapse = setTimeout(function() {
- that.collapse();
- }, this.options.autoCollapseTime);
- return this;
- },
- collapseDelayedStop: function() {
- clearTimeout(this.timerCollapse);
- return this;
- },
- ////start DOM creations
- _createAlert: function(className) {
- var alert = L.DomUtil.create('div', className, this._container);
- alert.style.display = 'none';
- L.DomEvent
- .on(alert, 'click', L.DomEvent.stop, this)
- .on(alert, 'click', this.hideAlert, this);
- return alert;
- },
- _createInput: function (text, className) {
- var label = L.DomUtil.create('label', className, this._container);
- var input = L.DomUtil.create('input', className, this._container);
- input.type = 'text';
- input.size = this._inputMinSize;
- input.value = '';
- input.autocomplete = 'off';
- input.autocorrect = 'off';
- input.autocapitalize = 'off';
- input.placeholder = text;
- input.style.display = 'none';
- input.role = 'search';
- input.id = input.role + input.type + input.size;
-
- label.htmlFor = input.id;
- label.style.display = 'none';
- label.value = text;
- L.DomEvent
- .disableClickPropagation(input)
- .on(input, 'keydown', this._handleKeypress, this)
- .on(input, 'blur', this.collapseDelayed, this)
- .on(input, 'focus', this.collapseDelayedStop, this);
-
- return input;
- },
- _createCancel: function (title, className) {
- var cancel = L.DomUtil.create('a', className, this._container);
- cancel.href = '#';
- cancel.title = title;
- cancel.style.display = 'none';
- cancel.innerHTML = "<span>⊗</span>";//imageless(see css)
- L.DomEvent
- .on(cancel, 'click', L.DomEvent.stop, this)
- .on(cancel, 'click', this.cancel, this);
- return cancel;
- },
-
- _createButton: function (title, className) {
- var button = L.DomUtil.create('a', className, this._container);
- button.href = '#';
- button.title = title;
- L.DomEvent
- .on(button, 'click', L.DomEvent.stop, this)
- .on(button, 'click', this._handleSubmit, this)
- .on(button, 'focus', this.collapseDelayedStop, this)
- .on(button, 'blur', this.collapseDelayed, this);
- return button;
- },
- _createTooltip: function(className) {
- var tool = L.DomUtil.create('ul', className, this._container);
- tool.style.display = 'none';
- var that = this;
- L.DomEvent
- .disableClickPropagation(tool)
- .on(tool, 'blur', this.collapseDelayed, this)
- .on(tool, 'mousewheel', function(e) {
- that.collapseDelayedStop();
- L.DomEvent.stopPropagation(e);//disable zoom map
- }, this)
- .on(tool, 'mouseover', function(e) {
- that.collapseDelayedStop();
- }, this);
- return tool;
- },
- _createTip: function(text, val) {//val is object in recordCache, usually is Latlng
- var tip;
-
- if(this.options.buildTip)
- {
- tip = this.options.buildTip.call(this, text, val); //custom tip node or html string
- if(typeof tip === 'string')
- {
- var tmpNode = L.DomUtil.create('div');
- tmpNode.innerHTML = tip;
- tip = tmpNode.firstChild;
- }
- }
- else
- {
- tip = L.DomUtil.create('li', '');
- tip.innerHTML = text;
- }
-
- L.DomUtil.addClass(tip, 'search-tip');
- tip._text = text; //value replaced in this._input and used by _autoType
- if(this.options.tipAutoSubmit)
- L.DomEvent
- .disableClickPropagation(tip)
- .on(tip, 'click', L.DomEvent.stop, this)
- .on(tip, 'click', function(e) {
- this._input.value = text;
- this._handleAutoresize();
- this._input.focus();
- this._hideTooltip();
- this._handleSubmit();
- }, this);
- return tip;
- },
- //////end DOM creations
- _getUrl: function(text) {
- return (typeof this.options.url === 'function') ? this.options.url(text) : this.options.url;
- },
- _defaultFilterData: function(text, records) {
-
- var I, icase, regSearch, frecords = {};
- text = text.replace(/[.*+?^${}()|[\]\\]/g, ''); //sanitize remove all special characters
- if(text==='')
- return [];
- I = this.options.initial ? '^' : ''; //search only initial text
- icase = !this.options.casesensitive ? 'i' : undefined;
- regSearch = new RegExp(I + text, icase);
- //TODO use .filter or .map
- for(var key in records) {
- if( regSearch.test(key) )
- frecords[key]= records[key];
- }
-
- return frecords;
- },
- showTooltip: function(records) {
-
- this._countertips = 0;
- this._tooltip.innerHTML = '';
- this._tooltip.currentSelection = -1; //inizialized for _handleArrowSelect()
- if(this.options.tooltipLimit)
- {
- for(var key in records)//fill tooltip
- {
- if(this._countertips === this.options.tooltipLimit)
- break;
-
- this._countertips++;
- this._tooltip.appendChild( this._createTip(key, records[key]) );
- }
- }
-
- if(this._countertips > 0)
- {
- this._tooltip.style.display = 'block';
-
- if(this._autoTypeTmp)
- this._autoType();
- this._autoTypeTmp = this.options.autoType;//reset default value
- }
- else
- this._hideTooltip();
- this._tooltip.scrollTop = 0;
- return this._countertips;
- },
- _hideTooltip: function() {
- this._tooltip.style.display = 'none';
- this._tooltip.innerHTML = '';
- return 0;
- },
- _defaultFormatData: function(json) { //default callback for format data to indexed data
- var propName = this.options.propertyName,
- propLoc = this.options.propertyLoc,
- i, jsonret = {};
- if( L.Util.isArray(propLoc) )
- for(i in json)
- jsonret[ _getPath(json[i],propName) ]= L.latLng( json[i][ propLoc[0] ], json[i][ propLoc[1] ] );
- else
- for(i in json)
- jsonret[ _getPath(json[i],propName) ]= L.latLng( _getPath(json[i],propLoc) );
- //TODO throw new Error("propertyName '"+propName+"' not found in JSON data");
- return jsonret;
- },
- _recordsFromJsonp: function(text, callAfter) { //extract searched records from remote jsonp service
- L.Control.Search.callJsonp = callAfter;
- var script = L.DomUtil.create('script','leaflet-search-jsonp', document.getElementsByTagName('body')[0] ),
- url = L.Util.template(this._getUrl(text)+'&'+this.options.jsonpParam+'=L.Control.Search.callJsonp', {s: text}); //parsing url
- //rnd = '&_='+Math.floor(Math.random()*10000);
- //TODO add rnd param or randomize callback name! in recordsFromJsonp
- script.type = 'text/javascript';
- script.src = url;
- return { abort: function() { script.parentNode.removeChild(script); } };
- },
- _recordsFromAjax: function(text, callAfter) { //Ajax request
- if (window.XMLHttpRequest === undefined) {
- window.XMLHttpRequest = function() {
- try { return new ActiveXObject("Microsoft.XMLHTTP.6.0"); }
- catch (e1) {
- try { return new ActiveXObject("Microsoft.XMLHTTP.3.0"); }
- catch (e2) { throw new Error("XMLHttpRequest is not supported"); }
- }
- };
- }
- var IE8or9 = ( L.Browser.ie && !window.atob && document.querySelector ),
- request = IE8or9 ? new XDomainRequest() : new XMLHttpRequest(),
- url = L.Util.template(this._getUrl(text), {s: text});
- //rnd = '&_='+Math.floor(Math.random()*10000);
- //TODO add rnd param or randomize callback name! in recordsFromAjax
-
- request.open("GET", url);
- var that = this;
- request.onload = function() {
- callAfter( JSON.parse(request.responseText) );
- };
- request.onreadystatechange = function() {
- if(request.readyState === 4 && request.status === 200) {
- this.onload();
- }
- };
- request.send();
- return request;
- },
-
- _recordsFromLayer: function() { //return table: key,value from layer
- var that = this,
- retRecords = {},
- propName = this.options.propertyName,
- loc;
-
- this._layer.eachLayer(function(layer) {
- if(layer.hasOwnProperty('_isMarkerSearch')) return;
- if(layer instanceof L.Marker || layer instanceof L.CircleMarker)
- {
- try {
- if(_getPath(layer.options,propName))
- {
- loc = layer.getLatLng();
- loc.layer = layer;
- retRecords[ _getPath(layer.options,propName) ] = loc;
-
- }
- else if(_getPath(layer.feature.properties,propName)){
-
- loc = layer.getLatLng();
- loc.layer = layer;
- retRecords[ _getPath(layer.feature.properties,propName) ] = loc;
-
- }
- else
- throw new Error("propertyName '"+propName+"' not found in marker");
-
- }
- catch(err){
- if (console) { }
- }
- }
- else if(layer.hasOwnProperty('feature'))//GeoJSON
- {
- try {
- if(layer.feature.properties.hasOwnProperty(propName))
- {
- loc = layer.getBounds().getCenter();
- loc.layer = layer;
- retRecords[ layer.feature.properties[propName] ] = loc;
- }
- else
- throw new Error("propertyName '"+propName+"' not found in feature");
- }
- catch(err){
- if (console) { }
- }
- }
- else if(layer instanceof L.LayerGroup)
- {
- //TODO: Optimize
- layer.eachLayer(function(m) {
- loc = m.getLatLng();
- loc.layer = m;
- retRecords[ m.feature.properties[propName] ] = loc;
- });
- }
-
- },this);
-
- return retRecords;
- },
- _autoType: function() {
-
- //TODO implements autype without selection(useful for mobile device)
-
- var start = this._input.value.length,
- firstRecord = this._tooltip.firstChild ? this._tooltip.firstChild._text : '',
- end = firstRecord.length;
- if (firstRecord.indexOf(this._input.value) === 0) { // If prefix match
- this._input.value = firstRecord;
- this._handleAutoresize();
- if (this._input.createTextRange) {
- var selRange = this._input.createTextRange();
- selRange.collapse(true);
- selRange.moveStart('character', start);
- selRange.moveEnd('character', end);
- selRange.select();
- }
- else if(this._input.setSelectionRange) {
- this._input.setSelectionRange(start, end);
- }
- else if(this._input.selectionStart) {
- this._input.selectionStart = start;
- this._input.selectionEnd = end;
- }
- }
- },
- _hideAutoType: function() { // deselect text:
- var sel;
- if ((sel = this._input.selection) && sel.empty) {
- sel.empty();
- }
- else if (this._input.createTextRange) {
- sel = this._input.createTextRange();
- sel.collapse(true);
- var end = this._input.value.length;
- sel.moveStart('character', end);
- sel.moveEnd('character', end);
- sel.select();
- }
- else {
- if (this._input.getSelection) {
- this._input.getSelection().removeAllRanges();
- }
- this._input.selectionStart = this._input.selectionEnd;
- }
- },
-
- _handleKeypress: function (e) { //run _input keyup event
- switch(e.keyCode)
- {
- case 27://Esc
- this.collapse();
- break;
- case 13://Enter
- if(this._countertips == 1 || (this.options.firstTipSubmit && this._countertips > 0))
- this._handleArrowSelect(1);
- this._handleSubmit(); //do search
- break;
- case 38://Up
- this._handleArrowSelect(-1);
- break;
- case 40://Down
- this._handleArrowSelect(1);
- break;
- case 8://Backspace
- case 45://Insert
- case 46://Delete
- this._autoTypeTmp = false;//disable temporarily autoType
- break;
- case 37://Left
- case 39://Right
- case 16://Shift
- case 17://Ctrl
- case 35://End
- case 36://Home
- break;
- default://All keys
- if(this._input.value.length)
- this._cancel.style.display = 'block';
- else
- this._cancel.style.display = 'none';
- if(this._input.value.length >= this.options.minLength)
- {
- var that = this;
- clearTimeout(this.timerKeypress); //cancel last search request while type in
- this.timerKeypress = setTimeout(function() { //delay before request, for limit jsonp/ajax request
- that._fillRecordsCache();
-
- }, this.options.delayType);
- }
- else
- this._hideTooltip();
- }
- this._handleAutoresize();
- },
- searchText: function(text) {
- var code = text.charCodeAt(text.length);
- this._input.value = text;
- this._input.style.display = 'block';
- L.DomUtil.addClass(this._container, 'search-exp');
- this._autoTypeTmp = false;
- this._handleKeypress({keyCode: code});
- },
-
- _fillRecordsCache: function() {
- var inputText = this._input.value,
- that = this, records;
- if(this._curReq && this._curReq.abort)
- this._curReq.abort();
- //abort previous requests
- L.DomUtil.addClass(this._container, 'search-load');
- if(this.options.layer)
- {
- //TODO _recordsFromLayer must return array of objects, formatted from _formatData
- this._recordsCache = this._recordsFromLayer();
-
- records = this._filterData( this._input.value, this._recordsCache );
- this.showTooltip( records );
- L.DomUtil.removeClass(this._container, 'search-load');
- }
- else
- {
- if(this.options.sourceData)
- this._retrieveData = this.options.sourceData;
- else if(this.options.url) //jsonp or ajax
- this._retrieveData = this.options.jsonpParam ? this._recordsFromJsonp : this._recordsFromAjax;
- this._curReq = this._retrieveData.call(this, inputText, function(data) {
-
- that._recordsCache = that._formatData(data);
- //TODO refact!
- if(that.options.sourceData)
- records = that._filterData( that._input.value, that._recordsCache );
- else
- records = that._recordsCache;
- that.showTooltip( records );
-
- L.DomUtil.removeClass(that._container, 'search-load');
- });
- }
- },
-
- _handleAutoresize: function() { //autoresize this._input
- //TODO refact _handleAutoresize now is not accurate
- if (this._input.style.maxWidth != this._map._container.offsetWidth) //If maxWidth isn't the same as when first set, reset to current Map width
- this._input.style.maxWidth = L.DomUtil.getStyle(this._map._container, 'width');
- if(this.options.autoResize && (this._container.offsetWidth + 45 < this._map._container.offsetWidth))
- this._input.size = this._input.value.length<this._inputMinSize ? this._inputMinSize : this._input.value.length;
- },
- _handleArrowSelect: function(velocity) {
-
- var searchTips = this._tooltip.hasChildNodes() ? this._tooltip.childNodes : [];
-
- for (i=0; i<searchTips.length; i++)
- L.DomUtil.removeClass(searchTips[i], 'search-tip-select');
-
- if ((velocity == 1 ) && (this._tooltip.currentSelection >= (searchTips.length - 1))) {// If at end of list.
- L.DomUtil.addClass(searchTips[this._tooltip.currentSelection], 'search-tip-select');
- }
- else if ((velocity == -1 ) && (this._tooltip.currentSelection <= 0)) { // Going back up to the search box.
- this._tooltip.currentSelection = -1;
- }
- else if (this._tooltip.style.display != 'none') {
- this._tooltip.currentSelection += velocity;
-
- L.DomUtil.addClass(searchTips[this._tooltip.currentSelection], 'search-tip-select');
-
- this._input.value = searchTips[this._tooltip.currentSelection]._text;
- // scroll:
- var tipOffsetTop = searchTips[this._tooltip.currentSelection].offsetTop;
-
- if (tipOffsetTop + searchTips[this._tooltip.currentSelection].clientHeight >= this._tooltip.scrollTop + this._tooltip.clientHeight) {
- this._tooltip.scrollTop = tipOffsetTop - this._tooltip.clientHeight + searchTips[this._tooltip.currentSelection].clientHeight;
- }
- else if (tipOffsetTop <= this._tooltip.scrollTop) {
- this._tooltip.scrollTop = tipOffsetTop;
- }
- }
- },
- _handleSubmit: function() { //button and tooltip click and enter submit
- this._hideAutoType();
-
- this.hideAlert();
- this._hideTooltip();
- if(this._input.style.display == 'none') //on first click show _input only
- this.expand();
- else
- {
- if(this._input.value === '') //hide _input only
- this.collapse();
- else
- {
- var loc = this._getLocation(this._input.value);
-
- if(loc===false)
- this.showAlert();
- else
- {
- this.showLocation(loc, this._input.value);
- this.fire('search:locationfound', {
- latlng: loc,
- text: this._input.value,
- layer: loc.layer ? loc.layer : null
- });
- }
- }
- }
- },
- _getLocation: function(key) { //extract latlng from _recordsCache
- if( this._recordsCache.hasOwnProperty(key) )
- return this._recordsCache[key];//then after use .loc attribute
- else
- return false;
- },
- _defaultMoveToLocation: function(latlng, title, map) {
- if(this.options.zoom)
- this._map.setView(latlng, this.options.zoom);
- else
- this._map.panTo(latlng);
- },
- showLocation: function(latlng, title) { //set location on map from _recordsCache
- var self = this;
- self._map.once('moveend zoomend', function(e) {
- if(self._markerSearch) {
- self._markerSearch.addTo(self._map).setLatLng(latlng);
- }
-
- });
- self._moveToLocation(latlng, title, self._map);
- //FIXME autoCollapse option hide self._markerSearch before that visualized!!
- if(self.options.autoCollapse)
- self.collapse();
- return self;
- }
- });
- L.Control.Search.Marker = L.Marker.extend({
- includes: L.Mixin.Events,
-
- options: {
- icon: new L.Icon.Default(),
- animate: true,
- circle: {
- radius: 10,
- weight: 3,
- color: '#e03',
- stroke: true,
- fill: false
- }
- },
-
- initialize: function (latlng, options) {
- L.setOptions(this, options);
- if(options.icon === true)
- options.icon = new L.Icon.Default();
- L.Marker.prototype.initialize.call(this, latlng, options);
-
- if( _isObject(this.options.circle) )
- this._circleLoc = new L.CircleMarker(latlng, this.options.circle);
- },
- onAdd: function (map) {
- L.Marker.prototype.onAdd.call(this, map);
- if(this._circleLoc) {
- map.addLayer(this._circleLoc);
- if(this.options.animate)
- this.animate();
- }
- },
- onRemove: function (map) {
- L.Marker.prototype.onRemove.call(this, map);
- if(this._circleLoc)
- map.removeLayer(this._circleLoc);
- },
-
- setLatLng: function (latlng) {
- L.Marker.prototype.setLatLng.call(this, latlng);
- if(this._circleLoc)
- this._circleLoc.setLatLng(latlng);
- return this;
- },
-
- _initIcon: function () {
- if(this.options.icon)
- L.Marker.prototype._initIcon.call(this);
- },
- _removeIcon: function () {
- if(this.options.icon)
- L.Marker.prototype._removeIcon.call(this);
- },
- animate: function() {
- //TODO refact animate() more smooth! like this: http://goo.gl/DDlRs
- if(this._circleLoc)
- {
- var circle = this._circleLoc,
- tInt = 200, //time interval
- ss = 5, //frames
- mr = parseInt(circle._radius/ss),
- oldrad = this.options.circle.radius,
- newrad = circle._radius * 2,
- acc = 0;
- circle._timerAnimLoc = setInterval(function() {
- acc += 0.5;
- mr += acc; //adding acceleration
- newrad -= mr;
-
- circle.setRadius(newrad);
- if(newrad<oldrad)
- {
- clearInterval(circle._timerAnimLoc);
- circle.setRadius(oldrad);//reset radius
- //if(typeof afterAnimCall == 'function')
- //afterAnimCall();
- //TODO use create event 'animateEnd' in L.Control.Search.Marker
- }
- }, tInt);
- }
-
- return this;
- }
- });
- L.Map.addInitHook(function () {
- if (this.options.searchControl) {
- this.searchControl = L.control.search(this.options.searchControl);
- this.addControl(this.searchControl);
- }
- });
- L.control.search = function (options) {
- return new L.Control.Search(options);
- };
- return L.Control.Search;
- });
|