kladr-rails 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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);