update leaflet-search

This commit is contained in:
Norbert Renner 2014-05-14 15:31:54 +02:00
parent cec17a1c26
commit 09932b4b96
14 changed files with 284 additions and 124 deletions

View file

@ -1,6 +1,6 @@
{
"name": "leaflet-search",
"version": "1.4.7",
"version": "1.5.1",
"main": "leaflet-search.js",
"ignore": [
"**/.*",
@ -10,11 +10,11 @@
"examples"
],
"homepage": "https://github.com/stefanocudini/leaflet-search",
"_release": "1.4.7",
"_release": "1.5.1",
"_resolution": {
"type": "version",
"tag": "v1.4.7",
"commit": "411f216e1f407da9ef61047832b227c19ed47fab"
"tag": "v1.5.1",
"commit": "75ab103b838a966692cfb6cb3dc78c3b0f306eee"
},
"_source": "git://github.com/stefanocudini/leaflet-search.git",
"_target": "*",

View file

@ -1,16 +1,17 @@
Leaflet.Control.Search
============
#What
A leaflet control that search markers/features location by cutstom property.
With ajax/jsonp autocompletion and json fields re-mapping
A leaflet control that search markers/features location by custom property.<br />
With ajax/jsonp autocompletion and JSON fields filter/remap
Tested in Leaflet 0.6.4
Copyright 2014 [Stefano Cudini](http://labs.easyblog.it/stefano-cudini/)
Tested in Leaflet 0.7.2
#Where
**Demos:**
**Demo online:**
[labs.easyblog.it/maps/leaflet-search](http://labs.easyblog.it/maps/leaflet-search/)
**Source code:**
@ -19,36 +20,49 @@ Tested in Leaflet 0.6.4
[NPM](https://npmjs.org/package/leaflet-search)
[Atmosphere](https://atmosphere.meteor.com/package/leaflet-search)
#How
Insert leaflet-search.css styles to your css page
#Build
Since Version 1.4.7 this plugin support [Grunt](http://gruntjs.com/) for building process.
Therefore the deployment require [NPM](https://npmjs.org/) installed in your system.
After you've made sure to have npm working, run this in command line:
```bash
npm install
grunt
```
#Examples
(require src/leaflet-search.css)
Adding the search control to the map:
```
```javascript
map.addControl( new L.Control.Search({layer: searchLayer}) );
//searchLayer if a L.LayerGroup contains searched markers
```
short way:
//searchLayer is a L.LayerGroup contains searched markers
```
Short way:
```javascript
var map = new L.Map('map', { searchControl: {layer: searchLayer} });
```
other examples:
```
//ajax request to search.php for retrieve elements locations
#Advanced Examples
Ajax request to search.php for retrieve elements locations:
```javascript
map.addControl( new L.Control.Search({url: 'search.php?q={s}'}) );
```
//jsonp request to 3rd party service, implements Geocode Searching using OSM API
Request to third party JSONP service, implements Geocode Searching using OSM API:
```javascript
map.addControl( new L.Control.Search({
url: 'http://nominatim.openstreetmap.org/search?format=json&q={s}',
jsonpParam: 'json_callback',
propertyName: 'display_name',
propertyLoc: ['lat','lon']
}) );
```
//geojson layer, search and color feature vector
Search and color features vector in GeoJSON layer:
```javascript
var searchControl = new L.Control.Search({layer: geojsonLayer, circleLocation:false});
searchControl.on('search_locationfound', function(e) {
@ -63,3 +77,22 @@ searchControl.on('search_locationfound', function(e) {
map.addControl(searchControl);
```
Static data source:
```
var data = [
{"loc":[41.575330,13.102411], "title":"aquamarine"},
{"loc":[41.575730,13.002411], "title":"black"},
{"loc":[41.219190,13.062145], "title":"cyan"}
];
map.addControl(new L.Control.Search({
markerLocation: true,
callData: function(text, callResponse) {
//here can use custom criteria or merge data from multiple layers
callResponse(data);
}
}) );
```

View file

@ -1,27 +1,59 @@
Tasks found in: src/leaflet-search.js
[Line: 22] [low] //TODO important! implements uniq option 'sourceData' that recognizes source type: url,array,callback or layer
[Line: 23] [low] //TODO implement can do research on multiple sources
[Line: 26] [low] //TODO implement sub property filter for propertyName,propertyLoc like this: "prop.subprop.title"
[Line: 38] [low] //TODO add option for persist markerLoc after collapse!
[Line: 48] [low] //TODO add option collapsed, like control.layers
[Line: 53] [low] //TODO important optimization!!! always append data in this._recordsCache
[Line: 57] [low] //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
[Line: 60] [low] //TODO change structure of _recordsCache
[Line: 342] [low] //TODO add option for case sesitive search, also showLocation
[Line: 345] [low] //TODO use .filter or .map
[Line: 407] [low] //TODO throw new Error("propertyName '"+propName+"' not found in JSON data");
[Line: 412] [low] //TODO remove script node after call run
[Line: 421] [low] //TODO add rnd param or randomize callback name! in recordsFromJsonp
[Line: 441] [low] //TODO add rnd param or randomize callback name! in recordsFromAjax
[Line: 504] [low] //TODO implements autype without selection(useful for mobile device)
[Line: 604] [low] //TODO important optimization!!! always append data in this._recordsCache
[Line: 608] [low] //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
[Line: 611] [low] //TODO change structure of _recordsCache
[Line: 662] [low] //TODO refact _handleAutoresize now is not accurate
[Line: 758] [low] //TODO showLocation: start animation after setView or panTo, maybe with map.on('moveend')...
[Line: 779] [low] //TODO add custom icon!
[Line: 787] [low] //TODO add inner circle
[Line: 843] [low] //TODO refact animate() more smooth! like this: http://goo.gl/DDlRs
[Line: 865] [low] //TODO use create event 'animateEnd' in SearchMarker
[Line: 50] [med] //FIXME option condition problem {autoCollapse: true, markerLocation: true} not show location
[Line: 51] [med] //FIXME option condition problem {autoCollapse: false }
[Line: 358] [med] //FIXME problem with jsonp/ajax when remote filter has different behavior of this._filterRecords
[Line: 731] [med] //FIXME if collapse in _handleSubmit hide _markerLoc!
[Line: 761] [med] //FIXME autoCollapse option hide this._markerLoc before that visualized!!
Tasks found in: src/leaflet-search_collapsed.js
[Line: 22] [low] //TODO important! implements uniq option 'sourceData' that recognizes source type: url,array,callback or layer
[Line: 23] [low] //TODO implement can do research on multiple sources
[Line: 37] [low] //TODO add option for persist markerLoc after collapse!
[Line: 47] [low] //TODO add option collapsed, like control.layers
[Line: 296] [low] //TODO add option for case sesitive search, also showLocation
[Line: 299] [low] //TODO use .filter or .map
[Line: 361] [low] //TODO verify json[n].hasOwnProperty(propName)
[Line: 367] [low] //TODO remove script node after call run
[Line: 376] [low] //TODO add rnd param or randomize callback name! in recordsFromJsonp
[Line: 396] [low] //TODO add rnd param or randomize callback name! in recordsFromAjax
[Line: 458] [low] //TODO implements autype without selection(useful for mobile device)
[Line: 558] [low] //TODO important optimization!!! always append data in this._recordsCache
[Line: 562] [low] //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
[Line: 565] [low] //TODO change structure of _recordsCache
[Line: 616] [low] //TODO refact _handleAutoresize now is not accurate
[Line: 712] [low] //TODO showLocation: start animation after setView or panTo, maybe with map.on('moveend')...
[Line: 733] [low] //TODO add custom icon!
[Line: 741] [low] //TODO add inner circle
[Line: 797] [low] //TODO refact animate() more smooth! like this: http://goo.gl/DDlRs
[Line: 819] [low] //TODO use create event 'animateEnd' in SearchMarker
[Line: 52] [low] //TODO important optimization!!! always append data in this._recordsCache
[Line: 56] [low] //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
[Line: 59] [low] //TODO change structure of _recordsCache
[Line: 87] [low] // TODO: touch
[Line: 358] [low] //TODO add option for case sesitive search, also showLocation
[Line: 361] [low] //TODO use .filter or .map
[Line: 423] [low] //TODO throw new Error("propertyName '"+propName+"' not found in JSON data");
[Line: 428] [low] //TODO remove script node after call run
[Line: 437] [low] //TODO add rnd param or randomize callback name! in recordsFromJsonp
[Line: 457] [low] //TODO add rnd param or randomize callback name! in recordsFromAjax
[Line: 520] [low] //TODO implements autype without selection(useful for mobile device)
[Line: 620] [low] //TODO important optimization!!! always append data in this._recordsCache
[Line: 624] [low] //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
[Line: 627] [low] //TODO change structure of _recordsCache
[Line: 678] [low] //TODO refact _handleAutoresize now is not accurate
[Line: 774] [low] //TODO showLocation: start animation after setView or panTo, maybe with map.on('moveend')...
[Line: 795] [low] //TODO add custom icon!
[Line: 803] [low] //TODO add inner circle
[Line: 859] [low] //TODO refact animate() more smooth! like this: http://goo.gl/DDlRs
[Line: 881] [low] //TODO use create event 'animateEnd' in SearchMarker
[Line: 49] [med] //FIXME option condition problem {autoCollapse: true, markerLocation: true} not show location
[Line: 50] [med] //FIXME option condition problem {autoCollapse: false }
[Line: 312] [med] //FIXME problem with jsonp/ajax when remote filter has different behavior of this._filterRecords
[Line: 685] [med] //FIXME if collapse in _handleSubmit hide _markerLoc!
[Line: 715] [med] //FIXME autoCollapse option hide this._markerLoc before that visualized!!
[Line: 374] [med] //FIXME problem with jsonp/ajax when remote filter has different behavior of this._filterRecords
[Line: 747] [med] //FIXME if collapse in _handleSubmit hide _markerLoc!
[Line: 777] [med] //FIXME autoCollapse option hide this._markerLoc before that visualized!!

View file

@ -1,6 +1,6 @@
{
"name": "leaflet-search",
"version": "1.4.6",
"version": "1.5.1",
"main": "leaflet-search.js",
"ignore": [
"**/.*",

View file

@ -1,5 +1,5 @@
/*
* Leaflet Search Control v1.4.7 - 2014-01-04
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
/*
* Leaflet Search Control v1.4.7 - 2014-01-04
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com

View file

@ -1,5 +1,5 @@
/*
* Leaflet Search Control v1.4.7 - 2014-01-04
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com

View file

@ -1,5 +1,5 @@
/*
* Leaflet Search Control v1.4.7 - 2014-01-04
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com

View file

@ -1,5 +1,5 @@
/*
* Leaflet Search Control v1.4.7 - 2014-01-04
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com
@ -14,32 +14,32 @@
* git@github.com:stefanocudini/leaflet-search.git
*
*/
(function() {
L.Control.Search = L.Control.extend({
includes: L.Mixin.Events,
//
// Name Data passed Description
// Name Data passed Description
//
//Managed Events:
// search_locationfound {latlng, title} fired after moved and show markerLocation
// search_collapsed {} fired after control was collapsed
// search_locationfound {latlng, title, layer} fired after moved and show markerLocation
// search_collapsed {} fired after control was collapsed
//
//Public methods:
// setLayer() L.LayerGroup() set layer search at runtime
// showAlert() 'Text message' Show alert message
// setLayer() L.LayerGroup() set layer search at runtime
// showAlert() 'Text message' Show alert message
//
options: {
wrapper: '', //container id to insert Search Control
url: '', //url for search by ajax request, ex: "search.php?q={s}"
jsonpParam: null, //jsonp param name for search by jsonp service, ex: "callback"
layer: null, //layer where search markers(is a L.LayerGroup)
callData: null, //function that fill _recordsCache, passed searching text by first param and callback in second
//TODO important! implements uniq option 'sourceData' that recognizes source type: url,array,callback or layer
//TODO implement can do research on multiple sources
propertyName: 'title', //property in marker.options(or feature.properties for vector layer) trough filter elements in layer
propertyLoc: 'loc', //field name for remapping location, using array: ['latname','lonname'] for select double fields(ex. ['lat','lon'] )
//TODO implement sub property filter for propertyName,propertyLoc like this: "prop.subprop.title"
propertyName: 'title', //property in marker.options(or feature.properties for vector layer) trough filter elements in layer,
propertyLoc: 'loc', //field for remapping location, using array: ['latname','lonname'] for select double fields(ex. ['lat','lon'] )
// support dotted format: 'prop.subprop.title'
callTip: null, //function that return row tip html node(or html string), receive text tooltip in first param
filterJSON: null, //callback for filtering data to _recordsCache
minLength: 1, //minimal text length for autocomplete
@ -49,6 +49,7 @@ L.Control.Search = L.Control.extend({
tooltipLimit: -1, //limit max results to show in tooltip. -1 for no limit.
tipAutoSubmit: true, //auto map panTo when click on tooltip
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)
//TODO add option for persist markerLoc after collapse!
autoCollapseTime: 1200, //delay for autoclosing alert and collapse after blur
@ -64,7 +65,18 @@ L.Control.Search = L.Control.extend({
},
//FIXME option condition problem {autoCollapse: true, markerLocation: true} not show location
//FIXME option condition problem {autoCollapse: false }
//
//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(callData,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
initialize: function(options) {
L.Util.setOptions(this, options || {});
this._inputMinSize = this.options.text ? this.options.text.length : 10;
@ -83,7 +95,10 @@ L.Control.Search = L.Control.extend({
this._cancel = this._createCancel(this.options.textCancel, 'search-cancel');
this._button = this._createButton(this.options.text, 'search-button');
this._alert = this._createAlert('search-alert');
if(this.options.collapsed===false)
this.expand();
if(this.options.circleLocation || this.options.markerLocation)
this._markerLoc = new SearchMarker([0,0], {marker: this.options.markerLocation});//see below
@ -91,10 +106,23 @@ L.Control.Search = L.Control.extend({
map.on({
// 'layeradd': this._onLayerAddRemove,
// 'layerremove': this._onLayerAddRemove
'resize':this._handleAutoresize()
'resize': this._handleAutoresize
}, this);
return this._container;
},
addTo: function (map) {
if(this.options.wrapper) {
this._container = this.onAdd(map);
this._wrapper = L.DomUtil.get(this.options.wrapper);
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 = {};
@ -111,7 +139,22 @@ L.Control.Search = L.Control.extend({
// if( L.stamp(e.layer) != L.stamp(this._layer) )
// this.setLayer(e.layer);
// },
_getPath: function(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];
},
setLayer: function(layer) { //set search layer at runtime
//this.options.layer = layer; //setting this, run only this._recordsFromLayer()
this._layer = layer;
@ -147,7 +190,7 @@ L.Control.Search = L.Control.extend({
return this;
},
expand: function() {
expand: function() {
this._input.style.display = 'block';
L.DomUtil.addClass(this._container, 'search-exp');
this._input.focus();
@ -159,12 +202,15 @@ L.Control.Search = L.Control.extend({
this._hideTooltip();
this.cancel();
this._alert.style.display = 'none';
this._input.style.display = 'none';
this._input.blur();
this._cancel.style.display = 'none';
L.DomUtil.removeClass(this._container, 'search-exp');
//this._markerLoc.hide();//maybe unuseful
this._map.off('dragstart', this.collapse, this);
if(this.options.collapsed)
{
this._input.style.display = 'none';
this._cancel.style.display = 'none';
L.DomUtil.removeClass(this._container, 'search-exp');
//this._markerLoc.hide();//maybe unuseful
this._map.off('dragstart', this.collapse, this);
}
this.fire('search_collapsed');
return this;
},
@ -364,18 +410,17 @@ L.Control.Search = L.Control.extend({
},
_defaultFilterJSON: function(json) { //default callback for filter data
var jsonret = {},
var jsonret = {}, i,
propName = this.options.propertyName,
propLoc = this.options.propertyLoc;
if( L.Util.isArray(propLoc) )
for(var i in json)
jsonret[ json[i][propName] ]= L.latLng( json[i][ propLoc[0] ], json[i][ propLoc[1] ] );
for(i in json)
jsonret[ this._getPath(json[i],propName) ]= L.latLng( json[i][ propLoc[0] ], json[i][ propLoc[1] ] );
else
for(var n in json)
jsonret[ json[n][propName] ]= L.latLng( json[n][ propLoc ] );
//TODO verify json[n].hasOwnProperty(propName)
//throw new Error("propertyName '"+propName+"' not found in JSON data");
for(i in json)
jsonret[ this._getPath(json[i],propName) ]= L.latLng( this._getPath(json[i],propLoc) );
//TODO throw new Error("propertyName '"+propName+"' not found in JSON data");
return jsonret;
},
@ -426,7 +471,8 @@ L.Control.Search = L.Control.extend({
},
_recordsFromLayer: function() { //return table: key,value from layer
var retRecords = {},
var that = this,
retRecords = {},
propName = this.options.propertyName,
loc;
@ -436,17 +482,17 @@ L.Control.Search = L.Control.extend({
if(layer instanceof L.Marker)
{
if(layer.options.hasOwnProperty(propName))
if(that._getPath(layer.options,propName))
{
loc = layer.getLatLng();
loc.layer = layer;
retRecords[ layer.options[propName] ] = loc;
retRecords[ that._getPath(layer.options,propName) ] = loc;
}else if(layer.feature.properties.hasOwnProperty(propName)){
}else if(that._getPath(layer.feature.properties,propName)){
loc = layer.getLatLng();
loc.layer = layer;
retRecords[ layer.feature.properties[propName] ] = loc;
retRecords[ that._getPath(layer.feature.properties,propName) ] = loc;
}else{
console.log("propertyName '"+propName+"' not found in marker", layer);
@ -587,7 +633,7 @@ L.Control.Search = L.Control.extend({
L.DomUtil.addClass(this._container, 'search-load');
if(this.options.callData) //CUSTOM SEARCH CALLBACK(USUALLY FOR AJAX SEARCHING)
if(this.options.callData) //CUSTOM SEARCH CALLBACK
{
that = this;
this.options.callData(inputText, function(jsonraw) {
@ -837,7 +883,7 @@ var SearchMarker = L.Marker.extend({
}, tInt);
return this;
}
}
});
L.Map.addInitHook(function () {

View file

@ -37,24 +37,26 @@
<li>Customize tooltip menu</li>
<li>Many options to customize the behavior</li>
<li>Support search in features collection</li>
<li>Render Search Box Outside the Leaflet Map</li>
</ul>
</div>
<div class="contents">
<h4>Examples</h4>
<ul id="examples">
<li><a href="examples/simple.html">Simple</a></li>
<li><a href="examples/outside.html">Outside the Map</a></li>
<li><a href="examples/geojson-layer.html">GeoJSON features</a></li>
<li><a href="examples/ajax.html">Ajax</a></li>
<li><a href="examples/jsonp.html">Jsonp</a></li>
<li><a href="examples/ajax-jquery.html">Ajax by jQuery</a></li>
<li><a href="examples/ajax-jquery.html">Ajax by jQuery</a></li>
<li><a href="examples/calldata.html">Static data</a></li>
<li><a href="examples/jsonp-filtered.html">Jsonp Filtered</a></li>
<li><a href="examples/ajax-bulk.html">Bulk data</a></li>
<li><a href="examples/custom-tip.html">Custom Tip</a></li>
<li><a href="examples/custom-tip.html">Custom Tip Item</a></li>
<li><a href="examples/google-geocoding.html">GeoCode Search - Google Geocoding API</a></li>
<li><a href="examples/nominatim.html">GeoCode Search - OSM Nominatim API</a></li>
<li><a href="examples/cloudmade.html">GeoCode Search - Cloudmade API</a></li>
<li><a href="examples/mobile.html">Mobile styled</a></li>
<li><a href="examples/twitter.html">Twitter API</a></li>
<li><a href="examples/mobile.html">Mobile styled</a></li>
</ul>
</div>
<div class="contents">

View file

@ -1,6 +1,6 @@
{
"name": "leaflet-search",
"version": "1.4.7",
"version": "1.5.1",
"description": "Leaflet Control for searching markers/features by attribute on map or remote searching in jsonp/ajax",
"repository": {
"type": "git",
@ -23,6 +23,7 @@
},
"devDependencies": {
"grunt": "~0.4.2",
"grunt-cli": "~0.1.11",
"grunt-contrib-uglify": "~0.2.7",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-clean": "~0.5.0",

View file

@ -3,6 +3,6 @@
"description": "Leaflet Control for searching markers/features by attribute on map or remote searching in jsonp/ajax",
"homepage": "http://labs.easyblog.it/maps/leaflet-search/",
"author": "Stefano Cudini <stefano.cudini@gmail.com>",
"version": "1.4.7",
"version": "1.5.1",
"git": "https://github.com/stefanocudini/leaflet-search.git"
}
}

View file

@ -1,29 +1,29 @@
(function() {
L.Control.Search = L.Control.extend({
includes: L.Mixin.Events,
//
// Name Data passed Description
// Name Data passed Description
//
//Managed Events:
// search_locationfound {latlng, title} fired after moved and show markerLocation
// search_collapsed {} fired after control was collapsed
// search_locationfound {latlng, title, layer} fired after moved and show markerLocation
// search_collapsed {} fired after control was collapsed
//
//Public methods:
// setLayer() L.LayerGroup() set layer search at runtime
// showAlert() 'Text message' Show alert message
// setLayer() L.LayerGroup() set layer search at runtime
// showAlert() 'Text message' Show alert message
//
options: {
wrapper: '', //container id to insert Search Control
url: '', //url for search by ajax request, ex: "search.php?q={s}"
jsonpParam: null, //jsonp param name for search by jsonp service, ex: "callback"
layer: null, //layer where search markers(is a L.LayerGroup)
callData: null, //function that fill _recordsCache, passed searching text by first param and callback in second
//TODO important! implements uniq option 'sourceData' that recognizes source type: url,array,callback or layer
//TODO implement can do research on multiple sources
propertyName: 'title', //property in marker.options(or feature.properties for vector layer) trough filter elements in layer
propertyLoc: 'loc', //field name for remapping location, using array: ['latname','lonname'] for select double fields(ex. ['lat','lon'] )
//TODO implement sub property filter for propertyName,propertyLoc like this: "prop.subprop.title"
propertyName: 'title', //property in marker.options(or feature.properties for vector layer) trough filter elements in layer,
propertyLoc: 'loc', //field for remapping location, using array: ['latname','lonname'] for select double fields(ex. ['lat','lon'] )
// support dotted format: 'prop.subprop.title'
callTip: null, //function that return row tip html node(or html string), receive text tooltip in first param
filterJSON: null, //callback for filtering data to _recordsCache
minLength: 1, //minimal text length for autocomplete
@ -33,6 +33,7 @@ L.Control.Search = L.Control.extend({
tooltipLimit: -1, //limit max results to show in tooltip. -1 for no limit.
tipAutoSubmit: true, //auto map panTo when click on tooltip
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)
//TODO add option for persist markerLoc after collapse!
autoCollapseTime: 1200, //delay for autoclosing alert and collapse after blur
@ -48,7 +49,18 @@ L.Control.Search = L.Control.extend({
},
//FIXME option condition problem {autoCollapse: true, markerLocation: true} not show location
//FIXME option condition problem {autoCollapse: false }
//
//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(callData,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
initialize: function(options) {
L.Util.setOptions(this, options || {});
this._inputMinSize = this.options.text ? this.options.text.length : 10;
@ -67,7 +79,10 @@ L.Control.Search = L.Control.extend({
this._cancel = this._createCancel(this.options.textCancel, 'search-cancel');
this._button = this._createButton(this.options.text, 'search-button');
this._alert = this._createAlert('search-alert');
if(this.options.collapsed===false)
this.expand();
if(this.options.circleLocation || this.options.markerLocation)
this._markerLoc = new SearchMarker([0,0], {marker: this.options.markerLocation});//see below
@ -75,10 +90,23 @@ L.Control.Search = L.Control.extend({
map.on({
// 'layeradd': this._onLayerAddRemove,
// 'layerremove': this._onLayerAddRemove
'resize':this._handleAutoresize()
'resize': this._handleAutoresize
}, this);
return this._container;
},
addTo: function (map) {
if(this.options.wrapper) {
this._container = this.onAdd(map);
this._wrapper = L.DomUtil.get(this.options.wrapper);
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 = {};
@ -95,7 +123,22 @@ L.Control.Search = L.Control.extend({
// if( L.stamp(e.layer) != L.stamp(this._layer) )
// this.setLayer(e.layer);
// },
_getPath: function(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];
},
setLayer: function(layer) { //set search layer at runtime
//this.options.layer = layer; //setting this, run only this._recordsFromLayer()
this._layer = layer;
@ -131,7 +174,7 @@ L.Control.Search = L.Control.extend({
return this;
},
expand: function() {
expand: function() {
this._input.style.display = 'block';
L.DomUtil.addClass(this._container, 'search-exp');
this._input.focus();
@ -143,12 +186,15 @@ L.Control.Search = L.Control.extend({
this._hideTooltip();
this.cancel();
this._alert.style.display = 'none';
this._input.style.display = 'none';
this._input.blur();
this._cancel.style.display = 'none';
L.DomUtil.removeClass(this._container, 'search-exp');
//this._markerLoc.hide();//maybe unuseful
this._map.off('dragstart', this.collapse, this);
if(this.options.collapsed)
{
this._input.style.display = 'none';
this._cancel.style.display = 'none';
L.DomUtil.removeClass(this._container, 'search-exp');
//this._markerLoc.hide();//maybe unuseful
this._map.off('dragstart', this.collapse, this);
}
this.fire('search_collapsed');
return this;
},
@ -348,18 +394,17 @@ L.Control.Search = L.Control.extend({
},
_defaultFilterJSON: function(json) { //default callback for filter data
var jsonret = {},
var jsonret = {}, i,
propName = this.options.propertyName,
propLoc = this.options.propertyLoc;
if( L.Util.isArray(propLoc) )
for(var i in json)
jsonret[ json[i][propName] ]= L.latLng( json[i][ propLoc[0] ], json[i][ propLoc[1] ] );
for(i in json)
jsonret[ this._getPath(json[i],propName) ]= L.latLng( json[i][ propLoc[0] ], json[i][ propLoc[1] ] );
else
for(var n in json)
jsonret[ json[n][propName] ]= L.latLng( json[n][ propLoc ] );
//TODO verify json[n].hasOwnProperty(propName)
//throw new Error("propertyName '"+propName+"' not found in JSON data");
for(i in json)
jsonret[ this._getPath(json[i],propName) ]= L.latLng( this._getPath(json[i],propLoc) );
//TODO throw new Error("propertyName '"+propName+"' not found in JSON data");
return jsonret;
},
@ -410,7 +455,8 @@ L.Control.Search = L.Control.extend({
},
_recordsFromLayer: function() { //return table: key,value from layer
var retRecords = {},
var that = this,
retRecords = {},
propName = this.options.propertyName,
loc;
@ -420,17 +466,17 @@ L.Control.Search = L.Control.extend({
if(layer instanceof L.Marker)
{
if(layer.options.hasOwnProperty(propName))
if(that._getPath(layer.options,propName))
{
loc = layer.getLatLng();
loc.layer = layer;
retRecords[ layer.options[propName] ] = loc;
retRecords[ that._getPath(layer.options,propName) ] = loc;
}else if(layer.feature.properties.hasOwnProperty(propName)){
}else if(that._getPath(layer.feature.properties,propName)){
loc = layer.getLatLng();
loc.layer = layer;
retRecords[ layer.feature.properties[propName] ] = loc;
retRecords[ that._getPath(layer.feature.properties,propName) ] = loc;
}else{
console.log("propertyName '"+propName+"' not found in marker", layer);
@ -571,7 +617,7 @@ L.Control.Search = L.Control.extend({
L.DomUtil.addClass(this._container, 'search-load');
if(this.options.callData) //CUSTOM SEARCH CALLBACK(USUALLY FOR AJAX SEARCHING)
if(this.options.callData) //CUSTOM SEARCH CALLBACK
{
that = this;
this.options.callData(inputText, function(jsonraw) {
@ -821,7 +867,7 @@ var SearchMarker = L.Marker.extend({
}, tInt);
return this;
}
}
});
L.Map.addInitHook(function () {