kladr-rails 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 02676087a2d888a64c0add856bdb446dcc6b6b39
4
+ data.tar.gz: e4a4822b7d3e0cce74aaacf6c15ec4b0cb38de8c
5
+ SHA512:
6
+ metadata.gz: 2a4d9989b2f2d27ef867fc8c0c7ec63da73cc43332af27955e7de8b22ecc78ab19cfdf2edf69df9def09cac70ff033d4f87c9197618908f4b437de3f8a82ee14
7
+ data.tar.gz: 4fec12a7134f436ac133acb78cc14f9844d9b88ea02fac9dbaf880a681b0c830987b3746ada8014d4a22a5d300f1bc3786be968bb336e6cdbe1a0dd61d5c593d
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Navin Peiris
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Kladr for Rails
2
+
3
+ Kladr API is free service for retrieving address details (cities, streets and etc) for Russian regions
4
+
5
+ See the [Kladr home page](https://kladr-api.ru/) for more information and examples.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'kladr-rails'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install kladr-rails
20
+
21
+ ## Using the javascripts
22
+
23
+ Require `kladr` in your `app/assets/javascripts/application.js` file:
24
+
25
+ //= require kladr
26
+
27
+ ## Using the default styles
28
+
29
+ Add the following to your app/assets/stylesheets/application.css file:
30
+
31
+ *= require kladr
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ module Kladr
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Kladr
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Kladr
2
+ module Rails
3
+ VERSION = '0.9.0'
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module Kladr
2
+ module Rails
3
+ if ::Rails.version < '3.1'
4
+ require 'kladr-rails/railtie'
5
+ else
6
+ require 'kladr-rails/engine'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,163 @@
1
+ (function ($, window) {
2
+ $.kladr = {};
3
+
4
+ (function () {
5
+ var protocol = window.location.protocol == 'https:' ? 'https:' : 'http:';
6
+
7
+ // Service URL
8
+ $.kladr.url = protocol + '//kladr-api.ru/api.php';
9
+ })();
10
+
11
+ // Enum KLADR object types
12
+ $.kladr.type = {
13
+ region: 'region', // Область
14
+ district: 'district', // Район
15
+ city: 'city', // Город
16
+ street: 'street', // Улица
17
+ building: 'building' // Строение
18
+ };
19
+
20
+ // Enum city object types
21
+ $.kladr.typeCode = {
22
+ city: 1, // Город
23
+ settlement: 2, // Посёлок
24
+ village: 4 // Деревня
25
+ };
26
+
27
+ // Validate query
28
+ $.kladr.validate = function (query) {
29
+ var type = $.kladr.type;
30
+
31
+ switch (query.type) {
32
+ case type.region:
33
+ case type.district:
34
+ case type.city:
35
+ if (query.parentType && !query.parentId) {
36
+ error('parentId undefined');
37
+ return false;
38
+ }
39
+ break;
40
+ case type.street:
41
+ if (query.parentType != type.city) {
42
+ error('parentType must equal "city"');
43
+ return false;
44
+ }
45
+ if (!query.parentId) {
46
+ error('parentId undefined');
47
+ return false;
48
+ }
49
+ break;
50
+ case type.building:
51
+ if (!query.zip) {
52
+ if (!~$.inArray(query.parentType, [type.street, type.city])) {
53
+ error('parentType must equal "street" or "city"');
54
+ return false;
55
+ }
56
+ if (!query.parentId) {
57
+ error('parentId undefined');
58
+ return false;
59
+ }
60
+ }
61
+ break;
62
+ default:
63
+ if (!query.oneString) {
64
+ error('type incorrect');
65
+ return false;
66
+ }
67
+ break;
68
+ }
69
+
70
+ if (query.oneString && query.parentType && !query.parentId) {
71
+ error('parentId undefined');
72
+ return false;
73
+ }
74
+
75
+ if (query.typeCode && (query.type != type.city)) {
76
+ error('type must equal "city"');
77
+ return false;
78
+ }
79
+
80
+ if (query.limit < 1) {
81
+ error('limit must greater than 0');
82
+ return false;
83
+ }
84
+
85
+ return true;
86
+ };
87
+
88
+ // Send query to service
89
+ $.kladr.api = function (query, callback) {
90
+ if (!callback) {
91
+ error('Callback undefined');
92
+ return;
93
+ }
94
+
95
+ if (!$.kladr.validate(query)) {
96
+ callback([]);
97
+ return;
98
+ }
99
+
100
+ var timeout = setTimeout(function () {
101
+ callback([]);
102
+ timeout = null;
103
+ }, 3000);
104
+
105
+ $.getJSON($.kladr.url + "?callback=?",
106
+ toApiFormat(query),
107
+ function (data) {
108
+ if (timeout) {
109
+ callback(data.result || []);
110
+ clearTimeout(timeout);
111
+ }
112
+ }
113
+ );
114
+ };
115
+
116
+ // Check exist object
117
+ $.kladr.check = function (query, callback) {
118
+ if (!callback) {
119
+ error('Callback undefined');
120
+ return;
121
+ }
122
+
123
+ query.withParents = false;
124
+ query.limit = 1;
125
+
126
+ $.kladr.api(query, function (objs) {
127
+ objs && objs.length
128
+ ? callback(objs[0])
129
+ : callback(false);
130
+ });
131
+ };
132
+
133
+ function toApiFormat(query) {
134
+ var params = {},
135
+ fields = {
136
+ type: 'contentType',
137
+ name: 'query',
138
+ withParents: 'withParent'
139
+ };
140
+
141
+ if (query.parentType && query.parentId) {
142
+ params[query.parentType + 'Id'] = query.parentId;
143
+ }
144
+
145
+ for (var key in query) {
146
+ if (hasOwn(query, key) && query[key]) {
147
+ params[hasOwn(fields, key) ? fields[key] : key] = query[key];
148
+ }
149
+ }
150
+
151
+ return params;
152
+ }
153
+
154
+ function hasOwn(obj, property) {
155
+ return obj.hasOwnProperty(property);
156
+ }
157
+
158
+ function error(error) {
159
+ var console = window.console;
160
+
161
+ console && console.error && console.error(error);
162
+ }
163
+ })(jQuery, window);
@@ -0,0 +1,3 @@
1
+ //= require kladr/core
2
+ //= require kladr/kladr
3
+ //= require kladr/kladr_zip
@@ -0,0 +1,1097 @@
1
+ (function ($, window, document, undefined) {
2
+ var defaultOptions = {
3
+
4
+ // Api params
5
+ token: null,
6
+ key: null,
7
+ type: null,
8
+ typeCode: null,
9
+ parentType: null,
10
+ parentId: null,
11
+ limit: 10,
12
+ oneString: false,
13
+ withParents: false,
14
+
15
+ // Plugin options
16
+ parentInput: null,
17
+ verify: false,
18
+ spinner: true,
19
+
20
+ // Plugin events
21
+ open: null,
22
+ close: null,
23
+ send: null,
24
+ receive: null,
25
+ select: null,
26
+ check: null,
27
+ change: null,
28
+
29
+ // Plugin events before actions
30
+ openBefore: null,
31
+ closeBefore: null,
32
+ sendBefore: null,
33
+ selectBefore: null,
34
+ checkBefore: null,
35
+
36
+ source: function (query, callback) {
37
+ $.kladr.api(query, callback);
38
+ },
39
+
40
+ labelFormat: function (obj, query) {
41
+ var objs;
42
+
43
+ if (query.oneString) {
44
+ if (obj.parents) {
45
+ objs = [].concat(obj.parents);
46
+ objs.push(obj);
47
+
48
+ return $.kladr.buildAddress(objs);
49
+ }
50
+
51
+ return (obj.typeShort ? obj.typeShort + '. ' : '') + obj.name;
52
+ }
53
+
54
+ var label = '',
55
+ name,
56
+ objName,
57
+ queryName,
58
+ start;
59
+
60
+ if (obj.typeShort) {
61
+ label += obj.typeShort + '. ';
62
+ }
63
+
64
+ name = obj.name;
65
+ objName = name.toLowerCase();
66
+ queryName = query.name.toLowerCase();
67
+ start = objName.indexOf(queryName);
68
+ start = ~start ? start : 0;
69
+
70
+ if (queryName.length < objName.length) {
71
+ label += name.substr(0, start);
72
+ label += '<strong>' + name.substr(start, queryName.length) + '</strong>';
73
+ label += name.substr(start + queryName.length);
74
+ } else {
75
+ label += '<strong>' + name + '</strong>';
76
+ }
77
+
78
+ return label;
79
+ },
80
+
81
+ valueFormat: function (obj, query) {
82
+ var objs;
83
+
84
+ if (query.oneString) {
85
+ if (obj.parents) {
86
+ objs = [].concat(obj.parents);
87
+ objs.push(obj);
88
+
89
+ return $.kladr.buildAddress(objs);
90
+ }
91
+
92
+ return (obj.typeShort ? obj.typeShort + '. ' : '') + obj.name;
93
+ }
94
+
95
+ return obj.name;
96
+ },
97
+
98
+ showSpinner: function ($spinner) {
99
+ var top = -0.2,
100
+ spinnerInterval = setInterval(function () {
101
+ if (!$spinner.is(':visible')) {
102
+ clearInterval(spinnerInterval);
103
+ spinnerInterval = null;
104
+ return;
105
+ }
106
+
107
+ $spinner.css('background-position', '0% ' + top + '%');
108
+
109
+ top += 5.555556;
110
+
111
+ if (top > 95) {
112
+ top = -0.2;
113
+ }
114
+ }, 30);
115
+
116
+ $spinner.show();
117
+ },
118
+
119
+ hideSpinner: function ($spinner) {
120
+ $spinner.hide();
121
+ }
122
+ };
123
+
124
+ var readOnlyParams = {
125
+ current: null,
126
+ controller: null
127
+ };
128
+
129
+ var keys = {
130
+ up: 38,
131
+ down: 40,
132
+ enter: 13
133
+ };
134
+
135
+ $.kladr = $.extend($.kladr, {
136
+ setDefault: function (param1, param2) {
137
+ var params = readParams(param1, param2);
138
+
139
+ if (params.obj) {
140
+ for (var i in params.obj) {
141
+ if (hasOwn(defaultOptions, i)) {
142
+ defaultOptions[i] = params.obj[i];
143
+ }
144
+ }
145
+ }
146
+ else if (params.str && !params.isGet && hasOwn(defaultOptions, params.str[0])) {
147
+ defaultOptions[params.str[0]] = params.str[1];
148
+ }
149
+ },
150
+
151
+ getDefault: function (param) {
152
+ if (hasOwn(defaultOptions, param)) {
153
+ return defaultOptions[param];
154
+ }
155
+ },
156
+
157
+ getInputs: function (selector) {
158
+ var $source = $(selector || document.body),
159
+ inputSelector = '[data-kladr-type]';
160
+
161
+ return $source
162
+ .filter(inputSelector)
163
+ .add($source.find(inputSelector));
164
+ },
165
+
166
+ setValues: function (values, selector) {
167
+ var changeEvent = 'kladr_change.setvalues',
168
+ types = $.kladr.type,
169
+ filtered = {},
170
+ sorted = [],
171
+ $inputs, t;
172
+
173
+ if (!~$.inArray($.type(values), ['object', 'array'])) {
174
+ return;
175
+ }
176
+
177
+ $.each(values, function (key, value) {
178
+ if (!value) {
179
+ return;
180
+ }
181
+
182
+ var type = value.contentType || value.type || key;
183
+
184
+ if (hasOwn(types, type)) {
185
+ filtered[type] = value;
186
+ }
187
+ });
188
+
189
+ for (t in types) {
190
+ if (hasOwn(types, t) && filtered[t]) {
191
+ sorted[t] = filtered[t];
192
+ }
193
+ }
194
+
195
+ $inputs = $.kladr.getInputs(selector);
196
+
197
+ (function set() {
198
+ var $input, type, value;
199
+
200
+ for (type in sorted) {
201
+ if (hasOwn(sorted, type)) {
202
+ value = sorted[type];
203
+ delete sorted[type];
204
+ break;
205
+ }
206
+ }
207
+
208
+ if (!type) {
209
+ return;
210
+ }
211
+
212
+ $input = $inputs.filter('[data-kladr-type="' + type + '"]');
213
+
214
+ if (!$input.length) {
215
+ set();
216
+ return;
217
+ }
218
+
219
+ $input
220
+ .on(changeEvent, function () {
221
+ $input.off(changeEvent);
222
+ set();
223
+ })
224
+ .kladr('controller')
225
+ .setValue(value);
226
+ })();
227
+ },
228
+
229
+ getAddress: function (selector, build) {
230
+ var $inputs = $.kladr.getInputs(selector),
231
+ types = $.kladr.type,
232
+ filtered = {},
233
+ sorted = {},
234
+ t;
235
+
236
+ $inputs.each(function () {
237
+ var $this = $(this),
238
+ obj, objs, i;
239
+
240
+ if ($this.attr('data-kladr-id')) {
241
+ obj = $this.kladr('current');
242
+
243
+ if ($this.attr('data-kladr-one-string') && obj.parents) {
244
+ objs = [].concat(obj.parents);
245
+ objs.push(obj);
246
+
247
+ for (i = 0; i < objs.length; i++) {
248
+ filtered[objs[i].contentType] = objs[i];
249
+ }
250
+ }
251
+ else {
252
+ filtered[$this.attr('data-kladr-type')] = obj;
253
+ }
254
+ }
255
+ else {
256
+ filtered[$this.attr('data-kladr-type')] = $this.val();
257
+ }
258
+ });
259
+
260
+ for (t in types) {
261
+ if (hasOwn(types, t) && filtered[t]) {
262
+ sorted[t] = filtered[t];
263
+ }
264
+ }
265
+
266
+ return (build || $.kladr.buildAddress)(sorted);
267
+ },
268
+
269
+ buildAddress: function (objs) {
270
+ var lastIds = [],
271
+ address = '',
272
+ zip = '';
273
+
274
+ $.each(objs, function (i, obj) {
275
+ var name = '',
276
+ type = '',
277
+ j;
278
+
279
+ if ($.type(obj) === 'object') {
280
+ for (j = 0; j < lastIds.length; j++) {
281
+ if (lastIds[j] == obj.id) {
282
+ return;
283
+ }
284
+ }
285
+
286
+ lastIds.push(obj.id);
287
+
288
+ name = obj.name;
289
+ type = obj.typeShort + '. ';
290
+ zip = obj.zip || zip;
291
+ }
292
+ else {
293
+ name = obj;
294
+ }
295
+
296
+ if (address) address += ', ';
297
+ address += type + name;
298
+ });
299
+
300
+ address = (zip ? zip + ', ' : '') + address;
301
+
302
+ return address;
303
+ }
304
+ });
305
+
306
+ $.fn.kladr = function (param1, param2) {
307
+ var params = readParams(param1, param2),
308
+ result = null;
309
+
310
+ this.each(function () {
311
+ var res = kladr($(this), params);
312
+
313
+ if (params.isGet) {
314
+ result = res;
315
+ return false;
316
+ }
317
+ });
318
+
319
+ if (params.isGet) {
320
+ return result;
321
+ }
322
+
323
+ return this;
324
+ };
325
+
326
+ function kladr($input, params) {
327
+ var options = (function () {
328
+ var dataKey = 'kladr-data',
329
+ data = $input.data(dataKey);
330
+
331
+ if (!data) {
332
+ data = $.extend({}, defaultOptions, readOnlyParams);
333
+ $input.data(dataKey, data);
334
+ }
335
+
336
+ return {
337
+ set: function (params) {
338
+ if (params.obj) {
339
+ for (var i in params.obj) {
340
+ if (hasOwn(params.obj, i) && hasOwn(defaultOptions, i)) {
341
+ data[i] = params.obj[i];
342
+ }
343
+ }
344
+ }
345
+ else if (params.str && !params.isGet && hasOwn(defaultOptions, params.str[0])) {
346
+ data[params.str[0]] = params.str[1];
347
+ }
348
+
349
+ $input.data(dataKey, data);
350
+ },
351
+
352
+ get: function (param) {
353
+ if (hasOwn(defaultOptions, param) || hasOwn(readOnlyParams, param)) {
354
+ return data[param];
355
+ }
356
+ },
357
+
358
+ _set: function (param, value) {
359
+ data[param] = value;
360
+ $input.data(dataKey, data);
361
+ },
362
+
363
+ _get: function (param) {
364
+ if (hasOwn(data, param)) {
365
+ return data[param];
366
+ }
367
+ }
368
+ };
369
+ })();
370
+
371
+ function init(params, callback) {
372
+ if (params.isGet) {
373
+ return options.get(params.str[0]);
374
+ }
375
+
376
+ options.set(params);
377
+ callback();
378
+ }
379
+
380
+ return init(params, function () {
381
+ var $ac = null,
382
+ $spinner = null,
383
+ eventNamespace = '.kladr',
384
+ triggerChangeFlag = 'kladrInputChange';
385
+
386
+ create(function () {
387
+ var isActive = false,
388
+ canCheck = true,
389
+ lastChangeVal = '';
390
+
391
+ $input
392
+ .attr('data-kladr-type', get('type') || '')
393
+ .attr('data-kladr-one-string', get('oneString') || null)
394
+ .on('keyup' + eventNamespace, open)
395
+ .on('keydown' + eventNamespace, keySelect)
396
+ .on('blur' + eventNamespace, function () {
397
+ if (!isActive && $input.data(triggerChangeFlag) && (lastChangeVal != $input.val())) {
398
+ $input.change();
399
+ }
400
+ })
401
+ .on('blur' + eventNamespace + ' change' + eventNamespace, function (event) {
402
+ if (isActive) return;
403
+
404
+ if (event.type == 'change') {
405
+ lastChangeVal = $input.val();
406
+ }
407
+
408
+ if (canCheck) {
409
+ canCheck = false;
410
+ check();
411
+ }
412
+
413
+ close();
414
+ return false;
415
+ })
416
+ .on('focus' + eventNamespace, function () {
417
+ canCheck = true;
418
+ });
419
+
420
+ $ac
421
+ .on('touchstart' + eventNamespace + ' mousedown' + eventNamespace, 'li, a', function (event) {
422
+ event.preventDefault();
423
+
424
+ isActive = true;
425
+ mouseSelect(this);
426
+ isActive = false;
427
+ });
428
+
429
+ $(window)
430
+ .on('resize' + eventNamespace, position);
431
+ });
432
+
433
+ function create(callback) {
434
+ var $container = $(document.getElementById('kladr_autocomplete'));
435
+
436
+ if (!$container.length) {
437
+ $container = $('<div id="kladr_autocomplete"></div>').appendTo(document.body);
438
+ }
439
+
440
+ var guid = get('guid');
441
+
442
+ if (guid) {
443
+ $ac = $container.find('.autocomplete' + guid);
444
+ $spinner = $container.find('.spinner' + guid);
445
+
446
+ $(window).off(eventNamespace);
447
+ $input.off(eventNamespace);
448
+ $ac.off(eventNamespace);
449
+ }
450
+ else {
451
+ guid = getGuid();
452
+ set('guid', guid);
453
+
454
+ $input.attr('autocomplete', 'off');
455
+
456
+ $ac = $('<ul class="autocomplete' + guid + ' autocomplete" style="display: none;"></ul>')
457
+ .appendTo($container);
458
+
459
+ $spinner = $('<div class="spinner' + guid + ' spinner" style="display: none;"></div>')
460
+ .appendTo($container);
461
+
462
+ createController();
463
+
464
+ position();
465
+ checkAutoFill();
466
+ }
467
+
468
+ callback();
469
+ }
470
+
471
+ function render(objs, query) {
472
+ var obj, value, label, $a;
473
+
474
+ $ac.empty();
475
+
476
+ for (var i = 0; i < objs.length; i++) {
477
+ obj = objs[i];
478
+ value = get('valueFormat')(obj, query);
479
+ label = get('labelFormat')(obj, query);
480
+
481
+ $a = $('<a data-val="' + value + '">' + label + '</a>');
482
+ $a.data('kladr-object', obj);
483
+
484
+ $('<li></li>')
485
+ .append($a)
486
+ .appendTo($ac);
487
+ }
488
+ }
489
+
490
+ function position() {
491
+ var inputOffset = $input.offset(),
492
+ inputWidth = $input.outerWidth(),
493
+ inputHeight = $input.outerHeight();
494
+
495
+ if (!inputOffset) {
496
+ return;
497
+ }
498
+
499
+ if ((position.top == inputOffset.top)
500
+ && (position.left == inputOffset.left)
501
+ && (position.width == inputWidth)
502
+ && (position.height == inputHeight)) {
503
+ return;
504
+ }
505
+
506
+ position.top = inputOffset.top;
507
+ position.left = inputOffset.left;
508
+ position.width = inputWidth;
509
+ position.height = inputHeight;
510
+
511
+ $ac.css({
512
+ top: inputOffset.top + inputHeight + 'px',
513
+ left: inputOffset.left
514
+ });
515
+
516
+ var differ = $ac.outerWidth() - $ac.width();
517
+ $ac.width(inputWidth - differ);
518
+
519
+ var spinnerWidth = $spinner.width(),
520
+ spinnerHeight = $spinner.height();
521
+
522
+ $spinner.css({
523
+ top: inputOffset.top + (inputHeight - spinnerHeight) / 2 - 1,
524
+ left: inputOffset.left + inputWidth - spinnerWidth - 2
525
+ });
526
+ }
527
+
528
+ function open(event) {
529
+ // return on control keys
530
+ if ((event.which > 8) && (event.which < 46)) {
531
+ return;
532
+ }
533
+
534
+ $input.data(triggerChangeFlag, false);
535
+
536
+ if (!trigger('open_before')) {
537
+ close();
538
+ return;
539
+ }
540
+
541
+ setCurrent(null);
542
+
543
+ var name = $input.val();
544
+
545
+ if (!$.trim(name)) {
546
+ error(false);
547
+ close();
548
+ return;
549
+ }
550
+
551
+ var query = getQuery(name);
552
+
553
+ if (!trigger('send_before', query)) {
554
+ close();
555
+ return;
556
+ }
557
+
558
+ showSpinner();
559
+ trigger('send');
560
+
561
+ get('source')(query, function (objs) {
562
+ trigger('receive');
563
+
564
+ if (!$input.is(':focus')) {
565
+ hideSpinner();
566
+ close();
567
+ return;
568
+ }
569
+
570
+ if (!$.trim($input.val()) || !objs.length) {
571
+ hideSpinner();
572
+ setCurrent(null);
573
+ close();
574
+ return;
575
+ }
576
+
577
+ render(objs, query);
578
+ position();
579
+ hideSpinner();
580
+
581
+ $ac.slideDown(50);
582
+ trigger('open');
583
+ });
584
+ }
585
+
586
+ function close() {
587
+ if (!trigger('close_before')) {
588
+ return;
589
+ }
590
+
591
+ $ac.empty().hide();
592
+ trigger('close');
593
+ }
594
+
595
+ function keySelect(event) {
596
+ var $active = $ac.find('li.active');
597
+
598
+ switch (event.which) {
599
+ case keys.up:
600
+ if ($active.length) {
601
+ $active.removeClass('active');
602
+ if ($active.prev().length) $active = $active.prev();
603
+ } else {
604
+ $active = $ac.find('li').last();
605
+ }
606
+
607
+ (function () {
608
+ var acScroll = $ac.scrollTop(),
609
+ acOffset = $ac.offset(),
610
+ activeHeight = $active.outerHeight(),
611
+ activeOffset = $active.offset();
612
+
613
+ if ((activeOffset.top - acOffset.top) < 0) {
614
+ $ac.scrollTop(acScroll - activeHeight);
615
+ }
616
+ })();
617
+
618
+ $active.addClass('active');
619
+ select();
620
+ break;
621
+
622
+ case keys.down:
623
+ if ($active.length) {
624
+ $active.removeClass('active');
625
+ if ($active.next().length) $active = $active.next();
626
+ } else {
627
+ $active = $ac.find('li').first();
628
+ }
629
+
630
+ (function () {
631
+ var acScroll = $ac.scrollTop(),
632
+ acHeight = $ac.height(),
633
+ acOffset = $ac.offset(),
634
+ activeHeight = $active.outerHeight(),
635
+ activeOffset = $active.offset();
636
+
637
+ if ((activeOffset.top - acOffset.top + activeHeight) > acHeight) {
638
+ $ac.scrollTop(acScroll + activeHeight);
639
+ }
640
+ })();
641
+
642
+ $active.addClass('active');
643
+ select();
644
+ break;
645
+
646
+ case keys.enter:
647
+ close();
648
+ break;
649
+ }
650
+ }
651
+
652
+ function mouseSelect(element) {
653
+ var $li = $(element);
654
+
655
+ if ($li.is('a')) {
656
+ $li = $li.parents('li');
657
+ }
658
+
659
+ $li.addClass('active');
660
+
661
+ select();
662
+ close();
663
+ }
664
+
665
+ function select() {
666
+ if (!trigger('select_before')) {
667
+ return;
668
+ }
669
+
670
+ var $a = $ac.find('.active a');
671
+ if (!$a.length) {
672
+ return;
673
+ }
674
+
675
+ $input
676
+ .val($a.attr('data-val'))
677
+ .data(triggerChangeFlag, true);
678
+
679
+ error(false);
680
+ setCurrent($a.data('kladr-object'));
681
+ trigger('select', get('current'));
682
+ }
683
+
684
+ function check() {
685
+ if (!get('verify')) {
686
+ return;
687
+ }
688
+
689
+ if (!trigger('check_before')) {
690
+ return;
691
+ }
692
+
693
+ var name = $.trim($input.val());
694
+
695
+ if (!name) {
696
+ ret(null, false);
697
+ return;
698
+ }
699
+
700
+ if (get('current')) {
701
+ error(false);
702
+ return;
703
+ }
704
+
705
+ var query = getQuery(name);
706
+
707
+ query.withParents = false;
708
+ query.limit = 10;
709
+
710
+ if (!trigger('send_before', query)) {
711
+ ret(null, false);
712
+ trigger('check', null);
713
+ return;
714
+ }
715
+
716
+ showSpinner();
717
+ trigger('send');
718
+
719
+ get('source')(query, function (objs) {
720
+ trigger('receive');
721
+
722
+ if (!$.trim($input.val())) {
723
+ ret2(null, false);
724
+ return;
725
+ }
726
+
727
+ var nameLowerCase = query.name.toLowerCase(),
728
+ valueLowerCase = null,
729
+ obj = null;
730
+
731
+ for (var i = 0; i < objs.length; i++) {
732
+ valueLowerCase = objs[i].name.toLowerCase();
733
+
734
+ if (nameLowerCase == valueLowerCase) {
735
+ obj = objs[i];
736
+ break;
737
+ }
738
+ }
739
+
740
+ if (obj) {
741
+ $input.val(get('valueFormat')(obj, query));
742
+ }
743
+
744
+ ret2(obj, !obj);
745
+ trigger('check', obj);
746
+
747
+ function ret2(obj, er) {
748
+ hideSpinner();
749
+ ret(obj, er);
750
+ }
751
+ });
752
+
753
+ function ret(obj, er) {
754
+ error(er);
755
+ setCurrent(obj);
756
+ }
757
+ }
758
+
759
+ function createController() {
760
+ var controller = {
761
+
762
+ setValue: function (value) {
763
+ if ($.type(value) === 'object') {
764
+ return controller.setValueByObject(value);
765
+ }
766
+
767
+ if ($.type(value) === 'number') {
768
+ return controller.setValueById(value);
769
+ }
770
+
771
+ if ($.type(value) === 'string') {
772
+ return controller.setValueByName(value);
773
+ }
774
+
775
+ if (!value) {
776
+ return controller.clear();
777
+ }
778
+
779
+ return controller;
780
+ },
781
+
782
+ setValueByName: function (name) {
783
+ name = $.trim(name + '');
784
+
785
+ if (name) {
786
+ var query = getQuery('');
787
+
788
+ query.name = fixName(name);
789
+ query.withParents = false;
790
+ query.limit = 10;
791
+
792
+ if (!trigger('send_before', query)) {
793
+ changeValue(null, query);
794
+ return controller;
795
+ }
796
+
797
+ lock();
798
+ trigger('send');
799
+
800
+ get('source')(query, function (objs) {
801
+ trigger('receive');
802
+
803
+ var nameLowerCase = query.name.toLowerCase(),
804
+ valueLowerCase = null,
805
+ obj = null;
806
+
807
+ for (var i = 0; i < objs.length; i++) {
808
+ valueLowerCase = objs[i].name.toLowerCase();
809
+
810
+ if (nameLowerCase == valueLowerCase) {
811
+ obj = objs[i];
812
+ break;
813
+ }
814
+ }
815
+
816
+ changeValue(obj, query);
817
+ });
818
+ }
819
+
820
+ return controller;
821
+ },
822
+
823
+ setValueById: function (id) {
824
+ var query = getQuery('');
825
+
826
+ query.parentType = query.type;
827
+ query.parentId = id;
828
+ query.limit = 1;
829
+
830
+ lock();
831
+
832
+ $.kladr.api(query, function (objs) {
833
+ objs.length
834
+ ? changeValue(objs[0], query)
835
+ : changeValue(null, query);
836
+ });
837
+
838
+ return controller;
839
+ },
840
+
841
+ setValueByObject: function (obj) {
842
+ changeValue(obj, getQuery(''));
843
+ return controller;
844
+ },
845
+
846
+ clear: function () {
847
+ changeValue(null, null);
848
+ return controller;
849
+ }
850
+ };
851
+
852
+ var lockAttr = 'data-kladr-autofill-lock';
853
+
854
+ function lock() {
855
+ $input.attr(lockAttr, true);
856
+ }
857
+
858
+ function changeValue(obj, query) {
859
+ $input.val(obj ? get('valueFormat')(obj, query) : '');
860
+ setCurrent(obj);
861
+ $input.removeAttr(lockAttr);
862
+ }
863
+
864
+ set('controller', controller);
865
+ }
866
+
867
+ function checkAutoFill() {
868
+ var count = 0;
869
+
870
+ (function test() {
871
+ if (++count > 5 || isFilled()) {
872
+ return;
873
+ }
874
+
875
+ setTimeout(test, 100);
876
+ })();
877
+
878
+ function isFilled() {
879
+ var name = $input.val();
880
+
881
+ if (name) {
882
+ var query = getQuery(name),
883
+ queryType = query.type,
884
+ queryParentType = query.parentType,
885
+ type = $.kladr.type,
886
+ parentFilled = true,
887
+ setByName = get('controller').setValueByName,
888
+ lock;
889
+
890
+ // Crutch for street input
891
+ if (queryType == type.street && queryParentType != type.city) {
892
+ parentFilled = false;
893
+ }
894
+
895
+ // Crutch for building input
896
+ if (queryType == type.building && !~$.inArray(queryParentType, [type.street, type.city])) {
897
+ parentFilled = false;
898
+ }
899
+
900
+ lock = $input.attr('data-kladr-autofill-lock');
901
+
902
+ lock && get('current') && parentFilled && setByName(name);
903
+ return !!get('current');
904
+ }
905
+
906
+ return false;
907
+ }
908
+ }
909
+
910
+ function trigger(event, obj) {
911
+ if (!event) {
912
+ return true;
913
+ }
914
+
915
+ var eventProp = event.replace(/_([a-z])/ig, function (all, letter) {
916
+ return letter.toUpperCase();
917
+ });
918
+
919
+ $input.trigger('kladr_' + event, obj);
920
+
921
+ if ($.type(get(eventProp)) === 'function') {
922
+ return get(eventProp).call($input.get(0), obj) !== false;
923
+ }
924
+
925
+ return true;
926
+ }
927
+
928
+ function showSpinner() {
929
+ if (get('spinner')) {
930
+ get('showSpinner')($spinner);
931
+ }
932
+ }
933
+
934
+ function hideSpinner() {
935
+ if (get('spinner')) {
936
+ get('hideSpinner')($spinner);
937
+ }
938
+ }
939
+
940
+ function getQuery(name) {
941
+ var query = {},
942
+ fields = [
943
+ 'token',
944
+ 'key',
945
+ 'type',
946
+ 'typeCode',
947
+ 'parentType',
948
+ 'parentId',
949
+ 'oneString',
950
+ 'withParents',
951
+ 'limit'
952
+ ],
953
+ i;
954
+
955
+ for (i = 0; i < fields.length; i++) {
956
+ query[fields[i]] = get(fields[i]);
957
+ }
958
+
959
+ query.name = fixName(name);
960
+
961
+ var parentInput = get('parentInput'),
962
+ parent;
963
+
964
+ if (parentInput) {
965
+ parent = getParent(parentInput, query.type);
966
+
967
+ if (parent) {
968
+ query.parentType = parent.type;
969
+ query.parentId = parent.id;
970
+ }
971
+ }
972
+
973
+ // one string search crutch
974
+ if (query.oneString) {
975
+ query.withParents = true;
976
+ }
977
+
978
+ return query;
979
+ }
980
+
981
+ function getParent(selector, type) {
982
+ var $inputs = $.kladr.getInputs(selector),
983
+ types = $.kladr.type,
984
+ parents = {},
985
+ parent = null,
986
+ t;
987
+
988
+ $inputs.each(function () {
989
+ var $this = $(this),
990
+ id;
991
+
992
+ if (id = $this.attr('data-kladr-id')) {
993
+ parents[$this.attr('data-kladr-type')] = id;
994
+ }
995
+ });
996
+
997
+ for (t in types) {
998
+ if (t == type) {
999
+ return parent;
1000
+ }
1001
+
1002
+ if (hasOwn(types, t) && parents[t]) {
1003
+ parent = {
1004
+ type: t,
1005
+ id: parents[t]
1006
+ }
1007
+ }
1008
+ }
1009
+
1010
+ return parent;
1011
+ }
1012
+
1013
+ function fixName(name) {
1014
+ var noCorrect = 'abcdefghijklmnopqrstuvwxyz',
1015
+ testName = name.toLowerCase();
1016
+
1017
+ for (var i = 0; i < testName.length; i++) {
1018
+ if (~noCorrect.indexOf(testName[i])) {
1019
+ error(true);
1020
+ return name;
1021
+ }
1022
+ }
1023
+
1024
+ error(false);
1025
+ return name;
1026
+ }
1027
+
1028
+ function setCurrent(obj) {
1029
+ var curr = get('current');
1030
+
1031
+ if ((curr && curr.id) === (obj && obj.id)) {
1032
+ return;
1033
+ }
1034
+
1035
+ set('current', obj);
1036
+
1037
+ if (obj && obj.id) {
1038
+ $input.attr('data-kladr-id', obj.id);
1039
+ } else {
1040
+ $input.removeAttr('data-kladr-id');
1041
+ }
1042
+
1043
+ if (get('oneString')) {
1044
+ if (obj && obj.contentType) {
1045
+ $input.attr('data-kladr-type', obj.contentType);
1046
+ }
1047
+ }
1048
+
1049
+ trigger('change', obj);
1050
+ }
1051
+
1052
+ function error(error) {
1053
+ error
1054
+ ? $input.addClass('kladr-error')
1055
+ : $input.removeClass('kladr-error');
1056
+ }
1057
+
1058
+ function get(param) {
1059
+ return options._get(param);
1060
+ }
1061
+
1062
+ function set(param, value) {
1063
+ options._set(param, value);
1064
+ }
1065
+ });
1066
+ }
1067
+
1068
+ function readParams(param1, param2) {
1069
+ var params = {
1070
+ obj: false,
1071
+ str: false,
1072
+ isGet: false
1073
+ };
1074
+
1075
+ if ($.type(param1) === 'object') {
1076
+ params.obj = param1;
1077
+ return params;
1078
+ }
1079
+
1080
+ if ($.type(param1) === 'string') {
1081
+ params.str = [param1, param2];
1082
+ params.isGet = (param2 === undefined);
1083
+ }
1084
+
1085
+ return params;
1086
+ }
1087
+
1088
+ function getGuid() {
1089
+ return getGuid.guid
1090
+ ? ++getGuid.guid
1091
+ : getGuid.guid = 1;
1092
+ }
1093
+
1094
+ function hasOwn(obj, property) {
1095
+ return obj.hasOwnProperty(property);
1096
+ }
1097
+ })(jQuery, window, document);