1// https://yandex.ru/blog/ymapsapi/1501 2function SearchAddress(map, form) { 3 this._model = new SearchAddress.Model(map); 4 this._formView = new SearchAddress.FormView(form); 5 this._mapView = new SearchAddress.MapView(map); 6 7 this._attachHandlers(); 8} 9 10SearchAddress.prototype = { 11 constructor: SearchAddress, 12 _attachHandlers: function () { 13 this._formView.events 14 .on('searchrequest', $.proxy(this._onSearchRequest, this)); 15 }, 16 _detachHandlers: function () { 17 this._formView.events 18 .off(); 19 }, 20 _onSearchRequest: function (e) { 21 var promise = this._model.search(e.query); 22 23 this._mapView 24 .clear(); 25 26 promise.then( 27 $.proxy(this._onSearchSuccess, this), 28 $.proxy(this._onSearchError, this) 29 ); 30 }, 31 _onSearchSuccess: function (result) { 32 if(this._model.getResult()) { 33 this._mapView 34 .render(result); 35 } 36 else { 37 this._formView 38 .showMessage("ÐиÑего не найдено."); 39 } 40 }, 41 _onSearchError: function (e) { 42 this._formView.showMessage( 43 this._model.getError() 44 ); 45 }, 46 getModel: function () { 47 return this._formModel; 48 } 49}; 50 51SearchAddress.MapView = function (map) { 52 this._map = map; 53 this._point = null; 54}; 55 56SearchAddress.MapView.prototype = { 57 constructor: SearchAddress.MapView, 58 render: function (results) { 59 var metaData = results.metaData.geocoder, 60 result = results.geoObjects.get(0), 61 balloonContent = '<p><small>по запÑоÑÑ:</small> <em>' + metaData.request + '</em></p>' + 62 '<p><small>найдено:</small> <strong>' + result.properties.get('text') + '</strong></p>'; 63 64 this._point = new ymaps.Placemark(result.geometry.getCoordinates(), { 65 balloonContentBody: balloonContent 66 }); 67 68 this._map.geoObjects 69 .add(this._point); 70 71 this._setMapBounds(result.properties.get('boundedBy')); 72 73 return this; 74 }, 75 clear: function () { 76 if(this._point) { 77 this._map.geoObjects 78 .remove(this._point); 79 this._point = null; 80 } 81 82 return this; 83 }, 84 getPoint: function () { 85 return this._point; 86 }, 87 _setMapBounds: function (bounds) { 88 this._map.setBounds(bounds, { 89 checkZoomRange: true, 90 duration: 200, 91 callback: ymaps.util.bind(this._onSetMapBounds, this) 92 }); 93 }, 94 _onSetMapBounds: function () { 95 this._point.balloon 96 .open(); 97 } 98}; 99 100SearchAddress.FormView = function (form) { 101 this._form = form; 102 this._controls = form.find('.control-group'); 103 this._message = form.find('.help-inline'); 104 this._input = form.find('.search-query'); 105 106 this.events = $({}); 107 108 this._attachHandlers(); 109}; 110 111SearchAddress.FormView.prototype = { 112 constructor: SearchAddress.FormView, 113 _attachHandlers: function () { 114 // this._form 115 // .on('submit', $.proxy(this._onFormSubmit, this)); 116 this._input 117 .on('keydown', $.proxy(this._onInputChange, this)) 118 .typeahead({ 119 source: $.proxy(this._dataSource, this), 120 items: this.getSuggestConfig().limit, 121 minLength: 3 122 }); 123 }, 124 _detachHandlers: function () { 125 this._form 126 .off("submit"); 127 this._input 128 .off(); 129 }, 130 _onFormSubmit: function (e) { 131 e.preventDefault(); 132 133 var value = this._input.val(); 134 135 if(value) { 136 this.events.trigger($.Event('searchrequest', { 137 query: value 138 })); 139 } 140 else { 141 this.showMessage('Ðадан пÑÑÑой поиÑковÑй запÑоÑ.'); 142 } 143 }, 144 _onInputChange: function (e) { 145 this.hideMessage(); 146 }, 147 showMessage: function (text) { 148 this._controls 149 .addClass('error'); 150 this._message 151 .removeClass('invisible') 152 .text(text); 153 }, 154 hideMessage: function () { 155 this._controls 156 .removeClass('error'); 157 this._message 158 .addClass('invisible') 159 .text(''); 160 }, 161 _dataSource: function (query, callback) {
162 var config = this.getSuggestConfig(), 163 request = $.extend({ query: query }, config); 164 165 $.ajax({ 166 url: config.url, 167 dataType: 'jsonp', 168 data: request, 169 context: this, 170 success: function (json) { 171 var results = []; 172 173 for(var i = 0, len = json.result.length; i < len; i++) { 174 var result = json.result[i], 175 parent = result.parents && result.parents[0]; 176 177 results.push( 178 (parent && (parent.name + ' ' + parent.type + ', ') || '') + 179 result.type + ' ' + result.name 180 ); 181 } 182 183 callback(results); 184 } 185 }); 186 }, 187 getSuggestConfig: function () { 188 return { 189 url: 'https://kladr-api.ru/api.php', 190 contentType: 'city', 191 withParent: 1, 192 limit: 5, 193 token: '52024d6c472d040824000221', 194 key: '6cf033712aa73a4a26db39d72ea02bb682c8e390' 195 }; 196 } 197}; 198 199SearchAddress.Model = function (map) { 200 this._map = map; 201 this._result = null; 202 this._error = null; 203}; 204 205SearchAddress.Model.prototype = { 206 constructor: SearchAddress.Model, 207 search: function (request) { 208 var promise = ymaps.geocode(request, this.getDefaults()); 209 210 this.clear(); 211 212 promise.then( 213 $.proxy(this._onSearchSuccess, this), 214 $.proxy(this._onSearchFailed, this) 215 ); 216 217 return promise; 218 }, 219 clear: function () { 220 this._result = null; 221 this._error = null; 222 }, 223 _onSearchSuccess: function (result) { 224 this._result = result.geoObjects.get(0); 225 }, 226 _onSearchFailed: function (error) { 227 this._error = error; 228 }, 229 getDefaults: function () { 230 return { 231 results: 1, 232 boundedBy: this._map.getBounds() 233 }; 234 }, 235 getResult: function () { 236 return this._result; 237 }, 238 getError: function () { 239 return this._error; 240 } 241}; 242 243$(document).ready(function(){ 244 searchControl = new SearchAddress('', $('#route_form')); 245 246 $('.add_waypoint').click(function() { 247 $('.waypoints > span:visible, .waypoints > input:visible').next('input').show(); 248 if ($('.waypoints > input:hidden').length == 0) $(this).hide(); 249 }); 250});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.