biovision-base 0.8.170916 → 0.8.171029

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/biovision/base/placeholders/image.svg +3 -18
  3. data/app/assets/javascripts/biovision/base/biovision.js +228 -124
  4. data/app/assets/stylesheets/biovision/base/admin.scss +8 -7
  5. data/app/assets/stylesheets/biovision/base/biovision.scss +1 -1
  6. data/app/assets/stylesheets/biovision/base/default.scss +6 -3
  7. data/app/assets/stylesheets/biovision/base/default_admin.scss +30 -0
  8. data/app/assets/stylesheets/biovision/base/layout.scss +22 -14
  9. data/app/assets/stylesheets/biovision/base/message-box.scss +8 -1
  10. data/app/controllers/admin/regions_controller.rb +0 -9
  11. data/app/controllers/admin/users_controller.rb +2 -2
  12. data/app/controllers/authentication_controller.rb +4 -1
  13. data/app/controllers/concerns/toggleable_entity.rb +12 -3
  14. data/app/controllers/regions_controller.rb +1 -1
  15. data/app/helpers/biovision_users_helper.rb +18 -8
  16. data/app/models/region.rb +6 -1
  17. data/app/models/user.rb +3 -3
  18. data/app/models/user_profile.rb +8 -0
  19. data/app/services/canonizer.rb +9 -8
  20. data/app/views/admin/metrics/show.html.erb +20 -12
  21. data/app/views/admin/privileges/entity/_groups.html.erb +12 -10
  22. data/app/views/admin/regions/entity/_in_list.html.erb +1 -1
  23. data/app/views/admin/regions/show.html.erb +1 -1
  24. data/app/views/admin/users/_filter.html.erb +2 -14
  25. data/app/views/admin/users/index.html.erb +1 -1
  26. data/app/views/admin/users/privileges.html.erb +53 -38
  27. data/app/views/agents/_filter.html.erb +28 -28
  28. data/app/views/authentication/new.jbuilder +6 -0
  29. data/app/views/editable_pages/_editable_page.html.erb +6 -0
  30. data/app/views/editable_pages/form/_ckeditor.html.erb +3 -3
  31. data/app/views/layouts/admin.html.erb +1 -1
  32. data/app/views/my/recoveries/show.html.erb +1 -1
  33. data/app/views/shared/_breadcrumbs.html.erb +6 -0
  34. data/app/views/shared/_list_of_errors.html.erb +5 -9
  35. data/config/locales/common-ru.yml +22 -22
  36. data/config/locales/users-ru.yml +9 -0
  37. data/config/routes.rb +1 -1
  38. data/db/migrate/20170301000001_create_metrics.rb +1 -1
  39. data/db/migrate/20170301000002_create_metric_values.rb +1 -1
  40. data/db/migrate/20170301000101_create_browsers.rb +1 -1
  41. data/db/migrate/20170301000102_create_agents.rb +1 -1
  42. data/db/migrate/20170301000201_create_regions.rb +4 -1
  43. data/db/migrate/20170302000001_create_users.rb +2 -1
  44. data/db/migrate/20170302000003_create_tokens.rb +1 -1
  45. data/db/migrate/20170302000005_create_codes.rb +1 -1
  46. data/db/migrate/20170302000101_create_privileges.rb +1 -1
  47. data/db/migrate/20170302000102_create_user_privileges.rb +1 -1
  48. data/db/migrate/20170302000103_create_privilege_groups.rb +1 -1
  49. data/db/migrate/20170302000104_create_privilege_group_privileges.rb +1 -1
  50. data/db/migrate/20170320000000_create_editable_pages.rb +4 -1
  51. data/db/migrate/20170425000001_create_foreign_sites.rb +1 -1
  52. data/db/migrate/20170425000002_create_foreign_users.rb +1 -1
  53. data/db/migrate/20171025222222_add_new_fields_171026.rb +29 -0
  54. data/lib/biovision/base/engine.rb +5 -0
  55. data/lib/biovision/base/version.rb +1 -1
  56. metadata +8 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5cfc144ad5307b7e9d5d93dcbbb6f7d14eab5bb0
4
- data.tar.gz: 386e0f6f547aaef0befb3ad99f887f87dd533263
3
+ metadata.gz: 5a69729da19c47e5d87fe9296e687a6deace54a0
4
+ data.tar.gz: 81b91f26c62b8896b165d4a46fda4c82eaf017a2
5
5
  SHA512:
6
- metadata.gz: 1691ce1bf90cc9c6c36f0d6b5777ee955f80821de8bd983fb53c344300e4df20e26da20f0f997369bb6000f1ecf2833f5911babd54f594b01d516767181522af
7
- data.tar.gz: 07f2394d5f168f067cb749c10b16d371971dcac15753facc76246d4d4657ffd881f21429dd30160b4805b089de7bb4abf1ca551bc01805a90549bb30a334c38d
6
+ metadata.gz: 329c7b70ca3974fd53e319293cf1c6d229d2f22c7af228e4794a0a313bc4d560aec40af18f1ac18986517604b7bfdc16e222597333c9cb329700de9fd23954ed
7
+ data.tar.gz: 0667670c98830807dbe1b0243d8e6739e523790555725c70a7e7e5dd003c45ab9000fd38730366b66b0e0a4f31b770fe3ad4e7de465c98160aa8882e8b8ed34c
@@ -1,19 +1,4 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
- <!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
- <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
- <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
- width="480px" height="480px" viewBox="-216 -216 480 480" enable-background="new -216 -216 480 480" xml:space="preserve">
6
- <path d="M222.262,201.391H-174.26c-23.052,0-41.74-18.689-41.74-41.738v-271.304c0-23.05,18.688-41.74,41.74-41.74h396.521
7
- c23.051,0,41.738,18.689,41.738,41.74v271.304C264,182.701,245.312,201.391,222.262,201.391z M243.131-111.652
8
- c0-11.521-9.355-20.87-20.869-20.87H-174.26c-11.521,0-20.87,9.349-20.87,20.87v271.304c0,11.516,9.349,20.87,20.87,20.87h396.521
9
- c11.514,0,20.869-9.354,20.869-20.87V-111.652z M204.877,135.809l-66.094-66.096l-37.766,37.766l34.791,34.789
10
- c3.971,3.975,3.971,10.425,0,14.41c-3.985,3.973-10.436,3.973-14.41,0L-28.172,7.105l-128.703,128.703
11
- c-3.975,3.973-10.426,3.973-14.409,0c-3.98-3.985-3.98-10.436,0-14.41L-36.626-13.261c0.335-0.504,0.555-1.054,0.994-1.503
12
- c2.054-2.058,4.769-2.995,7.46-2.935c2.688-0.061,5.404,0.877,7.458,2.935c0.439,0.449,0.646,0.999,0.992,1.503L86.61,93.068
13
- l43.716-43.715c0.346-0.498,0.56-1.059,0.996-1.508c2.061-2.048,4.77-2.995,7.461-2.936c2.689-0.06,5.4,0.888,7.459,2.936
14
- c0.438,0.449,0.652,1.01,0.998,1.508l72.045,72.045c3.975,3.975,3.975,10.425,0,14.41
15
- C215.302,139.781,208.852,139.781,204.877,135.809z M76.174-28.173c-23.049,0-41.74-18.689-41.74-41.74
16
- c0-23.05,18.691-41.739,41.74-41.739c23.052,0,41.74,18.689,41.74,41.739C117.914-46.862,99.226-28.173,76.174-28.173z
17
- M76.174-90.783c-11.514,0-20.87,9.351-20.87,20.87c0,11.521,9.356,20.87,20.87,20.87s20.871-9.349,20.871-20.87
18
- C97.045-81.432,87.688-90.783,76.174-90.783z" fill="#aaa" />
19
- </svg>
2
+ <svg version="1.1" id="Layer_1" x="0px" y="0px" width="480px" height="360px" viewBox="0 0 479.9989929199219 360" enable-background="new -216 -216 480 480" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M 438.262 357.391 L 41.74 357.391 C 18.688 357.391 0 338.702 0 315.653 L 0 44.349 C 0 21.299 18.688 2.609 41.74 2.609 L 438.261 2.609 C 461.312 2.609 479.999 21.298 479.999 44.349 L 479.999 315.653 C 480 338.701 461.312 357.391 438.262 357.391 Z M 459.131 44.348 C 459.131 32.827 449.776 23.478 438.262 23.478 L 41.74 23.478 C 30.219 23.478 20.87 32.827 20.87 44.348 L 20.87 315.652 C 20.87 327.168 30.219 336.522 41.74 336.522 L 438.261 336.522 C 449.775 336.522 459.13 327.168 459.13 315.652 L 459.13 44.348 Z M 420.877 291.809 L 354.783 225.713 L 317.017 263.479 L 351.808 298.268 C 355.779 302.243 355.779 308.693 351.808 312.678 C 347.823 316.651 341.372 316.651 337.398 312.678 L 187.828 163.105 L 59.125 291.808 C 55.15 295.781 48.699 295.781 44.716 291.808 C 40.736 287.823 40.736 281.372 44.716 277.398 L 179.374 142.739 C 179.709 142.235 179.929 141.685 180.368 141.236 C 182.422 139.178 185.137 138.241 187.828 138.301 C 190.516 138.24 193.232 139.178 195.286 141.236 C 195.725 141.685 195.932 142.235 196.278 142.739 L 302.61 249.068 L 346.326 205.353 C 346.672 204.855 346.886 204.294 347.322 203.845 C 349.383 201.797 352.092 200.85 354.783 200.909 C 357.472 200.849 360.183 201.797 362.242 203.845 C 362.68 204.294 362.894 204.855 363.24 205.353 L 435.285 277.398 C 439.26 281.373 439.26 287.823 435.285 291.808 C 431.302 295.781 424.852 295.781 420.877 291.809 Z M 292.174 127.827 C 269.125 127.827 250.434 109.138 250.434 86.087 C 250.434 63.037 269.125 44.348 292.174 44.348 C 315.226 44.348 333.914 63.037 333.914 86.087 C 333.914 109.138 315.226 127.827 292.174 127.827 Z M 292.174 65.217 C 280.66 65.217 271.304 74.568 271.304 86.087 C 271.304 97.608 280.66 106.957 292.174 106.957 C 303.688 106.957 313.045 97.608 313.045 86.087 C 313.045 74.568 303.688 65.217 292.174 65.217 Z" fill="#aaa"/>
4
+ </svg>
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- let Biovision = {
3
+ const Biovision = {
4
4
  storage: {
5
5
  available: function (type) {
6
6
  try {
@@ -77,23 +77,58 @@ let Biovision = {
77
77
  }
78
78
  }
79
79
  },
80
- new_ajax_request: function(method, url, on_load, on_error) {
80
+ new_ajax_request: function (method, url, on_success, on_failure) {
81
81
  const request = new XMLHttpRequest();
82
82
 
83
- request.addEventListener('load', on_load);
84
- request.addEventListener('error', on_error || Biovision.handle_ajax_failure);
85
- request.open(method, url);
83
+ request.addEventListener('load', function () {
84
+ if (this.status >= 200 && this.status < 400) {
85
+ if (on_success) {
86
+ on_success.call(this);
87
+ }
88
+ } else {
89
+ (on_failure || Biovision.handle_ajax_failure).call(this);
90
+ }
91
+ });
92
+ request.addEventListener('error', function () {
93
+ console.log(this);
94
+ });
95
+
96
+ request.open(method.toUpperCase(), url);
86
97
  request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
87
98
  request.setRequestHeader('X-CSRF-Token', Biovision.csrf_token);
88
99
 
89
100
  return request;
90
101
  },
91
- handle_ajax_failure: function(response) {
102
+ handle_ajax_failure: function (response) {
103
+ console.log(this);
92
104
  if (response.hasOwnProperty('responseJSON')) {
93
105
  console.log(response['responseJSON']);
94
106
  } else {
95
107
  console.log(response);
96
108
  }
109
+ },
110
+ transliterate: function(input) {
111
+ const char_map = {
112
+ 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd',
113
+ 'е': 'e', 'ё': 'yo', 'ж': 'zh', 'з': 'z', 'и': 'i',
114
+ 'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm', 'н': 'n',
115
+ 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't',
116
+ 'у': 'u', 'ф': 'f', 'х': 'kh', 'ц': 'c', 'ч': 'ch',
117
+ 'ш': 'sh', 'щ': 'shh', 'ъ': '', 'ы': 'y', 'ь': '',
118
+ 'э': 'e', 'ю': 'yu', 'я': 'ya'
119
+ };
120
+ let string = input.toLowerCase();
121
+
122
+ for (let index in char_map) {
123
+ if (char_map.hasOwnProperty(index)) {
124
+ string = string.replace(new RegExp(index, 'g'), char_map[index]);
125
+ }
126
+ }
127
+ string = string.replace(/[^-a-z0-9_.]/g, '-');
128
+ string = string.replace(/^[-_.]*([-a-z0-9_.]*[a-z0-9]+)[-_.]*$/, '$1');
129
+ string = string.replace(/--+/g, '-');
130
+
131
+ return string;
97
132
  }
98
133
  };
99
134
 
@@ -109,150 +144,200 @@ document.addEventListener('DOMContentLoaded', function () {
109
144
  }
110
145
  });
111
146
 
112
- $(document).on('click', 'div.toggleable > span', function () {
113
- if (!$(this).hasClass('switch')) {
114
- let $flag = $(this);
115
- let url = $(this).parent().data('url');
116
- let parameter = $(this).data('flag');
117
-
118
- $.post({
119
- url: url,
120
- data: {parameter: parameter},
121
- beforeSend: function () {
122
- $flag.removeClass();
123
- $flag.addClass('switch');
124
- },
125
- success: function (response) {
126
- $flag.removeClass();
127
- if (response.hasOwnProperty('data') && response['data'].hasOwnProperty(parameter)) {
147
+ document.addEventListener('click', function (event) {
148
+ const element = event.target;
149
+
150
+ // Выбор результата поиска пользователей в админке
151
+ if (element.matches('.user-search .results li')) {
152
+ const container = element.closest('.user-search');
153
+ const target = document.getElementById(container.getAttribute('data-target'));
154
+
155
+ target.value = element.getAttribute('data-id');
156
+ }
157
+
158
+ // Запирание/отпирание сущности (иконка с замком)
159
+ if (element.matches('li.lock > a img')) {
160
+ event.preventDefault();
161
+
162
+ const container = element.closest('li');
163
+ const button = element.closest('a');
164
+ const lockable = container.parentNode.querySelectorAll('.lockable');
165
+ const url = container.getAttribute('data-url');
166
+
167
+ if (url.length > 1) {
168
+ const method = button.classList.contains('lock') ? 'PUT' : 'DELETE';
169
+
170
+ const request = Biovision.new_ajax_request(method, url, function () {
171
+ const response = JSON.parse(this.responseText);
172
+
173
+ if (response.hasOwnProperty('data') && response['data'].hasOwnProperty('locked')) {
174
+ const locked = response['data']['locked'];
175
+
176
+ if (locked) {
177
+ lockable.forEach(function (button) {
178
+ button.classList.add('hidden')
179
+ });
180
+ } else {
181
+ lockable.forEach(function (button) {
182
+ button.classList.remove('hidden')
183
+ });
184
+ }
185
+
186
+ container.querySelectorAll('a').forEach(function (button) {
187
+ const classes = button.classList;
188
+
189
+ if (classes.contains('lock')) {
190
+ locked ? classes.add('hidden') : classes.remove('hidden');
191
+ } else {
192
+ locked ? classes.remove('hidden') : classes.add('hidden');
193
+ }
194
+ });
195
+ }
196
+ });
197
+
198
+ request.send();
199
+ }
200
+ }
201
+
202
+ // Переключение флагов сущности
203
+ if (element.matches('div.toggleable > span')) {
204
+ if (!element.classList.contains('switch')) {
205
+ const url = element.parentNode.getAttribute('data-url');
206
+ const parameter = element.getAttribute('data-flag');
207
+
208
+ const on_success = function() {
209
+ const response = JSON.parse(this.responseText);
210
+
211
+ if (response.hasOwnProperty('data')) {
128
212
  switch (response['data'][parameter]) {
129
213
  case true:
130
- $flag.addClass('active');
214
+ element.className = 'active';
131
215
  break;
132
216
  case false:
133
- $flag.addClass('inactive');
217
+ element.className = 'inactive';
134
218
  break;
135
219
  default:
136
- $flag.addClass('unknown');
220
+ element.className = 'unknown';
137
221
  }
138
222
  } else {
139
- $flag.addClass('unknown');
223
+ element.className = 'unknown';
140
224
  }
141
- }
142
- }).fail(function (response) {
143
- $flag.removeClass();
144
- $flag.addClass('unknown');
145
- handle_ajax_failure(response);
146
- });
147
- }
148
- });
225
+ };
149
226
 
150
- $(document).on('click', 'li.lock > a', function () {
151
- let $container = $(this).closest('li');
152
- let $edit = $container.parent().find('.lockable');
153
- let url = $container.data('url');
227
+ const on_failure = function() {
228
+ element.className = 'unknown';
229
+ Biovision.handle_ajax_failure.call(this);
230
+ };
154
231
 
155
- if (url.length > 1) {
156
- $.ajax(url, {
157
- method: $(this).hasClass('lock') ? 'put' : 'delete',
158
- success: function (response) {
159
- if (response.hasOwnProperty('data') && response['data'].hasOwnProperty('locked')) {
160
- let locked = response['data']['locked'];
232
+ const request = Biovision.new_ajax_request('POST', url, on_success, on_failure);
233
+ const data = new FormData();
234
+ data.append('parameter', parameter);
161
235
 
162
- locked ? $edit.addClass('hidden') : $edit.removeClass('hidden');
236
+ element.className = 'switch';
163
237
 
164
- $container.find('a').each(function () {
165
- if ($(this).hasClass('lock')) {
166
- locked ? $(this).addClass('hidden') : $(this).removeClass('hidden');
167
- } else {
168
- locked ? $(this).removeClass('hidden') : $(this).addClass('hidden');
169
- }
170
- });
171
- }
172
- }
173
- }).fail(handle_ajax_failure);
238
+ request.send(data);
239
+ }
174
240
  }
175
241
 
176
- return false;
177
- });
242
+ // Изменение порядка сортировки элементов
243
+ if (element.matches('li.priority-changer > button')) {
244
+ const delta = parseInt(element.getAttribute('data-delta'));
245
+ const url = element.parentNode.getAttribute('data-url');
246
+ let item = element.closest('li[data-number]');
178
247
 
179
- $(document).on('click', 'li.priority-changer > button', function () {
180
- let $li = $(this).closest('li[data-number]');
181
- let delta = parseInt(this.getAttribute('data-delta'));
182
- let url = $(this).parent().data('url');
248
+ if (parseInt(item.getAttribute('data-number')) + delta > 0) {
249
+ const on_success = function() {
250
+ const response = JSON.parse(this.responseText);
183
251
 
184
- if (parseInt($li.data('number')) + delta > 0) {
185
- $.post(url, {delta: delta}, function (response) {
186
- console.log(response);
187
- if (response.hasOwnProperty('data')) {
188
- let $container = $li.parent();
189
- let $list = $container.children('li');
252
+ if (response.hasOwnProperty('data')) {
253
+ const data = response.data;
254
+ const container = item.parentNode;
255
+ const list = Array.prototype.slice.call(container.children);
190
256
 
191
- if (response['data'].hasOwnProperty('priority')) {
192
- $li.data('number', response['data']['priority']);
193
- $li.attr('data-number', response['data']['priority']);
194
- } else {
195
- for (let entity_id in response['data']) {
196
- if (response['data'].hasOwnProperty(entity_id)) {
197
- $li = $container.find('li[data-id=' + entity_id + ']');
198
- $li.data('number', response['data'][entity_id]);
199
- $li.attr('data-number', response['data'][entity_id]);
257
+ if (data.hasOwnProperty('priority')) {
258
+ item.setAttribute('data-number', data.priority);
259
+ } else {
260
+ for (let entity_id in data) {
261
+ if (data.hasOwnProperty(entity_id)) {
262
+ item = container.querySelector('li[data-id="' + entity_id + '"]');
263
+ item.setAttribute('data-number', data[entity_id]);
264
+ }
200
265
  }
201
266
  }
267
+
268
+ list.sort(function (a, b) {
269
+ let an = parseInt(a.getAttribute('data-number'));
270
+ let bn = parseInt(b.getAttribute('data-number'));
271
+
272
+ if (an > bn) {
273
+ return 1;
274
+ } else if (an < bn) {
275
+ return -1;
276
+ } else {
277
+ return 0;
278
+ }
279
+ }).forEach(function(item) {
280
+ container.appendChild(item);
281
+ });
202
282
  }
203
- $list.sort(function (a, b) {
204
- let an = parseInt($(a).data('number'));
205
- let bn = parseInt($(b).data('number'));
206
-
207
- if (an > bn) {
208
- return 1;
209
- } else if (an < bn) {
210
- return -1;
211
- } else {
212
- return 0;
213
- }
214
- });
283
+ };
215
284
 
216
- $list.detach().appendTo($container);
217
- }
218
- }).fail(handle_ajax_failure);
285
+ const request = Biovision.new_ajax_request('POST', url, on_success);
286
+
287
+ const data = new FormData();
288
+ data.append('delta', delta);
289
+
290
+ request.send(data);
291
+ }
219
292
  }
220
293
  });
221
294
 
222
- $('div[data-destroy-url] button.destroy').on('click', function () {
223
- let $button = $(this);
224
- let $container = $(this).closest('div[data-destroy-url]');
295
+ // Кнопка поиска пользователя в админке
296
+ document.querySelectorAll('.user-search button').forEach(function (element) {
297
+ element.addEventListener('click', function () {
298
+ const container = this.closest('.user-search');
299
+ const input = container.querySelector('input[type=search]');
300
+ const url = container.getAttribute('data-url') + '?q=' + encodeURIComponent(input.value);
225
301
 
226
- $button.attr('disabled', true);
302
+ const request = Biovision.new_ajax_request('GET', url, function () {
303
+ const response = JSON.parse(this.responseText);
304
+ const results = container.querySelector('.results');
227
305
 
228
- $.ajax($container.data('destroy-url'), {
229
- method: 'delete',
230
- success: function (response) {
231
- $container.remove();
232
- }
233
- }).fail(handle_ajax_failure);
306
+ if (response.hasOwnProperty('data')) {
307
+ results.innerHTML = response['data']['html'];
308
+ }
309
+ });
310
+
311
+ request.send();
312
+ });
234
313
  });
235
314
 
236
- $('.user-search button').on('click', function () {
237
- let $container = $(this).closest('.user-search');
238
- let $input = $container.find('input[type=search]');
239
- let $results = $container.find('.results');
315
+ // Кнопка удаления элемента через AJAX
316
+ document.querySelectorAll('div[data-destroy-url] button.destroy').forEach(function (element) {
317
+ element.addEventListener('click', function () {
318
+ const container = this.closest('div[data-destroy-url]');
319
+ const url = container.getAttribute('data-destroy-url');
320
+ const request = Biovision.new_ajax_request('DELETE', url, function () {
321
+ container.remove();
322
+ });
240
323
 
241
- $.get($container.data('url'), {q: $input.val()}, function (response) {
242
- if (response.hasOwnProperty('data')) {
243
- $results.html(response['data']['html']);
244
- }
245
- }).fail(handle_ajax_failure);
324
+ this.setAttribute('disabled', 'true');
325
+ request.send();
326
+ });
246
327
  });
247
328
 
248
- $(document).on('click', '.user-search .results li', function () {
249
- let $container = $(this).closest('.user-search');
250
- let $target = $('#' + $container.data('target'));
329
+ document.querySelectorAll('[data-transliterate]').forEach(function (element) {
330
+ element.addEventListener('blur', function () {
331
+ const target = document.getElementById(element.getAttribute('data-transliterate'));
251
332
 
252
- $target.val($(this).data('id'));
333
+ if (target && target.value === '') {
334
+ target.value = Biovision.transliterate(element.value);
335
+ target.dispatchEvent(new Event('change'));
336
+ }
337
+ });
253
338
  });
254
339
 
255
- if (jQuery) {
340
+ if (typeof jQuery !== 'undefined') {
256
341
  jQuery.ajaxSetup({
257
342
  headers: {
258
343
  'X-CSRF-Token': Biovision.csrf_token
@@ -276,11 +361,11 @@ function handle_ajax_failure(response) {
276
361
  */
277
362
 
278
363
  /**
279
- * Element.closest()
364
+ * Element.matches()
280
365
  *
281
366
  * IE 9+
282
367
  *
283
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
368
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
284
369
  */
285
370
  if (!Element.prototype.matches) {
286
371
  Element.prototype.matches =
@@ -288,6 +373,13 @@ if (!Element.prototype.matches) {
288
373
  Element.prototype.webkitMatchesSelector;
289
374
  }
290
375
 
376
+ /**
377
+ * Element.closest()
378
+ *
379
+ * IE 9+
380
+ *
381
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
382
+ */
291
383
  if (!Element.prototype.closest) {
292
384
  Element.prototype.closest = function (s) {
293
385
  let el = this;
@@ -308,14 +400,26 @@ if (!Element.prototype.closest) {
308
400
  }
309
401
 
310
402
  /**
311
- * Element.matches()
403
+ * ChildNode.remove()
312
404
  *
313
405
  * IE 9+
314
406
  *
315
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
407
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
316
408
  */
317
- if (!Element.prototype.matches) {
318
- Element.prototype.matches =
319
- Element.prototype.msMatchesSelector ||
320
- Element.prototype.webkitMatchesSelector;
321
- }
409
+ (function (arr) {
410
+ arr.forEach(function (item) {
411
+ if (item.hasOwnProperty('remove')) {
412
+ return;
413
+ }
414
+ Object.defineProperty(item, 'remove', {
415
+ configurable: true,
416
+ enumerable: true,
417
+ writable: true,
418
+ value: function remove() {
419
+ if (this.parentNode !== null) {
420
+ this.parentNode.removeChild(this);
421
+ }
422
+ }
423
+ });
424
+ });
425
+ })([Element.prototype, CharacterData.prototype, DocumentType.prototype]);