biovision-base 0.22.180920.0 → 0.34.190331.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -21
- data/app/assets/images/biovision/base/icons/apply.svg +4 -0
- data/app/assets/images/biovision/base/icons/components/contact.svg +26 -0
- data/app/assets/images/biovision/base/icons/components/registration.svg +17 -0
- data/app/assets/images/biovision/base/icons/destroy.svg +11 -8
- data/app/assets/images/biovision/base/icons/settings.svg +41 -0
- data/app/assets/images/biovision/base/icons/slider/arrow-left.svg +4 -0
- data/app/assets/images/biovision/base/icons/slider/arrow-right.svg +4 -0
- data/app/assets/images/biovision/base/placeholders/16x9.svg +10 -3
- data/app/assets/images/biovision/base/placeholders/1x1.svg +12 -0
- data/app/assets/images/biovision/base/placeholders/3x2.svg +10 -3
- data/app/assets/javascripts/biovision/base/biovision.js +780 -461
- data/app/assets/javascripts/biovision/base/components/carousel.js +123 -0
- data/app/assets/javascripts/biovision/base/polyfills.js +149 -0
- data/app/assets/stylesheets/biovision/base/admin.scss +85 -46
- data/app/assets/stylesheets/biovision/base/admin/components.scss +141 -0
- data/app/assets/stylesheets/biovision/base/biovision.scss +149 -33
- data/app/assets/stylesheets/biovision/base/buttons/buttons-common.scss +22 -0
- data/app/assets/stylesheets/biovision/base/default.scss +6 -6
- data/app/assets/stylesheets/biovision/base/default_admin.scss +25 -8
- data/app/assets/stylesheets/biovision/base/themes/simple-layout.scss +0 -3
- data/app/controllers/admin/editable_pages_controller.rb +6 -4
- data/app/controllers/admin/privileges_controller.rb +2 -3
- data/app/controllers/admin/settings_controller.rb +52 -0
- data/app/controllers/admin/simple_blocks_controller.rb +28 -0
- data/app/controllers/admin/users_controller.rb +1 -1
- data/app/controllers/agents_controller.rb +4 -4
- data/app/controllers/authentication_controller.rb +28 -6
- data/app/controllers/browsers_controller.rb +4 -4
- data/app/controllers/concerns/authentication.rb +8 -5
- data/app/controllers/concerns/entity_priority.rb +3 -0
- data/app/controllers/concerns/lockable_entity.rb +6 -3
- data/app/controllers/concerns/removable_image.rb +4 -5
- data/app/controllers/concerns/toggleable_entity.rb +4 -5
- data/app/controllers/editable_pages_controller.rb +14 -8
- data/app/controllers/fallback_controller.rb +7 -2
- data/app/controllers/feedback_requests_controller.rb +23 -8
- data/app/controllers/metrics_controller.rb +3 -3
- data/app/controllers/my/profiles_controller.rb +32 -15
- data/app/controllers/privilege_groups_controller.rb +4 -4
- data/app/controllers/privileges_controller.rb +7 -26
- data/app/controllers/simple_blocks_controller.rb +63 -0
- data/app/controllers/stored_values_controller.rb +4 -4
- data/app/controllers/tokens_controller.rb +4 -4
- data/app/controllers/users_controller.rb +8 -3
- data/app/helpers/biovision_users_helper.rb +60 -21
- data/app/helpers/editable_pages_helper.rb +22 -0
- data/app/helpers/languages_helper.rb +3 -0
- data/app/helpers/simple_image_helper.rb +66 -0
- data/app/mailers/application_mailer.rb +0 -2
- data/app/mailers/code_sender.rb +13 -2
- data/app/mailers/feedback_mailer.rb +5 -2
- data/app/mailers/user_mailer.rb +6 -1
- data/app/models/biovision_component.rb +43 -0
- data/app/models/biovision_parameter.rb +34 -0
- data/app/models/code.rb +22 -7
- data/app/models/code_type.rb +9 -1
- data/app/models/concerns/flat_priority.rb +50 -0
- data/app/models/concerns/nested_priority.rb +58 -0
- data/app/models/concerns/required_unique_slug.rb +5 -2
- data/app/models/editable_page.rb +49 -37
- data/app/models/foreign_site.rb +5 -3
- data/app/models/language.rb +15 -37
- data/app/models/metric.rb +2 -4
- data/app/models/privilege.rb +23 -45
- data/app/models/privilege_group.rb +6 -1
- data/app/models/simple_block.rb +66 -0
- data/app/models/user.rb +29 -26
- data/app/models/user_privilege.rb +1 -1
- data/app/services/biovision/components/base_component.rb +115 -0
- data/app/services/biovision/components/registration_component.rb +98 -0
- data/app/services/code_manager.rb +4 -1
- data/app/services/code_manager/confirmation.rb +8 -4
- data/app/services/code_manager/invitation.rb +9 -5
- data/app/services/code_manager/recovery.rb +9 -6
- data/app/services/user_manager.rb +5 -4
- data/app/services/user_profile_handler.rb +38 -11
- data/app/uploaders/avatar_uploader.rb +5 -1
- data/app/uploaders/editable_page_image_uploader.rb +4 -6
- data/app/uploaders/media_file_uploader.rb +6 -4
- data/app/uploaders/media_snapshot_uploader.rb +6 -2
- data/app/uploaders/simple_file_uploader.rb +12 -0
- data/app/uploaders/simple_image_uploader.rb +75 -0
- data/app/views/about/editable.html.erb +1 -1
- data/app/views/admin/agents/_filter.html.erb +1 -1
- data/app/views/admin/editable_pages/entity/_in_list.html.erb +16 -0
- data/app/views/admin/editable_pages/index.html.erb +8 -1
- data/app/views/admin/editable_pages/show.html.erb +21 -17
- data/app/views/admin/feedback_requests/entity/_in_list.html.erb +9 -1
- data/app/views/admin/index/_biovision_base.html.erb +5 -7
- data/app/views/admin/index/_components.html.erb +9 -0
- data/app/views/admin/index/dashboard/_editorial.html.erb +2 -2
- data/app/views/admin/index/dashboard/_settings.html.erb +2 -2
- data/app/views/admin/index/index.html.erb +2 -0
- data/app/views/admin/privileges/entity/_groups.html.erb +25 -25
- data/app/views/admin/privileges/entity/_in_list.html.erb +30 -9
- data/app/views/admin/privileges/index.html.erb +6 -1
- data/app/views/admin/privileges/show.html.erb +31 -18
- data/app/views/admin/settings/component/_new_parameter.html.erb +62 -0
- data/app/views/admin/settings/component/_parameters.html.erb +37 -0
- data/app/views/admin/settings/component/_setting.html.erb +18 -0
- data/app/views/admin/settings/component/_settings.html.erb +31 -0
- data/app/views/admin/settings/index.html.erb +27 -0
- data/app/views/admin/settings/show.html.erb +42 -0
- data/app/views/admin/simple_blocks/_nav_item.html.erb +6 -0
- data/app/views/admin/simple_blocks/entity/_in_list.html.erb +23 -0
- data/app/views/admin/simple_blocks/index.html.erb +21 -0
- data/app/views/admin/simple_blocks/show.html.erb +51 -0
- data/app/views/admin/tokens/_filter.html.erb +1 -1
- data/app/views/admin/users/_filter.html.erb +1 -1
- data/app/views/admin/users/entity/_privilege.html.erb +12 -21
- data/app/views/admin/users/entity/_privilege_tree.html.erb +17 -15
- data/app/views/admin/users/privileges.html.erb +9 -1
- data/app/views/admin/users/search.jbuilder +3 -3
- data/app/views/admin/users/show.html.erb +11 -6
- data/app/views/agents/_filter.html.erb +22 -22
- data/app/views/agents/_form.html.erb +25 -29
- data/app/views/application/forbidden.html.erb +9 -0
- data/app/views/application/forbidden.jbuilder +3 -0
- data/app/views/authentication/_form.html.erb +13 -13
- data/app/views/browsers/_form.html.erb +21 -25
- data/app/views/editable_blocks/_entity.html.erb +4 -1
- data/app/views/editable_pages/_form.html.erb +63 -62
- data/app/views/editable_pages/edit.html.erb +1 -1
- data/app/views/editable_pages/entity/_metadata.html.erb +4 -4
- data/app/views/editable_pages/new.html.erb +3 -3
- data/app/views/fallback/show.html.erb +8 -1
- data/app/views/feedback_requests/_form.html.erb +76 -52
- data/app/views/feedback_requests/create.js.erb +1 -10
- data/app/views/index/index/_editable.html.erb +0 -4
- data/app/views/metrics/_form.html.erb +38 -36
- data/app/views/my/confirmations/show.html.erb +5 -3
- data/app/views/my/profiles/closed.html.erb +7 -0
- data/app/views/my/profiles/edit/_form.html.erb +9 -9
- data/app/views/my/profiles/new.html.erb +9 -1
- data/app/views/my/profiles/new/_form.html.erb +22 -1
- data/app/views/my/recoveries/show.html.erb +2 -2
- data/app/views/privilege_groups/_form.html.erb +48 -21
- data/app/views/privileges/_form.html.erb +68 -36
- data/app/views/profiles/_profile.html.erb +3 -3
- data/app/views/shared/_pagination.jbuilder +7 -5
- data/app/views/shared/admin/_breadcrumbs.html.erb +1 -1
- data/app/views/shared/forms/_meta_texts.html.erb +3 -3
- data/app/views/shared/forms/_priority.html.erb +12 -0
- data/app/views/shared/forms/_state_container.html.erb +1 -0
- data/app/views/simple_blocks/_empty.html.erb +0 -0
- data/app/views/simple_blocks/_form.html.erb +120 -0
- data/app/views/simple_blocks/_simple_block.html.erb +26 -0
- data/app/views/simple_blocks/edit.html.erb +17 -0
- data/app/views/simple_blocks/new.html.erb +15 -0
- data/app/views/stored_values/_form.html.erb +57 -28
- data/app/views/tokens/_form.html.erb +31 -26
- data/app/views/users/_form.html.erb +1 -1
- data/config/initializers/carrierwave.rb +7 -2
- data/config/locales/common-ru.yml +5 -0
- data/config/locales/components-ru.yml +50 -0
- data/config/locales/editable-pages-en.yml +2 -0
- data/config/locales/editable-pages-ru.yml +50 -7
- data/config/locales/editable-pages-sv.yml +2 -0
- data/config/locales/feedback-ru.yml +1 -0
- data/config/locales/users-en.yml +0 -1
- data/config/locales/users-ru.yml +6 -1
- data/config/locales/users-sv.yml +0 -1
- data/config/routes.rb +32 -6
- data/db/migrate/20181217000000_create_biovision_components.rb +80 -0
- data/db/migrate/20181217000010_create_metrics.rb +40 -0
- data/db/migrate/20181217000015_create_browsers.rb +38 -0
- data/db/migrate/20181217000020_create_languages.rb +30 -0
- data/db/migrate/20181217000030_create_users.rb +118 -0
- data/db/migrate/20181217000035_create_codes.rb +51 -0
- data/db/migrate/20181217000040_create_privileges.rb +142 -0
- data/db/migrate/20181217000100_create_media_folders.rb +53 -0
- data/db/migrate/20181217000110_create_editable_pages.rb +90 -0
- data/db/migrate/20181217000200_create_feedback_requests.rb +27 -0
- data/db/migrate/20181217121211_add_uuid_to_users.rb +12 -0
- data/db/migrate/20181217121212_update_fields181217.rb +29 -0
- data/db/migrate/20190311121212_convert_json_columns.rb +47 -0
- data/db/migrate/20190324181818_add_data_to_feedback_requests.rb +14 -0
- data/db/migrate/20190326120000_create_simple_blocks.rb +31 -0
- data/db/{migrate → obsolete_migrations}/20171223333333_amend_foreign_keys.rb +0 -0
- data/db/{migrate → obsolete_migrations}/20180117151515_add_language_to_models.rb +0 -0
- data/db/{migrate → obsolete_migrations}/20180321000000_add_profile_data_to_users.rb +4 -4
- data/db/{migrate → obsolete_migrations}/20180405000000_add_consent_to_users.rb +0 -0
- data/db/{migrate → obsolete_migrations}/20180610222222_add_consent_to_feedback_requests.rb +0 -0
- data/db/{migrate → obsolete_migrations}/20180612111111_add_administrative_to_privilege.rb +0 -0
- data/db/{migrate → obsolete_migrations}/20180619121212_add_image_alt_text_to_editable_page.rb +0 -0
- data/db/{migrate → obsolete_migrations}/20180703111111_add_fields_to_editable_blocks.rb +0 -0
- data/db/{migrate → obsolete_migrations}/20180722222222_add_active_to_languages.rb +0 -0
- data/db/{migrate → obsolete_migrations}/20180725111111_add_referral_link_to_users.rb +0 -0
- data/db/obsolete_migrations/20181012222222_add_deletable_to_privileges.rb +19 -0
- data/db/obsolete_migrations/20181012222223_convert_stored_values.rb +13 -0
- data/db/obsolete_migrations/20181030080808_update_editable_pages_meta.rb +20 -0
- data/lib/biovision/base/base_methods.rb +19 -2
- data/lib/biovision/base/version.rb +3 -1
- data/lib/tasks/users.rake +19 -1
- metadata +75 -40
- data/app/views/admin/privileges/_list.html.erb +0 -15
- data/db/migrate/20170228000000_create_languages.rb +0 -23
- data/db/migrate/20170301000001_create_metrics.rb +0 -23
- data/db/migrate/20170301000002_create_metric_values.rb +0 -19
- data/db/migrate/20170301000101_create_browsers.rb +0 -22
- data/db/migrate/20170301000102_create_agents.rb +0 -22
- data/db/migrate/20170302000001_create_users.rb +0 -55
- data/db/migrate/20170302000003_create_tokens.rb +0 -23
- data/db/migrate/20170302000004_create_code_types.rb +0 -20
- data/db/migrate/20170302000005_create_codes.rb +0 -24
- data/db/migrate/20170302000101_create_privileges.rb +0 -41
- data/db/migrate/20170302000102_create_user_privileges.rb +0 -18
- data/db/migrate/20170302000103_create_privilege_groups.rb +0 -23
- data/db/migrate/20170302000104_create_privilege_group_privileges.rb +0 -24
- data/db/migrate/20170320000000_create_editable_pages.rb +0 -52
- data/db/migrate/20170425000001_create_foreign_sites.rb +0 -18
- data/db/migrate/20170425000002_create_foreign_users.rb +0 -23
- data/db/migrate/20170629120000_create_login_attempts.rb +0 -19
- data/db/migrate/20170823000001_create_stored_values.rb +0 -19
- data/db/migrate/20171202000000_create_media_folders.rb +0 -28
- data/db/migrate/20171202000001_create_media_files.rb +0 -27
- data/db/migrate/20171211000000_create_feedback_requests.rb +0 -33
- data/db/migrate/20180117160000_create_user_languages.rb +0 -17
- data/db/migrate/20180622140000_create_link_blocks.rb +0 -29
- data/db/migrate/20180622140001_create_link_block_items.rb +0 -23
- data/db/migrate/20180627190000_create_editable_blocks.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eaab273faa85e0bc922a32b591fa239f57f78d3391554d304afb1e1a32d60285
|
4
|
+
data.tar.gz: f8e5837fdf1922adf3e6acaca5801de5e3f4d483ca8ef6c124a3382e1a1d7330
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ee9f0baf217333f237339d555681d334c37cf27d9a822b92e6f1e0bc15fe4b3c654ba73b79bece91b97a80d3226d70cfe33c334323f5b6b18ebc764a0cc079b
|
7
|
+
data.tar.gz: 17bb0eef033b0bffe97faa5e4cb4eafefc177a592062298680caa67b286332b1f47cc925928cd9bf78fc48f34a331d48b93e8decfafc7bb4ab3571968bd4ea11
|
data/README.md
CHANGED
@@ -5,7 +5,8 @@ Biovision::Base
|
|
5
5
|
|
6
6
|
Используйте на свой страх и риск без каких-либо гарантий работоспособности.
|
7
7
|
|
8
|
-
Описание необходимых и рекомендуемых действий находится
|
8
|
+
Описание необходимых и рекомендуемых действий находится
|
9
|
+
в [setup.md](https://github.com/Biovision/biovision-base/blob/master/setup.md)
|
9
10
|
|
10
11
|
Очистка устаревших сессий
|
11
12
|
-------------------------
|
@@ -30,7 +31,7 @@ Biovision::Base
|
|
30
31
|
Параметры, которые можно задать через data-атрибуты:
|
31
32
|
|
32
33
|
* `delay` — задержка перед пролистыванием. По умолчанию — `125` (мс)
|
33
|
-
* `type` — тип. По умолчанию — `opacity` (
|
34
|
+
* `type` — тип. По умолчанию — `opacity` (есть ещё `slide`).
|
34
35
|
|
35
36
|
```html
|
36
37
|
<div class="biovision-slider" data-delay="250" data-type="opacity">
|
@@ -85,31 +86,14 @@ Biovision::Base
|
|
85
86
|
который проверяется.
|
86
87
|
|
87
88
|
4. Рядом с элементом нужно добавить `div` с атрибутом `data-field` и таким же
|
88
|
-
значением, а также классом `check-result-error
|
89
|
+
значением, а также классом `check-result-error`.
|
89
90
|
|
90
91
|
Пример — [app/views/my/profiles/new/_form.html.erb](https://github.com/Biovision/biovision-base/blob/master/app/views/my/profiles/new/_form.html.erb),
|
91
92
|
[app/controllers/users_controller.rb#check](https://github.com/Biovision/biovision-base/blob/master/app/controllers/users_controller.rb#L8),
|
92
93
|
[app/views/users/check.jbuilder](https://github.com/Biovision/biovision-base/blob/master/app/views/users/check.jbuilder)
|
93
94
|
|
94
|
-
## Installation
|
95
|
-
Add this line to your application's Gemfile:
|
96
|
-
|
97
|
-
```ruby
|
98
|
-
gem 'biovision-base'
|
99
|
-
```
|
100
|
-
|
101
|
-
And then execute:
|
102
|
-
```bash
|
103
|
-
$ bundle
|
104
|
-
```
|
105
|
-
|
106
|
-
Or install it yourself as:
|
107
|
-
```bash
|
108
|
-
$ gem install biovision-base
|
109
|
-
```
|
110
|
-
|
111
95
|
## Contributing
|
112
|
-
|
96
|
+
Fork, update, make pull request.
|
113
97
|
|
114
98
|
## License
|
115
99
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24px" height="24px" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<title>Contact</title>
|
3
|
+
<defs>
|
4
|
+
<style type="text/css">
|
5
|
+
* { stroke-width: 1; }
|
6
|
+
.a { stroke: #777; }
|
7
|
+
.b { stroke: #555; }
|
8
|
+
.c { fill: #3aa; }
|
9
|
+
line { stroke-linecap: round; }
|
10
|
+
</style>
|
11
|
+
</defs>
|
12
|
+
<g class="a">
|
13
|
+
<rect x="1" y="1" width="15" height="10" fill="#fff"/>
|
14
|
+
<polyline points="1,1 9,5 16,1" fill="none"/>
|
15
|
+
</g>
|
16
|
+
<g class="b">
|
17
|
+
<rect x="7" y="6" width="10" height="17" rx="2" fill="#eee"/>
|
18
|
+
<line x1="10" y1="8" x2="14" y2="8" />
|
19
|
+
<circle cx="12.25" cy="21" r=".5"/>
|
20
|
+
<rect x="8" y="9.5" width="8.125" height="10" rx="1" ry="1" fill="#555" stroke="none" />
|
21
|
+
</g>
|
22
|
+
<g class="c">
|
23
|
+
<path d="M20,24 l-3.5,-8 q4,-8 7,0 z"/>
|
24
|
+
<circle cx="20.125" cy="15.25" r="1.5" fill="#f7a"/>
|
25
|
+
</g>
|
26
|
+
</svg>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24px" height="24px" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<title>Registration</title>
|
3
|
+
<defs>
|
4
|
+
<style type="text/css">
|
5
|
+
.a { stroke-width: 2; stroke: #3a3; stroke-linecap: round; }
|
6
|
+
.b { stroke-width: 1.5; stroke: #333; fill: #eee; }
|
7
|
+
</style>
|
8
|
+
</defs>
|
9
|
+
<g class="a">
|
10
|
+
<line x1="5" y1="2" x2="5" y2="8"/>
|
11
|
+
<line x1="2" y1="5" x2="8" y2="5"/>
|
12
|
+
</g>
|
13
|
+
<g class="b">
|
14
|
+
<ellipse cx="12.5" cy="10" rx="3.5" ry="4.5"/>
|
15
|
+
<path d="M3,22 Q12,11 22,22 z" stroke-linejoin="round"/>
|
16
|
+
</g>
|
17
|
+
</svg>
|
@@ -1,9 +1,12 @@
|
|
1
|
-
|
2
|
-
<
|
3
|
-
<
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
<svg version="1.1" viewBox="0 0 24 24" width="24px" height="24px" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<title>Delete</title>
|
3
|
+
<defs>
|
4
|
+
<style type="text/css">
|
5
|
+
line { stroke: #e44061; stroke-width: 3; stroke-linecap: round; }
|
6
|
+
</style>
|
7
|
+
</defs>
|
8
|
+
<g>
|
9
|
+
<line x1="3" y1="3" x2="21" y2="21"/>
|
10
|
+
<line x1="3" y1="21" x2="21" y2="3"/>
|
8
11
|
</g>
|
9
|
-
</svg>
|
12
|
+
</svg>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="160px" height="160px">
|
2
|
+
<title>Settings</title>
|
3
|
+
<defs>
|
4
|
+
<style>
|
5
|
+
line { stroke-linecap: round }
|
6
|
+
circle { stroke-width: 3 }
|
7
|
+
.a { stroke-width: 15; stroke: #aaa }
|
8
|
+
.b { stroke-width: 5; stroke: #777 }
|
9
|
+
.c { fill: #bbb; stroke: #999 }
|
10
|
+
.d { stroke-width: 3; stroke: #444; fill: #777 }
|
11
|
+
</style>
|
12
|
+
</defs>
|
13
|
+
<g>
|
14
|
+
<g class="a">
|
15
|
+
<line x1="20" y1="10" x2="20" y2="150"/>
|
16
|
+
<line x1="60" y1="10" x2="60" y2="150"/>
|
17
|
+
<line x1="100" y1="10" x2="100" y2="150"/>
|
18
|
+
</g>
|
19
|
+
<g class="b">
|
20
|
+
<line x1="20" y1="10" x2="20" y2="150"/>
|
21
|
+
<line x1="60" y1="10" x2="60" y2="150"/>
|
22
|
+
<line x1="100" y1="10" x2="100" y2="150"/>
|
23
|
+
</g>
|
24
|
+
<g class="c">
|
25
|
+
<circle cx="20" cy="55" r="15"/>
|
26
|
+
<circle cx="60" cy="115" r="15"/>
|
27
|
+
<circle cx="100" cy="30" r="15"/>
|
28
|
+
</g>
|
29
|
+
</g>
|
30
|
+
<g>
|
31
|
+
<g>
|
32
|
+
<circle cx="140" cy="20" r="12" stroke="#070" fill="#4a4"/>
|
33
|
+
<circle cx="140" cy="60" r="12" stroke="#440" fill="#773"/>
|
34
|
+
<circle cx="140" cy="100" r="12" stroke="#400" fill="#733"/>
|
35
|
+
</g>
|
36
|
+
<g class="d">
|
37
|
+
<circle cx="140" cy="140" r="12"/>
|
38
|
+
<polyline points="130,140 126,126 140,130"/>
|
39
|
+
</g>
|
40
|
+
</g>
|
41
|
+
</svg>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<svg version="1.1" viewBox="0 0 12 36" width="12px" height="36px" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<title>Left arrow (wide)</title>
|
3
|
+
<polyline points="10,2 2,18 10,34" stroke="#777" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
4
|
+
</svg>
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<svg version="1.1" viewBox="0 0 12 36" width="12px" height="36px" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<title>Right arrow (wide)</title>
|
3
|
+
<polyline points="2,2 10,18 2,34" stroke="#777" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
4
|
+
</svg>
|
@@ -1,5 +1,12 @@
|
|
1
1
|
<svg version="1.1" viewBox="0 0 320 180" width="320px" height="180px" xmlns="http://www.w3.org/2000/svg">
|
2
|
-
<
|
3
|
-
<
|
4
|
-
|
2
|
+
<title>Image placeholder 16×9</title>
|
3
|
+
<style>
|
4
|
+
* { stroke: #777; fill: none; }
|
5
|
+
line { stroke-width: 3; }
|
6
|
+
</style>
|
7
|
+
<g>
|
8
|
+
<rect x="1" y="1" width="317" height="177" stroke-width="4"/>
|
9
|
+
<line x1="1" y1="1" x2="319" y2="179"/>
|
10
|
+
<line x1="1" y1="179" x2="319" y2="1"/>
|
11
|
+
</g>
|
5
12
|
</svg>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<svg version="1.1" viewBox="0 0 300 300" width="300px" height="300px" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<title>Image placeholder 1×1</title>
|
3
|
+
<style>
|
4
|
+
* { stroke: #777; fill: none; }
|
5
|
+
line { stroke-width: 3; }
|
6
|
+
</style>
|
7
|
+
<g>
|
8
|
+
<rect x="1" y="1" width="297" height="297" stroke-width="4"/>
|
9
|
+
<line x1="1" y1="1" x2="299" y2="299"/>
|
10
|
+
<line x1="1" y1="299" x2="299" y2="1"/>
|
11
|
+
</g>
|
12
|
+
</svg>
|
@@ -1,5 +1,12 @@
|
|
1
1
|
<svg version="1.1" viewBox="0 0 300 200" width="300px" height="200px" xmlns="http://www.w3.org/2000/svg">
|
2
|
-
<
|
3
|
-
<
|
4
|
-
|
2
|
+
<title>Image placeholder 3×2</title>
|
3
|
+
<style>
|
4
|
+
* { stroke: #777; fill: none; }
|
5
|
+
line { stroke-width: 3; }
|
6
|
+
</style>
|
7
|
+
<g>
|
8
|
+
<rect x="1" y="1" width="297" height="197" stroke-width="4"/>
|
9
|
+
<line x1="1" y1="1" x2="299" y2="199"/>
|
10
|
+
<line x1="1" y1="199" x2="299" y2="1"/>
|
11
|
+
</g>
|
5
12
|
</svg>
|
@@ -1,79 +1,26 @@
|
|
1
1
|
'use strict';
|
2
2
|
|
3
3
|
const Biovision = {
|
4
|
-
locale:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
}
|
17
|
-
},
|
18
|
-
set: function (type, key, value) {
|
19
|
-
if (Biovision.storage.available(type)) {
|
20
|
-
window[type].setItem(key, value);
|
21
|
-
} else {
|
22
|
-
console.log('set: Storage ' + type + ' is not available');
|
23
|
-
}
|
24
|
-
},
|
25
|
-
get: function (type, key) {
|
26
|
-
if (Biovision.storage.available(type)) {
|
27
|
-
return window[type].getItem(key);
|
28
|
-
} else {
|
29
|
-
console.log('get: Storage ' + type + ' is not available');
|
30
|
-
return null;
|
31
|
-
}
|
32
|
-
},
|
33
|
-
remove: function (type, key) {
|
34
|
-
if (Biovision.storage.available(type)) {
|
35
|
-
window[type].removeItem(key);
|
36
|
-
} else {
|
37
|
-
console.log('remove: Storage ' + type + ' is not available');
|
38
|
-
}
|
39
|
-
},
|
40
|
-
session: {
|
41
|
-
set: function (key, value) {
|
42
|
-
Biovision.storage.set('sessionStorage', key, value);
|
43
|
-
},
|
44
|
-
get: function (key) {
|
45
|
-
return Biovision.storage.get('sessionStorage', key);
|
46
|
-
},
|
47
|
-
remove: function (key) {
|
48
|
-
Biovision.storage.remove('sessionStorage', key);
|
49
|
-
}
|
50
|
-
},
|
51
|
-
local: {
|
52
|
-
set: function (key, value) {
|
53
|
-
Biovision.storage.set('localStorage', key, value);
|
54
|
-
},
|
55
|
-
get: function (key) {
|
56
|
-
return Biovision.storage.get('localStorage', key);
|
57
|
-
},
|
58
|
-
remove: function (key) {
|
59
|
-
Biovision.storage.remove('localStorage', key);
|
60
|
-
}
|
4
|
+
locale: '',
|
5
|
+
csrfToken: '',
|
6
|
+
components: {},
|
7
|
+
init: function () {
|
8
|
+
this.locale = document.querySelector('html').getAttribute('lang');
|
9
|
+
this.csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
|
10
|
+
|
11
|
+
if (typeof jQuery !== 'undefined') {
|
12
|
+
jQuery.ajaxSetup({
|
13
|
+
headers: {
|
14
|
+
'X-CSRF-Token': this.csrfToken
|
15
|
+
}
|
16
|
+
});
|
61
17
|
}
|
62
|
-
},
|
63
|
-
preview_file: function (input) {
|
64
|
-
const target_image = input.getAttribute('data-image');
|
65
|
-
|
66
|
-
if (target_image) {
|
67
|
-
const target = document.querySelector('#' + target_image + ' img');
|
68
18
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
};
|
75
|
-
|
76
|
-
reader.readAsDataURL(input.files[0]);
|
19
|
+
for (let component in this.components) {
|
20
|
+
if (this.components.hasOwnProperty(component)) {
|
21
|
+
if (this.components[component].hasOwnProperty('init')) {
|
22
|
+
this.components[component].init();
|
23
|
+
}
|
77
24
|
}
|
78
25
|
}
|
79
26
|
},
|
@@ -85,6 +32,7 @@ const Biovision = {
|
|
85
32
|
* @param [onFailure]
|
86
33
|
*/
|
87
34
|
new_ajax_request: function (method, url, onSuccess, onFailure) {
|
35
|
+
console.log("Biovision.new_ajax_request is deprecated; user Biovision.newAjaxRequest instead");
|
88
36
|
return Biovision.newAjaxRequest(method, url, onSuccess, onFailure);
|
89
37
|
},
|
90
38
|
/**
|
@@ -108,13 +56,11 @@ const Biovision = {
|
|
108
56
|
(onFailure || Biovision.handleAjaxFailure).call(this);
|
109
57
|
}
|
110
58
|
});
|
111
|
-
request.addEventListener(
|
112
|
-
console.log('AJAX error:', this);
|
113
|
-
});
|
59
|
+
request.addEventListener("error", Biovision.handleAjaxFailure);
|
114
60
|
|
115
61
|
request.open(method.toUpperCase(), url);
|
116
62
|
request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
117
|
-
request.setRequestHeader('X-CSRF-Token', Biovision.
|
63
|
+
request.setRequestHeader('X-CSRF-Token', Biovision.csrfToken);
|
118
64
|
|
119
65
|
return request;
|
120
66
|
},
|
@@ -130,6 +76,7 @@ const Biovision = {
|
|
130
76
|
* @param response
|
131
77
|
*/
|
132
78
|
handle_ajax_failure: function (response) {
|
79
|
+
console.log("Biovision.handle_ajax_failure is deprecated; use Biovision.handleAjaxFailure instead");
|
133
80
|
console.log('AJAX failed', this);
|
134
81
|
if (response.hasOwnProperty('responseJSON')) {
|
135
82
|
console.log(response['responseJSON']);
|
@@ -139,154 +86,456 @@ const Biovision = {
|
|
139
86
|
},
|
140
87
|
/**
|
141
88
|
* Handle failed AJAX request
|
89
|
+
*
|
90
|
+
* @type {Function}
|
142
91
|
*/
|
143
92
|
handleAjaxFailure: function () {
|
144
|
-
console.log('AJAX failed', this
|
93
|
+
console.log('AJAX failed', this);
|
145
94
|
},
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
95
|
+
/**
|
96
|
+
* Показать список ошибок после обработки формы
|
97
|
+
*
|
98
|
+
* Используется в контроллерах при отправке форм через remote: true
|
99
|
+
*
|
100
|
+
* @param {string} model_name название модели
|
101
|
+
* @param {Array<string>} list список ошибок
|
102
|
+
*/
|
103
|
+
showListOfErrors: function (model_name, list) {
|
104
|
+
const form = document.getElementById(model_name + '-form');
|
105
|
+
if (form) {
|
106
|
+
let errors = form.querySelector('ol.errors');
|
107
|
+
let data = '';
|
158
108
|
|
159
|
-
|
160
|
-
|
161
|
-
|
109
|
+
if (!errors) {
|
110
|
+
errors = document.createElement('ol');
|
111
|
+
errors.classList.add('errors');
|
162
112
|
}
|
163
|
-
}
|
164
|
-
string = string.replace(/[^-a-z0-9_.]/g, '-');
|
165
|
-
string = string.replace(/^[-_.]*([-a-z0-9_.]*[a-z0-9]+)[-_.]*$/, '$1');
|
166
|
-
string = string.replace(/--+/g, '-');
|
167
113
|
|
168
|
-
|
114
|
+
list.forEach(function (message) {
|
115
|
+
data += '<li>' + message + '</li>';
|
116
|
+
});
|
117
|
+
|
118
|
+
errors.innerHTML = data;
|
119
|
+
|
120
|
+
form.prepend(errors);
|
121
|
+
|
122
|
+
errors.scrollIntoView();
|
123
|
+
}
|
169
124
|
},
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
125
|
+
/**
|
126
|
+
* Hide and show elements in form with given id
|
127
|
+
*
|
128
|
+
* Toggles class "hidden" for elements with selectors
|
129
|
+
* hideSelector and showSelector for form children
|
130
|
+
*
|
131
|
+
* @param {String} formId
|
132
|
+
* @param {String} hideSelector elements to hide
|
133
|
+
* @param {String} showSelector elements to show
|
134
|
+
*/
|
135
|
+
switchFormElements: function (formId, hideSelector, showSelector) {
|
136
|
+
const form = document.getElementById(formId);
|
137
|
+
if (form) {
|
138
|
+
form.querySelectorAll(showSelector).forEach(function (element) {
|
139
|
+
element.classList.remove('hidden');
|
140
|
+
});
|
141
|
+
form.querySelectorAll(hideSelector).forEach(function (element) {
|
142
|
+
element.classList.add('hidden');
|
143
|
+
});
|
144
|
+
} else {
|
145
|
+
console.log('Cannot find element with id ' + formId)
|
146
|
+
}
|
147
|
+
}
|
148
|
+
};
|
149
|
+
|
150
|
+
/**
|
151
|
+
* Show/hide "go to top" link when it is present in layout
|
152
|
+
*
|
153
|
+
* @type {Object}
|
154
|
+
*/
|
155
|
+
Biovision.components.topLinker = {
|
156
|
+
/**
|
157
|
+
* @type {Boolean}
|
158
|
+
*/
|
159
|
+
initialized: false,
|
160
|
+
/**
|
161
|
+
* @type {HTMLElement}
|
162
|
+
*/
|
163
|
+
element: undefined,
|
164
|
+
/**
|
165
|
+
* Initialize component
|
166
|
+
*/
|
167
|
+
init: function () {
|
168
|
+
this.element = document.getElementById('go-to-top');
|
169
|
+
|
170
|
+
if (this.element) {
|
171
|
+
const topLinker = this.element;
|
172
|
+
|
173
|
+
window.addEventListener('scroll', function () {
|
174
|
+
if (window.pageYOffset > 500) {
|
175
|
+
topLinker.classList.remove('inactive');
|
176
|
+
} else {
|
177
|
+
topLinker.classList.add('inactive');
|
178
|
+
}
|
179
|
+
});
|
180
|
+
|
181
|
+
this.initialized = true;
|
182
|
+
}
|
183
|
+
}
|
184
|
+
};
|
185
|
+
|
186
|
+
/**
|
187
|
+
* Preview images when selecting them in input type="file" fields
|
188
|
+
*
|
189
|
+
* @type {Object}
|
190
|
+
*/
|
191
|
+
Biovision.components.filePreview = {
|
192
|
+
/**
|
193
|
+
* @type {Boolean}
|
194
|
+
*/
|
195
|
+
initialized: false,
|
196
|
+
/**
|
197
|
+
* Initialize component
|
198
|
+
*/
|
199
|
+
init: function () {
|
200
|
+
document.addEventListener('change', function (event) {
|
201
|
+
const input = event.target;
|
202
|
+
|
203
|
+
if (input.matches('input[type=file]')) {
|
204
|
+
Biovision.components.filePreview.handle(input);
|
205
|
+
}
|
179
206
|
});
|
207
|
+
this.initialized = true;
|
208
|
+
},
|
209
|
+
/**
|
210
|
+
* Handle change of file input field
|
211
|
+
*
|
212
|
+
* @param {EventTarget|HTMLInputElement} input
|
213
|
+
*/
|
214
|
+
handle: function (input) {
|
215
|
+
const targetImage = input.getAttribute('data-image');
|
180
216
|
|
181
|
-
|
182
|
-
|
217
|
+
if (targetImage) {
|
218
|
+
const target = document.querySelector('#' + targetImage + ' img');
|
183
219
|
|
184
|
-
if (
|
185
|
-
|
220
|
+
if (target && input.files && input.files[0]) {
|
221
|
+
const reader = new FileReader();
|
222
|
+
|
223
|
+
reader.onload = function (event) {
|
224
|
+
target.setAttribute('src', event.target["result"]);
|
225
|
+
};
|
226
|
+
|
227
|
+
reader.readAsDataURL(input.files[0]);
|
186
228
|
}
|
229
|
+
}
|
230
|
+
},
|
231
|
+
};
|
187
232
|
|
188
|
-
|
189
|
-
|
233
|
+
/**
|
234
|
+
* Linking entities with checkboxes
|
235
|
+
*
|
236
|
+
* @type {Object}
|
237
|
+
*/
|
238
|
+
Biovision.components.entityLinker = {
|
239
|
+
/**
|
240
|
+
* @type {Boolean}
|
241
|
+
*/
|
242
|
+
initialized: false,
|
243
|
+
selector: '.entity-links input[type=checkbox]',
|
244
|
+
/**
|
245
|
+
* List of elements with attached event listener
|
246
|
+
*
|
247
|
+
* @type {Array<HTMLElement>}
|
248
|
+
*/
|
249
|
+
elements: [],
|
250
|
+
/**
|
251
|
+
* Initialize component
|
252
|
+
*/
|
253
|
+
init: function () {
|
254
|
+
document.querySelectorAll(this.selector).forEach(this.apply);
|
255
|
+
this.initialized = true;
|
190
256
|
},
|
191
|
-
|
257
|
+
/**
|
258
|
+
* Apply handler to element
|
259
|
+
*
|
260
|
+
* @param {HTMLInputElement} element
|
261
|
+
*/
|
262
|
+
apply: function (element) {
|
263
|
+
const component = Biovision.components.entityLinker;
|
264
|
+
|
265
|
+
component.elements.push(element);
|
266
|
+
element.addEventListener('click', component.handler);
|
267
|
+
},
|
268
|
+
/**
|
269
|
+
* Event handler for clicking on element
|
270
|
+
*/
|
271
|
+
handler: function () {
|
192
272
|
const url = this.getAttribute('data-url');
|
193
273
|
|
194
274
|
if (url && !this.disabled) {
|
195
275
|
const method = this.checked ? 'put' : 'delete';
|
276
|
+
const box = this;
|
196
277
|
|
197
278
|
this.disabled = true;
|
198
279
|
|
199
|
-
Biovision.newAjaxRequest(method, url, ()
|
280
|
+
Biovision.newAjaxRequest(method, url, function () {
|
281
|
+
box.disabled = false
|
282
|
+
}).send();
|
200
283
|
}
|
284
|
+
}
|
285
|
+
};
|
286
|
+
|
287
|
+
/**
|
288
|
+
* Instantly check form validity
|
289
|
+
*
|
290
|
+
* @type {Object}
|
291
|
+
*/
|
292
|
+
Biovision.components.instantCheck = {
|
293
|
+
initialized: false,
|
294
|
+
selector: 'form[data-check-url]',
|
295
|
+
elements: [],
|
296
|
+
init: function () {
|
297
|
+
document.querySelectorAll(this.selector).forEach(this.apply);
|
298
|
+
this.initialized = true;
|
201
299
|
},
|
202
|
-
|
203
|
-
|
300
|
+
/**
|
301
|
+
*
|
302
|
+
* @param {HTMLFormElement} form
|
303
|
+
*/
|
304
|
+
apply: function (form) {
|
305
|
+
const component = Biovision.components.instantCheck;
|
204
306
|
|
205
|
-
|
206
|
-
|
307
|
+
form.querySelectorAll('[data-check]').forEach(function (element) {
|
308
|
+
component.elements.push(element);
|
309
|
+
element.addEventListener('blur', component.handler);
|
310
|
+
});
|
311
|
+
},
|
312
|
+
handler: function () {
|
313
|
+
const element = this;
|
314
|
+
const form = element.closest('form');
|
315
|
+
const url = form.getAttribute('data-check-url');
|
207
316
|
|
208
|
-
|
209
|
-
|
210
|
-
|
317
|
+
const request = Biovision.newAjaxRequest('POST', url, function () {
|
318
|
+
if (this.responseText) {
|
319
|
+
const response = JSON.parse(this.responseText);
|
211
320
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
const container = form.querySelector('[data-field="' + key + '"]');
|
321
|
+
if (response.hasOwnProperty('meta')) {
|
322
|
+
if (response.meta.valid) {
|
323
|
+
form.querySelectorAll('[data-field]').forEach(function (field) {
|
324
|
+
field.innerHTML = '';
|
325
|
+
});
|
326
|
+
} else {
|
327
|
+
const key = element.getAttribute('data-check');
|
328
|
+
const container = form.querySelector('[data-field="' + key + '"]');
|
221
329
|
|
222
|
-
|
223
|
-
|
330
|
+
if (container) {
|
331
|
+
const errors = response.meta['errors'];
|
224
332
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
}
|
333
|
+
if (errors.hasOwnProperty(key)) {
|
334
|
+
container.innerHTML = errors[key].join('; ');
|
335
|
+
container.classList.remove('hidden');
|
336
|
+
} else {
|
337
|
+
container.innerHTML = '';
|
231
338
|
}
|
232
339
|
}
|
233
340
|
}
|
234
341
|
}
|
235
|
-
}
|
342
|
+
}
|
343
|
+
});
|
236
344
|
|
237
|
-
|
238
|
-
|
239
|
-
|
345
|
+
const data = new FormData();
|
346
|
+
Array.from((new FormData(form)).entries()).forEach(function (entry) {
|
347
|
+
const value = entry[1];
|
240
348
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
}
|
349
|
+
if (value instanceof window.File && value.name === '' && value.size === 0) {
|
350
|
+
data.append(entry[0], new window.Blob([]), '');
|
351
|
+
} else {
|
352
|
+
if (entry[0] !== '_method') {
|
353
|
+
data.append(entry[0], value);
|
247
354
|
}
|
248
|
-
}
|
355
|
+
}
|
356
|
+
});
|
249
357
|
|
250
|
-
|
251
|
-
|
358
|
+
request.send(data);
|
359
|
+
}
|
360
|
+
};
|
252
361
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
362
|
+
Biovision.components.transliterator = {
|
363
|
+
initialized: false,
|
364
|
+
selector: '[data-transliterate]',
|
365
|
+
elements: [],
|
366
|
+
init: function () {
|
367
|
+
document.querySelectorAll(this.selector).forEach(this.apply);
|
368
|
+
this.initialized = true;
|
369
|
+
},
|
370
|
+
/**
|
371
|
+
*
|
372
|
+
* @param {HTMLElement} element
|
373
|
+
*/
|
374
|
+
apply: function (element) {
|
375
|
+
const component = Biovision.components.transliterator;
|
376
|
+
|
377
|
+
component.elements.push(element);
|
378
|
+
element.addEventListener('blur', component.handler);
|
379
|
+
},
|
380
|
+
/**
|
381
|
+
*
|
382
|
+
* @param {Event} event
|
383
|
+
*/
|
384
|
+
handler: function (event) {
|
385
|
+
const component = Biovision.components.transliterator;
|
386
|
+
const element = event.target;
|
387
|
+
const target = document.getElementById(element.getAttribute('data-transliterate'));
|
388
|
+
|
389
|
+
if (target && target.value === '') {
|
390
|
+
target.value = component.transliterate(element.value);
|
391
|
+
target.dispatchEvent(new Event('change'));
|
257
392
|
}
|
258
393
|
},
|
259
394
|
/**
|
260
|
-
* Показать список ошибок после обработки формы
|
261
395
|
*
|
262
|
-
*
|
396
|
+
* @param {string} input
|
397
|
+
* @returns {string}
|
398
|
+
*/
|
399
|
+
transliterate: function (input) {
|
400
|
+
const characterMap = {
|
401
|
+
'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd',
|
402
|
+
'е': 'e', 'ё': 'yo', 'ж': 'zh', 'з': 'z', 'и': 'i',
|
403
|
+
'й': 'j', 'к': 'k', 'л': 'l', 'м': 'm', 'н': 'n',
|
404
|
+
'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't',
|
405
|
+
'у': 'u', 'ф': 'f', 'х': 'kh', 'ц': 'c', 'ч': 'ch',
|
406
|
+
'ш': 'sh', 'щ': 'shh', 'ъ': '', 'ы': 'y', 'ь': '',
|
407
|
+
'э': 'e', 'ю': 'yu', 'я': 'ya',
|
408
|
+
'å': 'ao', 'ä': 'ae', 'ö': 'oe', 'é': 'e'
|
409
|
+
};
|
410
|
+
let string = input.toLowerCase();
|
411
|
+
|
412
|
+
for (let index in characterMap) {
|
413
|
+
if (characterMap.hasOwnProperty(index)) {
|
414
|
+
string = string.replace(new RegExp(index, 'g'), characterMap[index]);
|
415
|
+
}
|
416
|
+
}
|
417
|
+
string = string.replace(/[^-a-z0-9_.]/g, '-');
|
418
|
+
string = string.replace(/^[-_.]*([-a-z0-9_.]*[a-z0-9]+)[-_.]*$/, '$1');
|
419
|
+
string = string.replace(/--+/g, '-');
|
420
|
+
|
421
|
+
return string;
|
422
|
+
},
|
423
|
+
};
|
424
|
+
|
425
|
+
Biovision.components.formStatus = {
|
426
|
+
initialized: false,
|
427
|
+
selector: 'form[data-remote]',
|
428
|
+
elements: [],
|
429
|
+
init: function () {
|
430
|
+
document.querySelectorAll(this.selector).forEach(this.apply);
|
431
|
+
this.initialized = true;
|
432
|
+
},
|
433
|
+
/**
|
263
434
|
*
|
264
|
-
* @param {
|
265
|
-
* @param {Array<string>} list список ошибок
|
435
|
+
* @param {HTMLFormElement} element
|
266
436
|
*/
|
267
|
-
|
268
|
-
const
|
269
|
-
|
270
|
-
let errors = form.querySelector('ol.errors');
|
271
|
-
let data = '';
|
437
|
+
apply: function (element) {
|
438
|
+
const component = Biovision.components.formStatus;
|
439
|
+
component.elements.push(element);
|
272
440
|
|
273
|
-
|
274
|
-
|
275
|
-
|
441
|
+
const button = element.querySelector('button[type=submit]');
|
442
|
+
const loadingMessage = element.querySelector('.loading_message');
|
443
|
+
const stateContainer = element.querySelector('.state_container');
|
444
|
+
const progressPercent = element.querySelector('.state_container .percentage');
|
445
|
+
const progressBar = element.querySelector('.state_container progress');
|
446
|
+
|
447
|
+
element.addEventListener('ajax:before', function () {
|
448
|
+
button.disabled = true;
|
449
|
+
|
450
|
+
if (loadingMessage) {
|
451
|
+
loadingMessage.classList.remove('hidden');
|
276
452
|
}
|
453
|
+
});
|
277
454
|
|
278
|
-
|
279
|
-
|
455
|
+
element.addEventListener('ajax:complete', function () {
|
456
|
+
button.disabled = false;
|
457
|
+
|
458
|
+
if (loadingMessage) {
|
459
|
+
loadingMessage.classList.add('hidden');
|
460
|
+
}
|
461
|
+
if (progressBar) {
|
462
|
+
progressBar.value = '0';
|
463
|
+
}
|
464
|
+
});
|
465
|
+
|
466
|
+
if (stateContainer) {
|
467
|
+
element.addEventListener('ajax:beforeSend', function (event) {
|
468
|
+
const request = event.detail[0];
|
469
|
+
|
470
|
+
request.upload.addEventListener('progress', function (e) {
|
471
|
+
const value = e.loaded / e.total;
|
472
|
+
|
473
|
+
if (progressPercent) {
|
474
|
+
progressPercent.innerHTML = (value * 100) + '%';
|
475
|
+
}
|
476
|
+
if (progressBar) {
|
477
|
+
progressBar.value = value;
|
478
|
+
}
|
479
|
+
});
|
280
480
|
});
|
481
|
+
}
|
482
|
+
},
|
483
|
+
};
|
281
484
|
|
282
|
-
|
485
|
+
Biovision.components.autoExpand = {
|
486
|
+
initialized: false,
|
487
|
+
selector: 'textarea.auto-expand',
|
488
|
+
elements: [],
|
489
|
+
init: function () {
|
490
|
+
document.querySelectorAll(this.selector).forEach(this.apply);
|
491
|
+
this.initialized = true;
|
492
|
+
},
|
493
|
+
/**
|
494
|
+
*
|
495
|
+
* @param {HTMLTextAreaElement} element
|
496
|
+
*/
|
497
|
+
apply: function (element) {
|
498
|
+
const component = Biovision.components.autoExpand;
|
499
|
+
component.elements.push(element);
|
283
500
|
|
284
|
-
|
501
|
+
element.addEventListener('focus', component.handler);
|
502
|
+
element.addEventListener('input', component.handler);
|
503
|
+
},
|
504
|
+
handler: function () {
|
505
|
+
if (!this.hasOwnProperty('baseScrollHeight')) {
|
506
|
+
let savedValue = this.value;
|
507
|
+
this.value = '';
|
508
|
+
this.baseScrollHeight = this.scrollHeight;
|
509
|
+
this.value = savedValue;
|
510
|
+
}
|
511
|
+
const styles = getComputedStyle(this);
|
512
|
+
const ratio = styles.getPropertyValue('line-height').replace('px', '');
|
513
|
+
const minRows = this.getAttribute('data-min-rows') | 0;
|
514
|
+
const maxRows = this.hasAttribute('data-max-rows') ? parseInt(this.getAttribute('data-max-rows')) : 25;
|
515
|
+
const rows = Math.ceil((this.scrollHeight - this.baseScrollHeight) / ratio);
|
285
516
|
|
286
|
-
|
517
|
+
this.rows = minRows;
|
518
|
+
this.rows = minRows + rows;
|
519
|
+
if (this.rows > maxRows) {
|
520
|
+
this.rows = maxRows;
|
287
521
|
}
|
522
|
+
}
|
523
|
+
};
|
524
|
+
|
525
|
+
Biovision.components.entityImageRemover = {
|
526
|
+
initialized: false,
|
527
|
+
selector: '.remove-image-button',
|
528
|
+
elements: [],
|
529
|
+
init: function () {
|
530
|
+
document.querySelectorAll(this.selector).forEach(this.apply);
|
531
|
+
this.initialized = true;
|
288
532
|
},
|
289
|
-
|
533
|
+
apply: function (element) {
|
534
|
+
const component = Biovision.components.entityImageRemover;
|
535
|
+
component.elements.push(element);
|
536
|
+
element.addEventListener('click', component.handler);
|
537
|
+
},
|
538
|
+
handler: function () {
|
290
539
|
const button = this;
|
291
540
|
if (!button.disabled) {
|
292
541
|
const message = button.getAttribute('data-text');
|
@@ -311,104 +560,395 @@ const Biovision = {
|
|
311
560
|
request.send();
|
312
561
|
}
|
313
562
|
}
|
563
|
+
}
|
564
|
+
};
|
565
|
+
|
566
|
+
Biovision.components.ajaxDeleteButton = {
|
567
|
+
initialized: false,
|
568
|
+
selector: 'button.destroy[data-url]',
|
569
|
+
elements: [],
|
570
|
+
messages: {
|
571
|
+
"ru": "Вы уверены?",
|
572
|
+
"en": "Are you sure?"
|
314
573
|
},
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
574
|
+
init: function () {
|
575
|
+
document.querySelectorAll(this.selector).forEach(this.apply);
|
576
|
+
this.initialized = true;
|
577
|
+
},
|
578
|
+
apply: function (element) {
|
579
|
+
const component = Biovision.components.ajaxDeleteButton;
|
580
|
+
component.elements.push(element);
|
581
|
+
element.addEventListener('click', component.handler);
|
582
|
+
},
|
583
|
+
handler: function (event) {
|
584
|
+
const messages = Biovision.components.ajaxDeleteButton.messages;
|
585
|
+
const element = event.target;
|
586
|
+
const message = messages.hasOwnProperty(Biovision.locale) ? messages[Biovision.locale] : 'Are you sure?';
|
587
|
+
|
588
|
+
element.disabled = true;
|
589
|
+
|
590
|
+
if (confirm(message)) {
|
591
|
+
const url = element.getAttribute('data-url');
|
592
|
+
const request = Biovision.newAjaxRequest('delete', url, function () {
|
593
|
+
element.closest('li[data-id]').remove();
|
594
|
+
});
|
595
|
+
request.send();
|
321
596
|
}
|
322
|
-
const styles = getComputedStyle(this);
|
323
|
-
const ratio = styles.getPropertyValue('line-height').replace('px', '');
|
324
|
-
const minRows = this.getAttribute('data-min-rows') | 0;
|
325
|
-
const maxRows = this.hasAttribute('data-max-rows') ? parseInt(this.getAttribute('data-max-rows')) : 25;
|
326
|
-
const rows = Math.ceil((this.scrollHeight - this.baseScrollHeight) / ratio);
|
327
597
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
598
|
+
element.disabled = false;
|
599
|
+
}
|
600
|
+
};
|
601
|
+
|
602
|
+
Biovision.components.storage = {
|
603
|
+
initialized: false,
|
604
|
+
session: {
|
605
|
+
set: function (key, value) {
|
606
|
+
Biovision.components.storage.set('sessionStorage', key, value);
|
607
|
+
},
|
608
|
+
get: function (key) {
|
609
|
+
return Biovision.components.storage.get('sessionStorage', key);
|
610
|
+
},
|
611
|
+
remove: function (key) {
|
612
|
+
Biovision.components.storage.remove('sessionStorage', key);
|
613
|
+
}
|
614
|
+
},
|
615
|
+
local: {
|
616
|
+
set: function (key, value) {
|
617
|
+
Biovision.components.storage.set('localStorage', key, value);
|
618
|
+
},
|
619
|
+
get: function (key) {
|
620
|
+
return Biovision.components.storage.get('localStorage', key);
|
621
|
+
},
|
622
|
+
remove: function (key) {
|
623
|
+
Biovision.components.storage.remove('localStorage', key);
|
332
624
|
}
|
333
625
|
},
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
626
|
+
init: function () {
|
627
|
+
Biovision.storage = this;
|
628
|
+
this.initialized = true;
|
629
|
+
},
|
630
|
+
available: function (type) {
|
631
|
+
try {
|
632
|
+
const x = '__storage_test__';
|
340
633
|
|
341
|
-
|
342
|
-
|
634
|
+
window[type].setItem(x, x);
|
635
|
+
window[type].removeItem(x);
|
343
636
|
|
344
|
-
|
345
|
-
|
346
|
-
|
637
|
+
return true;
|
638
|
+
} catch (e) {
|
639
|
+
return false;
|
640
|
+
}
|
641
|
+
},
|
642
|
+
set: function (type, key, value) {
|
643
|
+
if (Biovision.components.storage.available(type)) {
|
644
|
+
window[type].setItem(key, value);
|
645
|
+
} else {
|
646
|
+
console.log('set: Storage ' + type + ' is not available');
|
647
|
+
}
|
648
|
+
},
|
649
|
+
get: function (type, key) {
|
650
|
+
if (Biovision.components.storage.available(type)) {
|
651
|
+
return window[type].getItem(key);
|
652
|
+
} else {
|
653
|
+
console.log('get: Storage ' + type + ' is not available');
|
654
|
+
return null;
|
655
|
+
}
|
656
|
+
},
|
657
|
+
remove: function (type, key) {
|
658
|
+
if (Biovision.components.storage.available(type)) {
|
659
|
+
window[type].removeItem(key);
|
660
|
+
} else {
|
661
|
+
console.log('remove: Storage ' + type + ' is not available');
|
662
|
+
}
|
663
|
+
}
|
664
|
+
};
|
665
|
+
|
666
|
+
// Кнопка удаления элемента через AJAX
|
667
|
+
Biovision.components.destroyButton = {
|
668
|
+
initialized: false,
|
669
|
+
selector: 'div[data-destroy-url] button.destroy',
|
670
|
+
elements: [],
|
671
|
+
init: function () {
|
672
|
+
document.querySelectorAll(this.selector).forEach(this.apply);
|
673
|
+
this.initialized = true;
|
674
|
+
},
|
675
|
+
apply: function (element) {
|
676
|
+
const component = Biovision.components.destroyButton;
|
677
|
+
component.elements.push(element);
|
678
|
+
element.addEventListener('click', component.handler);
|
679
|
+
},
|
680
|
+
handler: function () {
|
681
|
+
const container = this.closest('div[data-destroy-url]');
|
682
|
+
const url = container.getAttribute('data-destroy-url');
|
683
|
+
const request = Biovision.newAjaxRequest('DELETE', url, function () {
|
684
|
+
container.remove();
|
347
685
|
});
|
348
686
|
|
349
|
-
|
350
|
-
|
687
|
+
this.setAttribute('disabled', 'true');
|
688
|
+
request.send();
|
689
|
+
}
|
690
|
+
};
|
351
691
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
692
|
+
// Поиск пользователя в админке
|
693
|
+
Biovision.components.userSearch = {
|
694
|
+
initialized: false,
|
695
|
+
selector: '.user-search button',
|
696
|
+
elements: [],
|
697
|
+
init: function () {
|
698
|
+
document.querySelectorAll(this.selector).forEach(this.apply);
|
699
|
+
this.initialized = true;
|
700
|
+
},
|
701
|
+
apply: function (element) {
|
702
|
+
const component = Biovision.components.userSearch;
|
703
|
+
component.elements.push(element);
|
704
|
+
element.addEventListener('click', component.handler);
|
705
|
+
},
|
706
|
+
handler: function () {
|
707
|
+
const container = this.closest('.user-search');
|
708
|
+
const input = container.querySelector('input[type=search]');
|
709
|
+
const url = container.getAttribute('data-url') + '?q=' + encodeURIComponent(input.value);
|
710
|
+
|
711
|
+
const request = Biovision.newAjaxRequest('GET', url, function () {
|
712
|
+
const response = JSON.parse(this.responseText);
|
713
|
+
const results = container.querySelector('.results');
|
714
|
+
|
715
|
+
if (response.hasOwnProperty('data')) {
|
716
|
+
results.innerHTML = response['data']['html'];
|
717
|
+
|
718
|
+
results.querySelectorAll('li').forEach(function (li) {
|
719
|
+
li.addEventListener('click', function (event) {
|
720
|
+
const element = event.target;
|
721
|
+
const target = document.getElementById(container.getAttribute('data-target'));
|
722
|
+
|
723
|
+
target.value = element.getAttribute('data-id');
|
724
|
+
});
|
725
|
+
});
|
357
726
|
}
|
358
727
|
});
|
359
728
|
|
360
|
-
|
361
|
-
|
362
|
-
|
729
|
+
request.send();
|
730
|
+
}
|
731
|
+
};
|
363
732
|
|
364
|
-
|
365
|
-
|
733
|
+
/**
|
734
|
+
* Hide popups when clicking outside
|
735
|
+
*
|
736
|
+
* @type {Object}
|
737
|
+
*/
|
738
|
+
Biovision.components.hidingPopups = {
|
739
|
+
/**
|
740
|
+
* @type {Boolean}
|
741
|
+
*/
|
742
|
+
initialized: false,
|
743
|
+
/**
|
744
|
+
* @type {String}
|
745
|
+
*/
|
746
|
+
selector: '.hiding-popup-container .popup-control',
|
747
|
+
/**
|
748
|
+
* List of control checkboxes
|
749
|
+
*
|
750
|
+
* @type {Array<HTMLInputElement>}
|
751
|
+
*/
|
752
|
+
elements: [],
|
753
|
+
/**
|
754
|
+
* Initialize component
|
755
|
+
*/
|
756
|
+
init: function () {
|
757
|
+
const component = this;
|
758
|
+
this.elements = [];
|
759
|
+
document.querySelectorAll(this.selector).forEach(component.addElement);
|
760
|
+
document.addEventListener('click', component.handler);
|
366
761
|
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
762
|
+
this.initialized = true;
|
763
|
+
},
|
764
|
+
/**
|
765
|
+
* Add container to list
|
766
|
+
*
|
767
|
+
* @param {HTMLInputElement} element
|
768
|
+
*/
|
769
|
+
addElement: function (element) {
|
770
|
+
Biovision.components.hidingPopups.elements.push(element);
|
771
|
+
},
|
772
|
+
/**
|
773
|
+
* Handle click
|
774
|
+
*
|
775
|
+
* @param {Event} event
|
776
|
+
* @type {Function}
|
777
|
+
*/
|
778
|
+
handler: function (event) {
|
779
|
+
const component = Biovision.components.hidingPopups;
|
780
|
+
const selector = '.hiding-popup-container *';
|
781
|
+
const target = event.target;
|
782
|
+
|
783
|
+
if (target.matches(selector)) {
|
784
|
+
const container = target.closest('.hiding-popup-container');
|
785
|
+
const checkbox = container.querySelector(component.selector);
|
786
|
+
component.elements.forEach(function (element) {
|
787
|
+
if (element !== checkbox) {
|
788
|
+
element.checked = false;
|
789
|
+
}
|
790
|
+
});
|
791
|
+
} else {
|
792
|
+
component.elements.forEach(function (checkbox) {
|
793
|
+
checkbox.checked = false;
|
374
794
|
});
|
375
795
|
}
|
376
796
|
}
|
377
797
|
};
|
378
798
|
|
379
|
-
|
380
|
-
|
799
|
+
Biovision.components.componentEditor = {
|
800
|
+
initialized: false,
|
801
|
+
/**
|
802
|
+
* @type {HTMLElement}
|
803
|
+
*/
|
804
|
+
list: undefined,
|
805
|
+
url: undefined,
|
806
|
+
elements: [],
|
807
|
+
values: {},
|
808
|
+
init: function () {
|
809
|
+
this.list = document.getElementById('biovision-component-parameters');
|
810
|
+
if (this.list) {
|
811
|
+
const component = this;
|
812
|
+
this.url = this.list.getAttribute('data-url');
|
813
|
+
this.list.querySelectorAll('input[type="text"]').forEach(component.apply);
|
814
|
+
|
815
|
+
this.initialized = true;
|
816
|
+
}
|
817
|
+
},
|
818
|
+
/**
|
819
|
+
*
|
820
|
+
* @param element
|
821
|
+
* @type {Function}
|
822
|
+
*/
|
823
|
+
apply: function (element) {
|
824
|
+
const component = Biovision.components.componentEditor;
|
825
|
+
const button = element.parentNode.querySelector('button');
|
381
826
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
827
|
+
component.values[element.getAttribute('id')] = element.value;
|
828
|
+
|
829
|
+
component.elements.push(element);
|
830
|
+
element.addEventListener('change', component.handleChange);
|
831
|
+
element.addEventListener('keyup', component.keyUp);
|
832
|
+
button.addEventListener('click', component.handleClick);
|
833
|
+
},
|
834
|
+
handleChange: function (event) {
|
835
|
+
const element = event.target;
|
836
|
+
const button = element.parentNode.querySelector('button');
|
837
|
+
|
838
|
+
button.disabled = false;
|
839
|
+
},
|
840
|
+
keyUp: function (event) {
|
841
|
+
const component = Biovision.components.componentEditor;
|
842
|
+
const element = event.target;
|
843
|
+
const button = element.parentNode.querySelector('button');
|
844
|
+
|
845
|
+
if (component.values[element.getAttribute('id')] !== element.value) {
|
846
|
+
button.disabled = false;
|
847
|
+
}
|
848
|
+
},
|
849
|
+
/**
|
850
|
+
*
|
851
|
+
* @param {MouseEvent} event
|
852
|
+
* @type {Function}
|
853
|
+
*/
|
854
|
+
handleClick: function (event) {
|
855
|
+
const component = Biovision.components.componentEditor;
|
856
|
+
/**
|
857
|
+
*
|
858
|
+
* @type {HTMLButtonElement}
|
859
|
+
*/
|
860
|
+
const button = event.target;
|
861
|
+
const li = button.closest('li');
|
862
|
+
const input = li.querySelector('input');
|
863
|
+
const data = {
|
864
|
+
"key": {
|
865
|
+
"slug": button.getAttribute('data-slug'),
|
866
|
+
"value": input.value
|
389
867
|
}
|
868
|
+
};
|
869
|
+
|
870
|
+
const request = Biovision.jsonAjaxRequest('put', component.url, function () {
|
871
|
+
component.values[input.getAttribute('id')] = input.value;
|
390
872
|
});
|
873
|
+
|
874
|
+
button.disabled = true;
|
875
|
+
request.send(JSON.stringify(data));
|
876
|
+
},
|
877
|
+
add: function (data) {
|
878
|
+
if (this.initialized) {
|
879
|
+
const li = document.createElement('li');
|
880
|
+
const name = document.createElement('div');
|
881
|
+
const value = document.createElement('div');
|
882
|
+
const input = document.createElement('input');
|
883
|
+
|
884
|
+
name.classList.add('name');
|
885
|
+
name.innerHTML = "<label>" + data["slug"] + "</label>\n<span>(" + data["name"] + ")</span>";
|
886
|
+
|
887
|
+
value.classList.add('value');
|
888
|
+
input.value = data["value"];
|
889
|
+
value.appendChild(input);
|
890
|
+
|
891
|
+
li.appendChild(name);
|
892
|
+
li.appendChild(value);
|
893
|
+
|
894
|
+
if (data["description"]) {
|
895
|
+
const desc = document.createElement('div');
|
896
|
+
desc.classList.add('description');
|
897
|
+
desc.innerHTML = data["description"];
|
898
|
+
|
899
|
+
li.appendChild(desc);
|
900
|
+
}
|
901
|
+
|
902
|
+
this.list.appendChild(li);
|
903
|
+
} else {
|
904
|
+
console.log('componentEditor is not initialized');
|
905
|
+
}
|
391
906
|
}
|
907
|
+
};
|
392
908
|
|
393
|
-
|
394
|
-
|
395
|
-
|
909
|
+
Biovision.components.newParameterForm = {
|
910
|
+
initialized: false,
|
911
|
+
element: undefined,
|
912
|
+
init: function () {
|
913
|
+
this.element = document.getElementById('new-biovision-parameter-form');
|
914
|
+
if (this.element) {
|
915
|
+
const component = this;
|
396
916
|
|
397
|
-
|
398
|
-
|
917
|
+
this.element.addEventListener('submit', component.handler);
|
918
|
+
this.initialized = true;
|
399
919
|
}
|
400
|
-
}
|
920
|
+
},
|
921
|
+
handler: function (event) {
|
922
|
+
event.preventDefault();
|
923
|
+
|
924
|
+
const form = event.target;
|
925
|
+
const url = form.getAttribute('action');
|
926
|
+
const data = {"key": {}};
|
927
|
+
form.querySelectorAll('input[data-field]').forEach(function (input) {
|
928
|
+
data["key"][input.getAttribute('data-field')] = input.value;
|
929
|
+
});
|
401
930
|
|
402
|
-
|
403
|
-
|
931
|
+
const request = Biovision.jsonAjaxRequest('put', url, function () {
|
932
|
+
Biovision.components.newParameterForm.clear();
|
933
|
+
Biovision.components.componentEditor.add(data["key"]);
|
934
|
+
});
|
404
935
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
936
|
+
request.send(JSON.stringify(data));
|
937
|
+
},
|
938
|
+
clear: function () {
|
939
|
+
const component = Biovision.components.newParameterForm;
|
409
940
|
|
410
|
-
|
411
|
-
|
941
|
+
component.element.querySelectorAll('input').forEach(function (input) {
|
942
|
+
input.value = '';
|
943
|
+
});
|
944
|
+
}
|
945
|
+
};
|
946
|
+
|
947
|
+
document.addEventListener('DOMContentLoaded', function () {
|
948
|
+
Biovision.init();
|
949
|
+
|
950
|
+
document.addEventListener('click', function (event) {
|
951
|
+
const element = event.target;
|
412
952
|
|
413
953
|
// Запирание/отпирание сущности (иконка с замком)
|
414
954
|
if (element.matches('li.lock > a img')) {
|
@@ -546,77 +1086,6 @@ document.addEventListener('DOMContentLoaded', function () {
|
|
546
1086
|
}
|
547
1087
|
}
|
548
1088
|
});
|
549
|
-
|
550
|
-
// Кнопка поиска пользователя в админке
|
551
|
-
document.querySelectorAll('.user-search button').forEach(function (element) {
|
552
|
-
element.addEventListener('click', function () {
|
553
|
-
const container = this.closest('.user-search');
|
554
|
-
const input = container.querySelector('input[type=search]');
|
555
|
-
const url = container.getAttribute('data-url') + '?q=' + encodeURIComponent(input.value);
|
556
|
-
|
557
|
-
const request = Biovision.newAjaxRequest('GET', url, function () {
|
558
|
-
const response = JSON.parse(this.responseText);
|
559
|
-
const results = container.querySelector('.results');
|
560
|
-
|
561
|
-
if (response.hasOwnProperty('data')) {
|
562
|
-
results.innerHTML = response['data']['html'];
|
563
|
-
}
|
564
|
-
});
|
565
|
-
|
566
|
-
request.send();
|
567
|
-
});
|
568
|
-
});
|
569
|
-
|
570
|
-
document.querySelectorAll('.entity-links input[type=checkbox]').forEach(function (element) {
|
571
|
-
element.addEventListener('click', Biovision.entity_link_changer);
|
572
|
-
});
|
573
|
-
|
574
|
-
// Кнопка удаления элемента через AJAX
|
575
|
-
document.querySelectorAll('div[data-destroy-url] button.destroy').forEach(function (element) {
|
576
|
-
element.addEventListener('click', function () {
|
577
|
-
const container = this.closest('div[data-destroy-url]');
|
578
|
-
const url = container.getAttribute('data-destroy-url');
|
579
|
-
const request = Biovision.newAjaxRequest('DELETE', url, function () {
|
580
|
-
container.remove();
|
581
|
-
});
|
582
|
-
|
583
|
-
this.setAttribute('disabled', 'true');
|
584
|
-
request.send();
|
585
|
-
});
|
586
|
-
});
|
587
|
-
|
588
|
-
document.querySelectorAll('button.destroy[data-url]').forEach(Biovision.ajax_delete_button);
|
589
|
-
|
590
|
-
document.querySelectorAll('[data-transliterate]').forEach(function (element) {
|
591
|
-
element.addEventListener('blur', function () {
|
592
|
-
const target = document.getElementById(element.getAttribute('data-transliterate'));
|
593
|
-
|
594
|
-
if (target && target.value === '') {
|
595
|
-
target.value = Biovision.transliterate(element.value);
|
596
|
-
target.dispatchEvent(new Event('change'));
|
597
|
-
}
|
598
|
-
});
|
599
|
-
});
|
600
|
-
|
601
|
-
document.querySelectorAll('form[data-remote]').forEach(Biovision.remoteFormHandler);
|
602
|
-
document.querySelectorAll('form[data-check-url]').forEach(Biovision.instant_check);
|
603
|
-
|
604
|
-
document.querySelectorAll('.remove-image-button').forEach(function (button) {
|
605
|
-
button.addEventListener('click', Biovision.removeEntityImage);
|
606
|
-
});
|
607
|
-
|
608
|
-
document.querySelectorAll('textarea.auto-expand').forEach(function (textarea) {
|
609
|
-
textarea.addEventListener('focus', Biovision.autoExpand);
|
610
|
-
textarea.addEventListener('input', Biovision.autoExpand);
|
611
|
-
});
|
612
|
-
|
613
|
-
if (typeof jQuery !== 'undefined') {
|
614
|
-
jQuery.ajaxSetup({
|
615
|
-
headers: {
|
616
|
-
'X-CSRF-Token': Biovision.csrf_token
|
617
|
-
}
|
618
|
-
});
|
619
|
-
}
|
620
1089
|
});
|
621
1090
|
|
622
1091
|
function handle_ajax_failure(response) {
|
@@ -652,153 +1121,3 @@ document.addEventListener('ajax:beforeSend', function (e) {
|
|
652
1121
|
|
653
1122
|
e.detail[1].data = newFormData
|
654
1123
|
});
|
655
|
-
|
656
|
-
/*
|
657
|
-
*************
|
658
|
-
* Polyfills *
|
659
|
-
*************
|
660
|
-
*/
|
661
|
-
|
662
|
-
/**
|
663
|
-
* Element.matches()
|
664
|
-
*
|
665
|
-
* IE 9+
|
666
|
-
*
|
667
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
|
668
|
-
*/
|
669
|
-
if (!Element.prototype.matches) {
|
670
|
-
Element.prototype.matches =
|
671
|
-
Element.prototype.msMatchesSelector ||
|
672
|
-
Element.prototype.webkitMatchesSelector;
|
673
|
-
}
|
674
|
-
|
675
|
-
/**
|
676
|
-
* Element.closest()
|
677
|
-
*
|
678
|
-
* IE 9+
|
679
|
-
*
|
680
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
|
681
|
-
*/
|
682
|
-
if (!Element.prototype.closest) {
|
683
|
-
Element.prototype.closest = function (s) {
|
684
|
-
let el = this;
|
685
|
-
let ancestor = this;
|
686
|
-
|
687
|
-
if (!document.documentElement.contains(el)) {
|
688
|
-
return null;
|
689
|
-
}
|
690
|
-
do {
|
691
|
-
if (ancestor.matches(s)) {
|
692
|
-
return ancestor;
|
693
|
-
}
|
694
|
-
ancestor = ancestor.parentElement;
|
695
|
-
} while (ancestor !== null);
|
696
|
-
|
697
|
-
return null;
|
698
|
-
};
|
699
|
-
}
|
700
|
-
|
701
|
-
/**
|
702
|
-
* ParentNode.prepend()
|
703
|
-
*
|
704
|
-
* IE
|
705
|
-
*
|
706
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/prepend
|
707
|
-
* @see https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/prepend()/prepend().md
|
708
|
-
*/
|
709
|
-
(function (arr) {
|
710
|
-
arr.forEach(function (item) {
|
711
|
-
if (item.hasOwnProperty('prepend')) {
|
712
|
-
return;
|
713
|
-
}
|
714
|
-
Object.defineProperty(item, 'prepend', {
|
715
|
-
configurable: true,
|
716
|
-
enumerable: true,
|
717
|
-
writable: true,
|
718
|
-
value: function prepend() {
|
719
|
-
let argArr = Array.prototype.slice.call(arguments),
|
720
|
-
docFrag = document.createDocumentFragment();
|
721
|
-
|
722
|
-
argArr.forEach(function (argItem) {
|
723
|
-
let isNode = argItem instanceof Node;
|
724
|
-
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
|
725
|
-
});
|
726
|
-
|
727
|
-
this.insertBefore(docFrag, this.firstChild);
|
728
|
-
}
|
729
|
-
});
|
730
|
-
});
|
731
|
-
})([Element.prototype, Document.prototype, DocumentFragment.prototype]);
|
732
|
-
|
733
|
-
/**
|
734
|
-
* ParentNode.append()
|
735
|
-
*
|
736
|
-
* IE 9+
|
737
|
-
*
|
738
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append
|
739
|
-
* @see https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/append()/append().md
|
740
|
-
*/
|
741
|
-
(function (arr) {
|
742
|
-
arr.forEach(function (item) {
|
743
|
-
if (item.hasOwnProperty('append')) {
|
744
|
-
return;
|
745
|
-
}
|
746
|
-
Object.defineProperty(item, 'append', {
|
747
|
-
configurable: true,
|
748
|
-
enumerable: true,
|
749
|
-
writable: true,
|
750
|
-
value: function append() {
|
751
|
-
let argArr = Array.prototype.slice.call(arguments),
|
752
|
-
docFrag = document.createDocumentFragment();
|
753
|
-
|
754
|
-
argArr.forEach(function (argItem) {
|
755
|
-
let isNode = argItem instanceof Node;
|
756
|
-
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
|
757
|
-
});
|
758
|
-
|
759
|
-
this.appendChild(docFrag);
|
760
|
-
}
|
761
|
-
});
|
762
|
-
});
|
763
|
-
})([Element.prototype, Document.prototype, DocumentFragment.prototype]);
|
764
|
-
|
765
|
-
/**
|
766
|
-
* ChildNode.remove()
|
767
|
-
*
|
768
|
-
* IE 9+
|
769
|
-
*
|
770
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
|
771
|
-
*/
|
772
|
-
(function (arr) {
|
773
|
-
arr.forEach(function (item) {
|
774
|
-
if (item.hasOwnProperty('remove')) {
|
775
|
-
return;
|
776
|
-
}
|
777
|
-
Object.defineProperty(item, 'remove', {
|
778
|
-
configurable: true,
|
779
|
-
enumerable: true,
|
780
|
-
writable: true,
|
781
|
-
value: function remove() {
|
782
|
-
if (this.parentNode !== null) {
|
783
|
-
this.parentNode.removeChild(this);
|
784
|
-
}
|
785
|
-
}
|
786
|
-
});
|
787
|
-
});
|
788
|
-
})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
|
789
|
-
|
790
|
-
/**
|
791
|
-
* NodeList.forEach()
|
792
|
-
*
|
793
|
-
* ES5
|
794
|
-
*
|
795
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
|
796
|
-
*/
|
797
|
-
if (window.NodeList && !NodeList.prototype.forEach) {
|
798
|
-
NodeList.prototype.forEach = function (callback, thisArg) {
|
799
|
-
thisArg = thisArg || window;
|
800
|
-
for (let i = 0; i < this.length; i++) {
|
801
|
-
callback.call(thisArg, this[i], i, this);
|
802
|
-
}
|
803
|
-
};
|
804
|
-
}
|