decidim-term_customizer 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +180 -0
- data/Rakefile +48 -0
- data/app/assets/config/translation_sets_admin_manifest.js +2 -0
- data/app/assets/javascripts/decidim/term_customizer/admin/constraint_fields.js.es6 +45 -0
- data/app/assets/javascripts/decidim/term_customizer/admin/multifield/component.js.es6 +103 -0
- data/app/assets/javascripts/decidim/term_customizer/admin/multifield.js.es6 +5 -0
- data/app/assets/javascripts/decidim/term_customizer/admin/translation_sets_admin.js.es6 +19 -0
- data/app/assets/javascripts/decidim/term_customizer/admin/translations_admin.js.es6 +72 -0
- data/app/commands/decidim/term_customizer/admin/create_translation.rb +53 -0
- data/app/commands/decidim/term_customizer/admin/create_translation_set.rb +68 -0
- data/app/commands/decidim/term_customizer/admin/import_translation_keys.rb +59 -0
- data/app/commands/decidim/term_customizer/admin/update_translation.rb +65 -0
- data/app/commands/decidim/term_customizer/admin/update_translation_set.rb +61 -0
- data/app/controllers/decidim/term_customizer/admin/add_translations_controller.rb +72 -0
- data/app/controllers/decidim/term_customizer/admin/application_controller.rb +15 -0
- data/app/controllers/decidim/term_customizer/admin/translation_sets_controller.rb +107 -0
- data/app/controllers/decidim/term_customizer/admin/translations_controller.rb +102 -0
- data/app/forms/decidim/term_customizer/admin/translation_form.rb +39 -0
- data/app/forms/decidim/term_customizer/admin/translation_key_import_form.rb +15 -0
- data/app/forms/decidim/term_customizer/admin/translation_set_constraint_form.rb +58 -0
- data/app/forms/decidim/term_customizer/admin/translation_set_form.rb +18 -0
- data/app/forms/decidim/term_customizer/admin/translation_set_subject_component_form.rb +12 -0
- data/app/forms/decidim/term_customizer/admin/translation_set_subject_form.rb +61 -0
- data/app/helpers/decidim/term_customizer/admin/application_helper.rb +13 -0
- data/app/models/decidim/term_customizer/application_record.rb +10 -0
- data/app/models/decidim/term_customizer/constraint.rb +36 -0
- data/app/models/decidim/term_customizer/translation.rb +23 -0
- data/app/models/decidim/term_customizer/translation_set.rb +19 -0
- data/app/permissions/decidim/term_customizer/admin/permissions.rb +66 -0
- data/app/queries/decidim/term_customizer/organization_translation_sets.rb +37 -0
- data/app/queries/decidim/term_customizer/set_translations.rb +21 -0
- data/app/views/decidim/term_customizer/admin/add_translations/index.html.erb +59 -0
- data/app/views/decidim/term_customizer/admin/translation_sets/_constraint_fields.html.erb +58 -0
- data/app/views/decidim/term_customizer/admin/translation_sets/_form.html.erb +29 -0
- data/app/views/decidim/term_customizer/admin/translation_sets/edit.html.erb +9 -0
- data/app/views/decidim/term_customizer/admin/translation_sets/index.html.erb +44 -0
- data/app/views/decidim/term_customizer/admin/translation_sets/new.html.erb +9 -0
- data/app/views/decidim/term_customizer/admin/translations/_form.html.erb +15 -0
- data/app/views/decidim/term_customizer/admin/translations/edit.html.erb +7 -0
- data/app/views/decidim/term_customizer/admin/translations/index.html.erb +52 -0
- data/app/views/decidim/term_customizer/admin/translations/new.html.erb +7 -0
- data/config/locales/en.yml +65 -0
- data/config/locales/fi.yml +65 -0
- data/config/locales/sv.yml +65 -0
- data/lib/decidim/term_customizer/admin.rb +10 -0
- data/lib/decidim/term_customizer/admin_engine.rb +46 -0
- data/lib/decidim/term_customizer/engine.rb +35 -0
- data/lib/decidim/term_customizer/i18n_backend.rb +82 -0
- data/lib/decidim/term_customizer/resolver.rb +108 -0
- data/lib/decidim/term_customizer/test/factories.rb +43 -0
- data/lib/decidim/term_customizer/translation_directory.rb +50 -0
- data/lib/decidim/term_customizer/translation_store.rb +67 -0
- data/lib/decidim/term_customizer/version.rb +8 -0
- data/lib/decidim/term_customizer.rb +21 -0
- metadata +170 -0
data/README.md
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# Decidim::TermCustomizer
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.com/mainio/decidim-module-term_customizer.svg?branch=master)](https://travis-ci.com/mainio/decidim-module-term_customizer)
|
4
|
+
[![codecov](https://codecov.io/gh/mainio/decidim-module-term_customizer/branch/master/graph/badge.svg)](https://codecov.io/gh/mainio/decidim-module-term_customizer)
|
5
|
+
|
6
|
+
The gem has been developed by [Mainio Tech](https://www.mainiotech.fi/).
|
7
|
+
|
8
|
+
A [Decidim](https://github.com/decidim/decidim) module to customize the
|
9
|
+
localized terms in the system. The module allows administrators to add
|
10
|
+
"translation sets" through the admin panel which contain customized terms for
|
11
|
+
any module in the system. These sets can be applied against different scopes
|
12
|
+
within the system, e.g. the whole system, participatory space scope (e.g. all
|
13
|
+
participatory processes or a specific participatory process) or a specific
|
14
|
+
component within a participatory space.
|
15
|
+
|
16
|
+
The term customizations will be only applied to the scope which the admin user
|
17
|
+
has defined for the set. Multiple scopes can be defined against a single
|
18
|
+
translation set.
|
19
|
+
|
20
|
+
Example use cases for this module:
|
21
|
+
|
22
|
+
- Admin wants to change the term "Proposal" to "Idea" in all participatory
|
23
|
+
processes within the system.
|
24
|
+
- Admin wants to change the terms "accepted" and "rejected" in the proposals
|
25
|
+
component to "possible" and "not possible" for a specific participatory
|
26
|
+
process.
|
27
|
+
- Admin wants to change the term "debate" to "discussion" for all assemblies
|
28
|
+
within the system.
|
29
|
+
|
30
|
+
Currently using this gem requires a bit of technical knowledge in defining the
|
31
|
+
terms to be customized. The admin needs to know or find out the translation keys
|
32
|
+
for the terms to be customized.
|
33
|
+
|
34
|
+
## Installation
|
35
|
+
|
36
|
+
Add this line to your application's Gemfile:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
gem "decidim-term_customizer"
|
40
|
+
```
|
41
|
+
|
42
|
+
And then execute:
|
43
|
+
|
44
|
+
```bash
|
45
|
+
$ bundle
|
46
|
+
$ bundle exec rails decidim_term_customizer:install:migrations
|
47
|
+
$ bundle exec rails db:migrate
|
48
|
+
```
|
49
|
+
|
50
|
+
To keep the gem up to date, you can use the commands above to also update it.
|
51
|
+
|
52
|
+
## Usage
|
53
|
+
|
54
|
+
- Install the gem.
|
55
|
+
- Login to the system as an administrator.
|
56
|
+
- Go to the admin panel > Term customizer.
|
57
|
+
- Add a new translation set and give it a name (e.g. "All processes"). The
|
58
|
+
name of the set is only relevant for the admin to identify what that set is
|
59
|
+
used for. It is suggested to give the sets a name that identifies the scope
|
60
|
+
where it is used.
|
61
|
+
- Apply the set to the scope or scopes where you want these customizations to be
|
62
|
+
active.
|
63
|
+
- Save the set.
|
64
|
+
- Add the translations to the set which you want to customize within the defined
|
65
|
+
scope.
|
66
|
+
|
67
|
+
## Contributing
|
68
|
+
|
69
|
+
For instructions how to setup your development environment for Decidim, see [Decidim](https://github.com/decidim/decidim). Also follow Decidim's general
|
70
|
+
instructions for development for this project as well.
|
71
|
+
|
72
|
+
### Developing
|
73
|
+
|
74
|
+
To start contributing to this project, first:
|
75
|
+
|
76
|
+
- Install the basic dependencies (such as Ruby and PostgreSQL)
|
77
|
+
- Clone this repository
|
78
|
+
|
79
|
+
Decidim's main repository also provides a Docker configuration file if you
|
80
|
+
prefer to use Docker instead of installing the dependencies locally on your
|
81
|
+
machine.
|
82
|
+
|
83
|
+
You can create the development app by running the following commands after
|
84
|
+
cloning this project:
|
85
|
+
|
86
|
+
```bash
|
87
|
+
$ bundle
|
88
|
+
$ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rake development_app
|
89
|
+
$ npm i
|
90
|
+
```
|
91
|
+
|
92
|
+
Note that the database user has to have rights to create and drop a database in
|
93
|
+
order to create the dummy test app database.
|
94
|
+
|
95
|
+
Then to test how the module works in Decidim, start the development server:
|
96
|
+
|
97
|
+
```bash
|
98
|
+
$ cd development_app
|
99
|
+
$ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rails s
|
100
|
+
```
|
101
|
+
|
102
|
+
In case you are using [rbenv](https://github.com/rbenv/rbenv) and have the
|
103
|
+
[rbenv-vars](https://github.com/rbenv/rbenv-vars) plugin installed for it, you
|
104
|
+
can add the environment variables to the root directory of the project in a file
|
105
|
+
named `.rbenv-vars`. If these are defined for the environment, you can omit
|
106
|
+
defining these in the commands shown above.
|
107
|
+
|
108
|
+
#### Code Styling
|
109
|
+
|
110
|
+
Please follow the code styling defined by the different linters that ensure we
|
111
|
+
are all talking with the same language collaborating on the same project. This
|
112
|
+
project is set to follow the same rules that Decidim itself follows.
|
113
|
+
|
114
|
+
The following linters are used:
|
115
|
+
|
116
|
+
- Ruby, [Rubocop](https://rubocop.readthedocs.io/)
|
117
|
+
- JS/ES, [eslint](https://eslint.org/)
|
118
|
+
|
119
|
+
You can run the code styling checks by running the following commands from the
|
120
|
+
console:
|
121
|
+
|
122
|
+
```
|
123
|
+
$ bundle exec rubocop
|
124
|
+
$ npm run lint
|
125
|
+
```
|
126
|
+
|
127
|
+
To ease up following the style guide, you should install the plugins to your
|
128
|
+
favorite editor, such as:
|
129
|
+
|
130
|
+
- Atom
|
131
|
+
* [linter-rubocop](https://atom.io/packages/linter-rubocop)
|
132
|
+
* [linter-eslint](https://atom.io/packages/linter-eslint)
|
133
|
+
- Sublime Text
|
134
|
+
* [Sublime RuboCop](https://github.com/pderichs/sublime_rubocop)
|
135
|
+
* [SublimeLinter-eslint](https://github.com/SublimeLinter/SublimeLinter-eslint)
|
136
|
+
- Visual Studio Code
|
137
|
+
* [Rubocop for Visual Studio Code](https://github.com/misogi/vscode-ruby-rubocop)
|
138
|
+
* [VS Code ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
|
139
|
+
|
140
|
+
### Testing
|
141
|
+
|
142
|
+
To run the tests run the following in the gem development path:
|
143
|
+
|
144
|
+
```bash
|
145
|
+
$ bundle
|
146
|
+
$ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rake test_app
|
147
|
+
$ DATABASE_USERNAME=<username> DATABASE_PASSWORD=<password> bundle exec rspec
|
148
|
+
```
|
149
|
+
|
150
|
+
Note that the database user has to have rights to create and drop a database in
|
151
|
+
order to create the dummy test app database.
|
152
|
+
|
153
|
+
In case you are using [rbenv](https://github.com/rbenv/rbenv) and have the
|
154
|
+
[rbenv-vars](https://github.com/rbenv/rbenv-vars) plugin installed for it, you
|
155
|
+
can add these environment variables to the root directory of the project in a
|
156
|
+
file named `.rbenv-vars`. In this case, you can omit defining these in the
|
157
|
+
commands shown above.
|
158
|
+
|
159
|
+
#### Test code coverage
|
160
|
+
|
161
|
+
If you want to generate the code coverage report for the tests, you can use
|
162
|
+
the `SIMPLECOV=1` environment variable in the rspec command as follows:
|
163
|
+
|
164
|
+
```bash
|
165
|
+
$ SIMPLECOV=1 bundle exec rspec
|
166
|
+
```
|
167
|
+
|
168
|
+
This will generate a folder named `coverage` in the project root which contains
|
169
|
+
the code coverage report.
|
170
|
+
|
171
|
+
### Localization
|
172
|
+
|
173
|
+
If you would like to see this module in your own language, you can help with its
|
174
|
+
translation at Crowdin:
|
175
|
+
|
176
|
+
https://crowdin.com/project/decidim-term-customizer
|
177
|
+
|
178
|
+
## License
|
179
|
+
|
180
|
+
See [LICENSE-AGPLv3.txt](LICENSE-AGPLv3.txt).
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "decidim/dev/common_rake"
|
4
|
+
|
5
|
+
def install_module(path)
|
6
|
+
Dir.chdir(path) do
|
7
|
+
system("bundle exec rake decidim_term_customizer:install:migrations")
|
8
|
+
system("bundle exec rake db:migrate")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def seed_db(path)
|
13
|
+
Dir.chdir(path) do
|
14
|
+
system("bundle exec rake db:seed")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Generates a dummy app for testing"
|
19
|
+
task test_app: "decidim:generate_external_test_app" do
|
20
|
+
ENV["RAILS_ENV"] = "test"
|
21
|
+
install_module("spec/decidim_dummy_app")
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Generates a development app"
|
25
|
+
task :development_app do
|
26
|
+
Bundler.with_original_env do
|
27
|
+
generate_decidim_app(
|
28
|
+
"development_app",
|
29
|
+
"--app_name",
|
30
|
+
"#{base_app_name}_development_app",
|
31
|
+
"--path",
|
32
|
+
"..",
|
33
|
+
"--recreate_db",
|
34
|
+
"--demo"
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
install_module("development_app")
|
39
|
+
seed_db("development_app")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Run all tests, include all
|
43
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
44
|
+
t.verbose = false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Run both by default
|
48
|
+
task default: [:spec]
|
@@ -0,0 +1,45 @@
|
|
1
|
+
// = require_self
|
2
|
+
|
3
|
+
(() => {
|
4
|
+
const initConstraintFields = ($section) => {
|
5
|
+
const $select = $("select.constraint-subject-selector", $section);
|
6
|
+
const $modelSelect = $("select.constraint-subject-model-selector", $section);
|
7
|
+
|
8
|
+
$select.on(
|
9
|
+
"change init",
|
10
|
+
|
11
|
+
/* @this HTMLElement */
|
12
|
+
function() {
|
13
|
+
const val = $(this).val();
|
14
|
+
$("[data-manifest]", $section).hide();
|
15
|
+
$(`[data-manifest="${val}"]`, $section).show();
|
16
|
+
}
|
17
|
+
).trigger("init");
|
18
|
+
|
19
|
+
$modelSelect.on(
|
20
|
+
"change init",
|
21
|
+
|
22
|
+
/* @this HTMLElement */
|
23
|
+
function() {
|
24
|
+
const $container = $(this).parents(".manifest-container");
|
25
|
+
const val = $(this).val();
|
26
|
+
$("[data-components]", $container).hide();
|
27
|
+
$(`[data-components="${val}"]`, $container).show();
|
28
|
+
}
|
29
|
+
).trigger("init");
|
30
|
+
};
|
31
|
+
|
32
|
+
$.fn.constraintSection = function() {
|
33
|
+
$(this).each(
|
34
|
+
|
35
|
+
/**
|
36
|
+
* @this HTMLElement
|
37
|
+
* @return {void}
|
38
|
+
*/
|
39
|
+
function() {
|
40
|
+
const $section = $(this);
|
41
|
+
initConstraintFields($section);
|
42
|
+
}
|
43
|
+
)
|
44
|
+
}
|
45
|
+
})();
|
@@ -0,0 +1,103 @@
|
|
1
|
+
((exports) => {
|
2
|
+
const { AutoLabelByPositionComponent, AutoButtonsByPositionComponent, createDynamicFields, createSortList } = exports.DecidimAdmin;
|
3
|
+
|
4
|
+
const initMultifield = ($wrapper) => {
|
5
|
+
const wrapperSelector = `#${$wrapper.attr("id")}`;
|
6
|
+
const placeholderId = $wrapper.data("placeholder-id");
|
7
|
+
|
8
|
+
const fieldSelector = ".multifield-field";
|
9
|
+
|
10
|
+
const autoLabelByPosition = new AutoLabelByPositionComponent({
|
11
|
+
listSelector: `${wrapperSelector} .multifield-field:not(.hidden)`,
|
12
|
+
labelSelector: ".card-title span:first",
|
13
|
+
onPositionComputed: (el, idx) => {
|
14
|
+
$(el).find("input.position-input").val(idx);
|
15
|
+
}
|
16
|
+
});
|
17
|
+
|
18
|
+
const autoButtonsByPosition = new AutoButtonsByPositionComponent({
|
19
|
+
listSelector: `${wrapperSelector} .multifield-field:not(.hidden)`,
|
20
|
+
hideOnFirstSelector: ".move-up-field",
|
21
|
+
hideOnLastSelector: ".move-down-field"
|
22
|
+
});
|
23
|
+
|
24
|
+
const createSortableList = () => {
|
25
|
+
createSortList(`${wrapperSelector} .fields-list:not(.published)`, {
|
26
|
+
handle: ".multifield-field-divider",
|
27
|
+
placeholder: '<div style="border-style: dashed; border-color: #000"></div>',
|
28
|
+
forcePlaceholderSize: true,
|
29
|
+
onSortUpdate: () => { autoLabelByPosition.run() }
|
30
|
+
});
|
31
|
+
};
|
32
|
+
|
33
|
+
const hideDeletedSection = ($target) => {
|
34
|
+
const inputDeleted = $target.find("input[name$=\\[deleted\\]]").val();
|
35
|
+
|
36
|
+
if (inputDeleted === "true") {
|
37
|
+
$target.addClass("hidden");
|
38
|
+
$target.hide();
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
createDynamicFields({
|
43
|
+
placeholderId: placeholderId,
|
44
|
+
wrapperSelector: wrapperSelector,
|
45
|
+
containerSelector: ".multifield-fields-list",
|
46
|
+
fieldSelector: fieldSelector,
|
47
|
+
addFieldButtonSelector: ".add-field",
|
48
|
+
removeFieldButtonSelector: ".remove-field",
|
49
|
+
moveUpFieldButtonSelector: ".move-up-field",
|
50
|
+
moveDownFieldButtonSelector: ".move-down-field",
|
51
|
+
onAddField: ($newField) => {
|
52
|
+
createSortableList();
|
53
|
+
|
54
|
+
autoLabelByPosition.run();
|
55
|
+
autoButtonsByPosition.run();
|
56
|
+
|
57
|
+
$wrapper.trigger("add-field-section", $newField);
|
58
|
+
},
|
59
|
+
onRemoveField: () => {
|
60
|
+
autoLabelByPosition.run();
|
61
|
+
autoButtonsByPosition.run();
|
62
|
+
},
|
63
|
+
onMoveUpField: () => {
|
64
|
+
autoLabelByPosition.run();
|
65
|
+
autoButtonsByPosition.run();
|
66
|
+
},
|
67
|
+
onMoveDownField: () => {
|
68
|
+
autoLabelByPosition.run();
|
69
|
+
autoButtonsByPosition.run();
|
70
|
+
}
|
71
|
+
});
|
72
|
+
|
73
|
+
createSortableList();
|
74
|
+
|
75
|
+
$(fieldSelector).each((idx, el) => {
|
76
|
+
const $target = $(el);
|
77
|
+
|
78
|
+
hideDeletedSection($target);
|
79
|
+
});
|
80
|
+
|
81
|
+
autoLabelByPosition.run();
|
82
|
+
autoButtonsByPosition.run();
|
83
|
+
}
|
84
|
+
|
85
|
+
$.fn.multifield = function() {
|
86
|
+
$(this).each(
|
87
|
+
|
88
|
+
/**
|
89
|
+
* @this HTMLElement
|
90
|
+
* @return {void}
|
91
|
+
*/
|
92
|
+
function() {
|
93
|
+
const $elem = $(this);
|
94
|
+
let id = $elem.attr("id");
|
95
|
+
if (!id || id.length < 1) {
|
96
|
+
id = `multifield-${Math.random().toString(16).slice(2)}`;
|
97
|
+
$elem.attr("id", id);
|
98
|
+
}
|
99
|
+
initMultifield($elem);
|
100
|
+
}
|
101
|
+
)
|
102
|
+
}
|
103
|
+
})(window);
|
@@ -0,0 +1,5 @@
|
|
1
|
+
// = require decidim/admin/auto_buttons_by_position.component
|
2
|
+
// = require decidim/admin/auto_label_by_position.component
|
3
|
+
// = require decidim/admin/dynamic_fields.component
|
4
|
+
// = require decidim/admin/sort_list.component
|
5
|
+
// = require decidim/term_customizer/admin/multifield/component
|
@@ -0,0 +1,19 @@
|
|
1
|
+
// = require decidim/term_customizer/admin/multifield
|
2
|
+
// = require decidim/term_customizer/admin/constraint_fields
|
3
|
+
// = require_self
|
4
|
+
|
5
|
+
$(() => {
|
6
|
+
const $fields = $("form.translation-sets-form .multifield-fields");
|
7
|
+
|
8
|
+
$fields.multifield();
|
9
|
+
$fields.on(
|
10
|
+
"add-field-section",
|
11
|
+
|
12
|
+
/* @this HTMLElement */
|
13
|
+
function(ev, newField) {
|
14
|
+
$(newField).constraintSection();
|
15
|
+
}
|
16
|
+
);
|
17
|
+
|
18
|
+
$(".constraints-list", $fields).constraintSection();
|
19
|
+
});
|
@@ -0,0 +1,72 @@
|
|
1
|
+
// = require_self
|
2
|
+
|
3
|
+
$(() => {
|
4
|
+
const $search = $("#data_picker-autocomplete");
|
5
|
+
const $results = $("#add-translations-results");
|
6
|
+
const $template = $("template", $results);
|
7
|
+
const $form = $search.parents("form");
|
8
|
+
let xhr = null;
|
9
|
+
let currentSearch = "";
|
10
|
+
|
11
|
+
$search.on("keyup", function() {
|
12
|
+
currentSearch = $search.val();
|
13
|
+
});
|
14
|
+
|
15
|
+
$search.autoComplete({
|
16
|
+
minChars: 2,
|
17
|
+
cache: 0,
|
18
|
+
source: function(term, response) {
|
19
|
+
try {
|
20
|
+
xhr.abort();
|
21
|
+
} catch (exception) { xhr = null; }
|
22
|
+
|
23
|
+
const url = $form.attr("action");
|
24
|
+
xhr = $.getJSON(
|
25
|
+
url,
|
26
|
+
$form.serializeArray(),
|
27
|
+
function(data) { response(data); }
|
28
|
+
);
|
29
|
+
},
|
30
|
+
renderItem: function (item, search) {
|
31
|
+
const sanitizedSearch = search.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
32
|
+
const re = new RegExp(`(${sanitizedSearch.split(" ").join("|")})`, "gi");
|
33
|
+
const modelId = item[0];
|
34
|
+
const title = item[1];
|
35
|
+
const val = `${title} - ${modelId}`;
|
36
|
+
return `<div class="autocomplete-suggestion" data-model-id="${modelId}" data-val="${title}">${val.replace(re, "<b>$1</b>")}</div>`;
|
37
|
+
},
|
38
|
+
onSelect: function(event, term, item) {
|
39
|
+
const $suggestions = $search.data("sc");
|
40
|
+
const modelId = item.data("modelId");
|
41
|
+
const title = item.data("val");
|
42
|
+
|
43
|
+
let template = $template.html();
|
44
|
+
template = template.replace(new RegExp("{{translation_key}}", "g"), modelId);
|
45
|
+
template = template.replace(new RegExp("{{translation_term}}", "g"), title);
|
46
|
+
const $newRow = $(template);
|
47
|
+
$("table tbody", $results).append($newRow);
|
48
|
+
$results.removeClass("hide");
|
49
|
+
|
50
|
+
// Add it to the autocomplete form
|
51
|
+
const $field = $(`<input type="hidden" name="keys[]" value="${modelId}">`);
|
52
|
+
$form.append($field);
|
53
|
+
|
54
|
+
// Listen to the click event on the remove button
|
55
|
+
$(".remove-translation-key", $newRow).on("click", function(ev) {
|
56
|
+
ev.preventDefault();
|
57
|
+
$newRow.remove();
|
58
|
+
$field.remove();
|
59
|
+
|
60
|
+
if ($("table tbody tr", $results).length < 1) {
|
61
|
+
$results.addClass("hide");
|
62
|
+
}
|
63
|
+
});
|
64
|
+
|
65
|
+
$search.val(currentSearch);
|
66
|
+
setTimeout(function() {
|
67
|
+
$(`[data-model-id="${modelId}"]`, $suggestions).remove();
|
68
|
+
$suggestions.show();
|
69
|
+
}, 20);
|
70
|
+
}
|
71
|
+
});
|
72
|
+
});
|