decidim 0.23.6 → 0.24.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim might be problematic. Click here for more details.

Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -0
  3. data/docs/README.adoc +74 -0
  4. data/docs/antora.yml +7 -0
  5. data/docs/modules/configure/pages/environment_variables.adoc +69 -0
  6. data/docs/modules/configure/pages/index.adoc +16 -0
  7. data/docs/modules/configure/pages/initializer.adoc +376 -0
  8. data/docs/modules/customize/assets/images/header-snippet.png +0 -0
  9. data/docs/modules/customize/assets/images/menu.png +0 -0
  10. data/docs/modules/customize/assets/images/organization-colors.png +0 -0
  11. data/docs/modules/customize/pages/authorizations.adoc +22 -0
  12. data/docs/{customization/code.md → modules/customize/pages/code.adoc} +12 -9
  13. data/docs/{customization/gemfile.md → modules/customize/pages/gemfile.adoc} +5 -4
  14. data/docs/modules/customize/pages/images.adoc +7 -0
  15. data/docs/modules/customize/pages/javascript.adoc +59 -0
  16. data/docs/modules/customize/pages/menu.adoc +25 -0
  17. data/docs/modules/customize/pages/oauth.adoc +33 -0
  18. data/docs/modules/customize/pages/styles.adoc +64 -0
  19. data/docs/modules/customize/pages/texts.adoc +30 -0
  20. data/docs/modules/customize/pages/users_registration_mode.adoc +17 -0
  21. data/docs/{customization/views.md → modules/customize/pages/views.adoc} +13 -13
  22. data/docs/modules/develop/assets/images/barcelona.png +0 -0
  23. data/docs/modules/develop/assets/images/helsinki.png +0 -0
  24. data/docs/modules/develop/assets/images/indices.png +0 -0
  25. data/docs/{advanced/api.md → modules/develop/pages/api.adoc} +2 -2
  26. data/docs/{advanced/authorship.md → modules/develop/pages/authorable.adoc} +5 -5
  27. data/docs/modules/develop/pages/c4_component.adoc +91 -0
  28. data/docs/modules/develop/pages/c4_container.adoc +42 -0
  29. data/docs/modules/develop/pages/c4_context.adoc +35 -0
  30. data/docs/{advanced/components.md → modules/develop/pages/components.adoc} +47 -10
  31. data/docs/{advanced/content_blocks.md → modules/develop/pages/content_blocks.adoc} +16 -13
  32. data/docs/{advanced/content_processors.md → modules/develop/pages/content_processors.adoc} +25 -19
  33. data/docs/modules/develop/pages/data-picker.adoc +85 -0
  34. data/docs/modules/develop/pages/deploy.adoc +15 -0
  35. data/docs/modules/develop/pages/docker.adoc +12 -0
  36. data/docs/{advanced/embeddable.md → modules/develop/pages/embeddable.adoc} +6 -6
  37. data/docs/{advanced/endorsable.md → modules/develop/pages/endorsable.adoc} +31 -25
  38. data/docs/{advanced/fixing_locales.md → modules/develop/pages/fixing_locales.adoc} +36 -23
  39. data/docs/{advanced/followers.md → modules/develop/pages/followable.adoc} +9 -8
  40. data/docs/modules/develop/pages/guide.adoc +16 -0
  41. data/docs/modules/develop/pages/guide_architecture.adoc +17 -0
  42. data/docs/modules/develop/pages/guide_changelog.adoc +8 -0
  43. data/docs/modules/develop/pages/guide_commands.adoc +86 -0
  44. data/docs/modules/develop/pages/guide_development_app.adoc +44 -0
  45. data/docs/modules/develop/pages/guide_development_with_custom_seed_data.adoc +31 -0
  46. data/docs/modules/develop/pages/guide_development_with_localhost_ssl.adoc +63 -0
  47. data/docs/modules/develop/pages/guide_example_apps.adoc +59 -0
  48. data/docs/modules/develop/pages/guide_git_conventions.adoc +75 -0
  49. data/docs/modules/develop/pages/guide_github_projects.adoc +42 -0
  50. data/docs/modules/develop/pages/guide_semver.adoc +7 -0
  51. data/docs/{advanced/how_to_fix_metrics.md → modules/develop/pages/how_to_fix_metrics.adoc} +76 -59
  52. data/docs/modules/develop/pages/machine_translations.adoc +42 -0
  53. data/docs/modules/develop/pages/managing_translations_i18n.adoc +24 -0
  54. data/docs/modules/develop/pages/maps.adoc +499 -0
  55. data/docs/modules/develop/pages/metrics.adoc +119 -0
  56. data/docs/{advanced/modules.md → modules/develop/pages/modules.adoc} +16 -6
  57. data/docs/{advanced/newsletter_templates.md → modules/develop/pages/newsletter_templates.adoc} +12 -10
  58. data/docs/{advanced/notifications.md → modules/develop/pages/notifications.adoc} +40 -38
  59. data/docs/{advanced/open-data.md → modules/develop/pages/open-data.adoc} +4 -3
  60. data/docs/modules/develop/pages/permissions.adoc +92 -0
  61. data/docs/{advanced/profiling.md → modules/develop/pages/profiling.adoc} +15 -12
  62. data/docs/modules/develop/pages/releases.adoc +148 -0
  63. data/docs/modules/develop/pages/reportable.adoc +31 -0
  64. data/docs/modules/develop/pages/security.adoc +33 -0
  65. data/docs/{advanced/share_tokens.md → modules/develop/pages/share_tokens.adoc} +18 -14
  66. data/docs/{advanced/templates.md → modules/develop/pages/templates.adoc} +14 -12
  67. data/docs/{advanced/testing.md → modules/develop/pages/testing.adoc} +21 -20
  68. data/docs/{advanced/activity_log.md → modules/develop/pages/traceable.adoc} +31 -26
  69. data/docs/modules/develop/pages/turbolinks.adoc +7 -0
  70. data/docs/{advanced/view_hooks.md → modules/develop/pages/view_hooks.adoc} +29 -23
  71. data/docs/modules/develop/pages/view_models_aka_cells.adoc +105 -0
  72. data/docs/modules/install/pages/checklist.adoc +39 -0
  73. data/docs/modules/install/pages/index.adoc +148 -0
  74. data/docs/{manual-installation.md → modules/install/pages/manual.adoc} +54 -42
  75. data/docs/modules/install/pages/update.adoc +95 -0
  76. data/docs/{services/activejob.md → modules/services/pages/activejob.adoc} +3 -3
  77. data/docs/modules/services/pages/elections_bulletin_board.adoc +52 -0
  78. data/docs/{services/etherpad.md → modules/services/pages/etherpad.adoc} +15 -12
  79. data/docs/modules/services/pages/maps.adoc +311 -0
  80. data/docs/modules/services/pages/smtp.adoc +10 -0
  81. data/docs/modules/services/pages/social_providers.adoc +122 -0
  82. data/lib/decidim/gem_manager.rb +5 -5
  83. data/lib/decidim/version.rb +1 -1
  84. metadata +137 -100
  85. data/README.md +0 -157
  86. data/docs/advanced/add_authorizable_action.md +0 -63
  87. data/docs/advanced/adding_fixtures_aka_dummy_content.md +0 -9
  88. data/docs/advanced/data-picker.md +0 -83
  89. data/docs/advanced/deploy.md +0 -9
  90. data/docs/advanced/how_to_create_a_module.md +0 -9
  91. data/docs/advanced/machine_translation_service.md +0 -12
  92. data/docs/advanced/managing_translations_i18n.md +0 -24
  93. data/docs/advanced/metrics.md +0 -114
  94. data/docs/advanced/permissions.md +0 -23
  95. data/docs/advanced/releases.md +0 -114
  96. data/docs/advanced/tradeoffs.md +0 -14
  97. data/docs/advanced/view_models_aka_cells.md +0 -99
  98. data/docs/checklist.md +0 -55
  99. data/docs/customization/authorizations.md +0 -5
  100. data/docs/customization/images.md +0 -7
  101. data/docs/customization/javascript.md +0 -9
  102. data/docs/customization/machine_translations.md +0 -30
  103. data/docs/customization/maps.md +0 -610
  104. data/docs/customization/oauth.md +0 -50
  105. data/docs/customization/styles.md +0 -11
  106. data/docs/customization/texts.md +0 -27
  107. data/docs/customization/users_registration_mode.md +0 -17
  108. data/docs/development_guide.md +0 -166
  109. data/docs/getting_started.md +0 -191
  110. data/docs/possible_flows_for_proposal.png +0 -0
  111. data/docs/services/analytics.md +0 -23
  112. data/docs/services/elections_bulletin_board.md +0 -38
  113. data/docs/services/maps.md +0 -362
  114. data/docs/services/social_providers.md +0 -98
@@ -0,0 +1,42 @@
1
+ = Using machine translations
2
+
3
+ For multilingual organizations, Decidim includes a way to integrate with amachine translation service. The aim of this integration is to provide machine translations for any user-generated content.
4
+
5
+ == Flow description
6
+
7
+ Every time a user creates or updates a translatable resource (that is, an instance of a resource that implements the `Decidim::TranslatableResource` concern), this workflow is triggered:
8
+
9
+ * A background job starts for the resource. This background job lists the fields that have been changed, and checks if any of the fields is considered translatable.
10
+ * For each translatable field that is changed, it lists the locales that need to be translated.
11
+ * For each combination field/locale a new job is fired.
12
+ * This job calls the machine translation service, which will handle how to translate that given text.
13
+
14
+ This workflow will only start if the machine translation service is configured in the installation, and the organization has the service enabled.
15
+
16
+ == Create your own machine translation service
17
+
18
+ You can use the `Decidim::Dev::DummyTranslator` service as a base. Any new translator service will need to implement the same API as this class.
19
+
20
+ == Integrating with async services
21
+
22
+ Some translation services are async, which means that some extra work is needed. This is the main overview:
23
+
24
+ * The Translation service will only send the translation request. It should have a way to send what resource, field and target locale are related to that translation.
25
+ * You'll need to create a custom controller in your application to receive the callback from the translation service when the translation is finished
26
+ * From that new endpoint, find a way to find the related resource, field and target locale. Then start a `Decidim::MachineTranslationSaveJob` with that data. This job will handle how to save the data in the DB.
27
+
28
+ == Enabling the integration, installation-wise
29
+
30
+ This is an option in the Decidim initializer:
31
+
32
+ [source,ruby]
33
+ ----
34
+ config.enable_machine_translations = true
35
+ config.machine_translation_service = "MyApp::MyOwnTranslationService"
36
+ ----
37
+
38
+ The class will need to be implemented, or reuse one from the community. Check the docs on how to implement a machine translation service.
39
+
40
+ == Enabling the integration, organization-wise
41
+
42
+ Each organization will be able to enable/disable machine translations if they want to. They can do that from the organization configuration.
@@ -0,0 +1,24 @@
1
+ = Managing translations (i18n)
2
+
3
+ == The workflow
4
+
5
+ Decidim uses https://crowdin.com/[Crowdin] to manage the translations.
6
+
7
+ * Whenever someone https://github.com/decidim/decidim/pull/1814/files#diff-c78c80097da59920d55b3f462ca21afaR177[adds a new translation key] to _Decidim_, _Crowdin_ gets notified and the new content is available to be translated from https://crowdin.com/project/decidim[Crowdin's Decidim dashboard].
8
+ * When a translator translates any key from Crowdin, it automatically creates a https://github.com/decidim/decidim/pulls?utf8=%E2%9C%93&q=is%3Apr%20author%3Adecidim-bot%20Crowdin[PR in Github], adding the keys in the corresponding _yaml_ files.
9
+ * 🌈
10
+
11
+ == Adding a new language
12
+
13
+ * Setup the new language in https://crowdin.com/project/decidim[_Crowdin's Decidim project_] (or open an issue on Github asking an admin to do that).
14
+ * Add the locale mapping in the `crowdin.yml` file
15
+ * Translate at least one key from every engine, so, your _yaml_ files are not empty. The easiest way to do this is to automatically translate and sync all the content. Later you'll be able to fix the content that wasn't properly translated.
16
+ * Add https://github.com/najlepsiwebdesigner/foundation-datepicker/tree/master/js/locales[Foundation Datepicker]'s translations (https://github.com/decidim/decidim/pull/2039[PR]).
17
+ * Add the new language to `available_locales` (https://github.com/decidim/decidim/pull/1991[PR]).
18
+ * Add the language in https://github.com/decidim/decidim/pull/5080/files#diff-9c9dc1c8c25dcecdfb8ce555d5ef5e47R15[decidim-core/spec/lib/available_locales_spec.rb].
19
+
20
+ == Test the new language
21
+
22
+ * Generate the development app and `cd` into it.
23
+ * Change the `config/initializer/decidim.rb` file and add your locale to `Decidim.available_locales`.
24
+ * `rake db:drop db:setup` to drop, create, load schema and seed the DB.
@@ -0,0 +1,499 @@
1
+ = Custom map providers
2
+
3
+ Decidim can be configured to use multiple different xref:/docs/services/maps.adoc[map service providers] but it can be also extended to use any possible service provider out there.
4
+
5
+ If you want to create your own provider integration, you will need to find a service provider that provides all the following services:
6
+
7
+ * https://en.wikipedia.org/wiki/Geocoding[A geocoding server] in order to turn user entered addresses into https://en.wikipedia.org/wiki/Geographic_coordinate_system[geocoordinates].
8
+ * https://en.wikipedia.org/wiki/Autocomplete[A geocoding autocompletion server] in order to suggest and predict addresses based on the user input and turning these suggested addresses into https://en.wikipedia.org/wiki/Geographic_coordinate_system[geocoordinates].
9
+ * https://en.wikipedia.org/wiki/Tile_Map_Service[A map tile server] for the dynamic maps, preferrably one that is compatible with the default https://leafletjs.com/[Leaflet] map library.
10
+ * https://wiki.openstreetmap.org/wiki/Static_map_images[A static map image server] for the static map images e.g.
11
+ on the proposal pages.
12
+ This service is optional as Decidim will use the dynamic map tiles to generate a similar map element if the static map image cannot be provided.
13
+
14
+ One option is to host some or all of these services yourself as there are open source alternatives available for all of these services.
15
+ More information about self hosting is available at the link:/docs/services/maps.md#combining-multiple-service-providers[maps and geocoding configuration] documentation.
16
+
17
+ You may also decide to link:/docs/services/maps.md#disabling[disable some of the services] that are not available at your service provider but in order to get the full out of Decidim, it is recommended to find a service provider with all these services.
18
+
19
+ In case you want to use different service providers for the different categories of map services, that is also possible.
20
+ Instructions for this are provided in the link:/docs/services/maps.md#combining-multiple-service-providers[maps and geocoding configuration] documentation.
21
+
22
+ == Creating your own map service provider
23
+
24
+ First thing you will need is to define a service provider module which also defines all the services your provider is able to serve.
25
+ An example service provider module looks as follows:
26
+
27
+ [source,ruby]
28
+ ----
29
+ module Decidim
30
+ module Map
31
+ module Provider
32
+ module Geocoding
33
+ autoload :YourProvider, "decidim/map/provider/geocoding/your_provider"
34
+ end
35
+ module Autocomplete
36
+ autoload :YourProvider, "decidim/map/provider/autocomplete/your_provider"
37
+ end
38
+ module DynamicMap
39
+ autoload :YourProvider, "decidim/map/provider/dynamic_map/your_provider"
40
+ end
41
+ module StaticMap
42
+ autoload :YourProvider, "decidim/map/provider/static_map/your_provider"
43
+ end
44
+ end
45
+ end
46
+ end
47
+ ----
48
+
49
+ Please note that you will need to place the utility classes for each category of services under the paths defined for the autoloading functionality.
50
+
51
+ === Defining the geocoding utility
52
+
53
+ For the geocoding functionality, Decidim uses the https://github.com/alexreisner/geocoder[Geocoder gem] which does most of the heavy lifting.
54
+ It is not necessary to use this gem but in case your target service is already integrated with that gem, it makes this step much easier for you.
55
+ Take a look at the list of https://github.com/alexreisner/geocoder/blob/master/README_API_GUIDE.md[supported geocoding APIs] for the Geocoder gem.
56
+
57
+ In case your API is supported by the Geocoder gem, the only thing you need to do to create your geocoding utility is to create the following empty class:
58
+
59
+ [source,ruby]
60
+ ----
61
+ module Decidim
62
+ module Map
63
+ module Provider
64
+ module Geocoding
65
+ class YourProvider < ::Decidim::Map::Geocoding
66
+ # ... add your customizations here ...
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ ----
73
+
74
+ If the target service has some other "lookup handle" defined in the Geocoder gem than `:your_provider`, you may want to override the `handle` method in the geocoding utility's class you just defined.
75
+ This is passed for the Geocoder gem as your lookup handle.
76
+ An example of this can be seen in the link:/decidim-core/lib/decidim/map/provider/geocoding/osm.rb[`Decidim::Map::Provider::Geocoding::Osm`] class which changes the handle to `:nominatim` instead of the default `:osm` which is not an existing lookup handle in the Geocoder gem.
77
+
78
+ In case you want to customize the geocoding utility for your provider, you can define the following methods in the utility class:
79
+
80
+ * `search(query, options = {})` - A common method for searching the geocoding API and returning an array of results.
81
+ The results array contains the Geocoder gem's result objects of type https://github.com/alexreisner/geocoder/blob/master/lib/geocoder/results/base.rb[`Geocoder::Result::Base`] or the result type specific to your API.
82
+ If the first parameter is an address string, the method does a forward geocoding request finding the closest matching coordinate pairs for that address.
83
+ If the first parameter is a coordinate pair array, the method does a reverse geocoding request finding the closest matching addresses for the search.
84
+ * `coordinates(address, options = {})` - A method that searches the best matching coordinates for the given address string.
85
+ Only returns one coordinate pair as an array.
86
+ * `address(coordinates, options = {})` - A method that searches the best matching address for the given coordinate pair array.
87
+ Only returns one address as a string.
88
+
89
+ Customization may be needed if you are not happy with the default results returned by the Geocoder gem.
90
+ For instance, in some occasions you might want to pass extra query options to the geocoding API or sort the results differently than what was returned by the API and what is already done in Decidim by default.
91
+
92
+ In order to provide configuration options for the Geocoder gem's lookup, you can pass them directly through the maps configuration with the following syntax:
93
+
94
+ [source,ruby]
95
+ ----
96
+ config.maps = {
97
+ provider: :your_provider,
98
+ api_key: Rails.application.secrets.maps[:api_key],
99
+ geocoding: { extra_option: "value", another_option: "value" }
100
+ }
101
+ ----
102
+
103
+ This would equal to configuring the Geocoder gem with the following code:
104
+
105
+ [source,ruby]
106
+ ----
107
+ Geocoder.configure(
108
+ your_provider: {
109
+ api_key: Rails.application.secrets.maps[:api_key],
110
+ extra_option: "value",
111
+ another_option: "value"
112
+ }
113
+ )
114
+ ----
115
+
116
+ Each geocoding API may require their own configuration options.
117
+ Please refer to the Geocoder gem's https://github.com/alexreisner/geocoder/blob/master/README_API_GUIDE.md[supported geocoding APIs] documentation to find out the available options for your API.
118
+
119
+ === Defining the geocoding autocompletion maps utility
120
+
121
+ For the geocoding autocompletion map functionality, you should preferrably use a service provider that is compatible with https://github.com/komoot/photon[Photon] which is already integrated with Decidim.
122
+
123
+ If this is not possible, you can also create a custom geocoding autocompletion maps utility for your own service provider by defining the following empty class to start with:
124
+
125
+ [source,ruby]
126
+ ----
127
+ module Decidim
128
+ module Map
129
+ module Provider
130
+ module Autocomplete
131
+ class YourProvider < ::Decidim::Map::Autocomplete
132
+ # ... add your customizations here ...
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ ----
139
+
140
+ In case you want to customize the geocoding autocompletion map utility for your provider, you can define the following methods in the utility class:
141
+
142
+ * `builder_class` - Returns a class for the geocoding autocompletion builder that is used to create the input fields for the autocompleted addresses in the front-end.
143
+ By default, this would be `Decidim::Map::Provider::Autocomplete::YourProvider::Builder` or if that is not defined, defaults to `Decidim::Map::Autocomplete::Builder`.
144
+ See below for further notes about the builder class.
145
+ * `builder_options` - A method that prepares the options for the builder instance that is used to create the maps in the front-end.
146
+ By default, this is an empty hash that needs to be configured for each provider.
147
+
148
+ To see an example how to customize the static map utility, take a look at the link:/decidim-core/lib/decidim/map/provider/autocomplete/here.rb[HERE Maps geocoding autocomletion utility].
149
+
150
+ In order to provide configuration options for the geocoding autocompletion, you can pass them directly through the maps configuration with the following syntax:
151
+
152
+ [source,ruby]
153
+ ----
154
+ config.maps = {
155
+ provider: :your_provider,
156
+ api_key: Rails.application.secrets.maps[:api_key],
157
+ autocomplete: {
158
+ url: "https://photon.example.org/api/"
159
+ }
160
+ }
161
+ ----
162
+
163
+ And then you can use these options in your provider utility as follows e.g.
164
+ in the `builder_options` method:
165
+
166
+ [source,ruby]
167
+ ----
168
+ def builder_options
169
+ { url: configuration.fetch(:url, nil) }.compact
170
+ end
171
+ ----
172
+
173
+ You will also need to define a builder class inside your provider utility class as follows:
174
+
175
+ [source,ruby]
176
+ ----
177
+ module Decidim
178
+ module Map
179
+ module Provider
180
+ module Autocomplete
181
+ class Here < ::Decidim::Map::Autocomplete
182
+ # ... other customizations go gere ...
183
+
184
+ # This is the actual builder customization where you could define e.g.
185
+ # the JavaScript asset which is used to initialize the geocoding
186
+ # autocompletion functionality in the front-end:
187
+ class Builder < Decidim::Map::Autocomplete::Builder
188
+ def javascript_snippets
189
+ template.javascript_include_tag("decidim/geocoding/provider/your_provider")
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+ ----
198
+
199
+ To see an example of the front-end JavaScript code that handles the geocoding requests, you can take a look at the link:/decidim-core/app/assets/javascripts/decidim/geocoding/provider/here.js.es6[HERE Maps example].
200
+ You will have to listen to the `geocoder-suggest.decidim` JavaScript event on all elements that have the `data-decidim-geocoding` attribute defined which contains all the configurations returned by the builder's `builder_options` method as mentioned above.
201
+ For example, if you passed the following configuration from that method:
202
+
203
+ [source,js]
204
+ ----
205
+ { url: "https://photon.example.org/api/", other_config: "foo" }
206
+ ----
207
+
208
+ This would be available in the JavaScript as follows:
209
+
210
+ [source,js]
211
+ ----
212
+ $(document).on("ready", () => {
213
+ $("[data-decidim-geocoding]").each((_i, el) => {
214
+ console.log($(el).data("decidim-geocoding"));
215
+ // => This would print out:
216
+ // {url: "https://photon.example.org/api/", otherConfig: "foo"}
217
+ });
218
+ });
219
+ ----
220
+
221
+ When you hook into the `geocoder-suggest.decidim` event on these methods, the event callback will be provided three arguments:
222
+
223
+ * `event` - The event that you hooked into
224
+ * `query` - The text to be queried, i.e.
225
+ what the user entered into the input
226
+ * `callback` - A callback method which you will need to call with your geocoding autocompletion results once the request to the API has finished in the front-end.
227
+
228
+ The `callback` method expects one argument which is the array of result objects.
229
+ The result objects need to contain the following keys:
230
+
231
+ * `key` - The key which will be matched against the user entered input
232
+ * `value` - The value which will be added to the address input if the user decides to select this value
233
+
234
+ Optionally, you can also include a `coordinates` key in the result object which contains an array of two cordinates (latitude and longitude respectively).
235
+ You can also include any other data you might need in the front-end for these results but it will be not used by Decidim.
236
+
237
+ The final code would look something like follows:
238
+
239
+ [source,js]
240
+ ----
241
+ $(document).on("ready", () => {
242
+ $("[data-decidim-geocoding]").each((_i, el) => {
243
+ const $input = $(el);
244
+ const config = $input.data("decidim-geocoding");
245
+
246
+ $input.on("geocoder-suggest.decidim", (event, query, callback) => {
247
+ currentSuggestionQuery = setTimeout(() => {
248
+ $.ajax({
249
+ method: "GET",
250
+ url: config.url,
251
+ data: { apiKey: config.apiKey },
252
+ dataType: "json"
253
+ }).done((resp) => {
254
+ if (resp.suggestions) {
255
+ return callback(resp.suggestions.map((item) => {
256
+ return {
257
+ key: item.label,
258
+ value: item.label,
259
+ coordinates: [item.latitude, item.longitude],
260
+ yourExtraData: item.yourExtraData
261
+ }
262
+ }));
263
+ }
264
+ return null;
265
+ });
266
+ });
267
+ });
268
+ });
269
+ ----
270
+
271
+ If your autocompletion API does not provide the coordinates information along with the autocompletion requests, you can hook into another event to do extra queries for the geocoordinates as follows:
272
+
273
+ [source,js]
274
+ ----
275
+ $(document).on("ready", () => {
276
+ $("geocoder-suggest-select.decidim", (ev, selectedItem) => {
277
+ console.log(selectedItem);
278
+ // => This would print out what you returned for the `callback` as shown
279
+ // above.
280
+
281
+ // NOTE: YOU DON'T NEED THIS IF YOUR RESPONSE OBJECTS ALREADY CONTAINED THE
282
+ // COORDINATES IN THE `coordinates` KEY OF EACH RESULT OBJECT!
283
+ // Then, once you know the coordinates, you trigger the following event on
284
+ // the same input (obviously, you need to query the API first):
285
+ const coordinates = [1.123, 2.234];
286
+ $(ev.target).trigger("geocoder-suggest-coordinates.decidim", [coordinates]);
287
+ });
288
+ });
289
+ ----
290
+
291
+ Finally, if you want to pass these coordinates to the same form where your address field is located at, you can use the `Decidim.attachGeocoding()` method as follows:
292
+
293
+ [source,js]
294
+ ----
295
+ $(document).ready(function() {
296
+ Decidim.attachGeocoding($("#your_address_input"));
297
+ });
298
+ ----
299
+
300
+ Now the latitude and longitude coordinates would be passed to the same form where the address input is located at.
301
+ For example, if the address input had the name `record[address]`, new hidden fields would be now generated for the geocoding autocomplete suggestion's coordinates with the following names:
302
+
303
+ * `record[latitude]` for the latitude coordinate
304
+ * `record[longitude]` for the longitude coordinate
305
+
306
+ Then, you can read these values along with the form's POST data in order to store the coordinates for your records in the back-end.
307
+ This is not 100% necessary but it improves the accuracy of the geocoding functionality and it also avoids unnecessary double requests to the geocoding API (front-end + back-end).
308
+
309
+ === Defining the dynamic maps utility
310
+
311
+ For the dynamic map functionality, you should primarily use a service provider that is compatible with the https://leafletjs.com/[Leaflet library] that ships with Decidim.
312
+ You can also integrate to services that are not compatible with Leaflet but it will cause you more work and is not covered by this guide.
313
+
314
+ Please note that you don't necessarily even need to create your own dynamic maps utility if your service provider is already compatible with the link:/decidim-core/lib/decidim/map/provider/dynamic_map/osm.rb[`Decidim::Map::Provider::DynamicMap::Osm`] provider.
315
+ In order to configure your custom OSM compatible service provider take a look at the link:/docs/services/maps.md#configuring-open-street-maps-based-service-providers[maps and geocoding configuration] documentation.
316
+
317
+ If your service provider is not fully compatible with the default OSM provider, you can start writing your customizations by creating an empty dynamic map provider utility with the following code:
318
+
319
+ [source,ruby]
320
+ ----
321
+ module Decidim
322
+ module Map
323
+ module Provider
324
+ module DynamicMap
325
+ class YourProvider < ::Decidim::Map::DynamicMap
326
+ # ... add your customizations here ...
327
+ end
328
+ end
329
+ end
330
+ end
331
+ end
332
+ ----
333
+
334
+ In case you want to customize the dynamic map utility for your provider, you can define the following methods in the utility class:
335
+
336
+ * `builder_class` - Returns a class for the dynamic map builder that is used to create the maps in the front-end.
337
+ By default, this would be `Decidim::Map::Provider::DynamicMap::YourProvider::Builder` or if that is not defined, defaults to `Decidim::Map::DynamicMap::Builder`.
338
+ See below for further notes about the builder class.
339
+ * `builder_options` - A method that prepares the options for the builder instance that is used to create the maps in the front-end.
340
+ By default, this prepares the tile layer configurations for the Leaflet map.
341
+
342
+ In addition, you may want to customize the Builder class in case you are not happy with the default dynamic map builder functionality.
343
+ To see an example how to customize the builder, take a look at the link:/decidim-core/lib/decidim/map/provider/dynamic_map/here.rb[HERE Maps builder class].
344
+ Please note that the custom dynamic map builder needs to extend the link:/decidim-core/lib/decidim/map/dynamic_map.rb[`Decidim::Map::DynamicMap::Builder`] class as you can also see from the HERE Maps example.
345
+
346
+ The builder class works directly with the view layer and can refer to the view in question or any methods available for the view using the `template` object inside the builder.
347
+ You may be already familiar with a similar builder concept if you have ever used the https://guides.rubyonrails.org/form_helpers.html#customizing-form-builders[Rails Form Builder].
348
+
349
+ In order to provide configuration options for the dynamic maps, you can pass them directly through the maps configuration with the following syntax:
350
+
351
+ [source,ruby]
352
+ ----
353
+ config.maps = {
354
+ provider: :your_provider,
355
+ api_key: Rails.application.secrets.maps[:api_key],
356
+ dynamic: {
357
+ tile_layer: {
358
+ url: "https://tiles.example.org/{z}/{x}/{y}.png?key={apiKey}&{foo}&style={style}",
359
+ api_key: true,
360
+ foo: "bar=baz",
361
+ style: "bright-style",
362
+ attribution: %{
363
+ <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap</a> contributors
364
+ }.strip
365
+ }
366
+ }
367
+ }
368
+ ----
369
+
370
+ This will cause the following options to be available for the builder instance by default:
371
+
372
+ [source,ruby]
373
+ ----
374
+ {
375
+ tile_layer: {
376
+ url: "https://tiles.example.org/{z}/{x}/{y}.png?key={apiKey}&{foo}&style={style}",
377
+ configuration: {
378
+ api_key: Rails.application.secrets.maps[:api_key],
379
+ foo: "bar=baz",
380
+ style: "bright",
381
+ attribution: %{
382
+ <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap</a> contributors
383
+ }.strip
384
+ }
385
+ }
386
+ }
387
+ ----
388
+
389
+ And by default, this will cause the Leaflet tile layer to be configured as follows:
390
+
391
+ [source,js]
392
+ ----
393
+ L.tileLayer(
394
+ "https://tiles.example.org/{z}/{x}/{y}.png?key={apiKey}&{foo}&style={style}",
395
+ {
396
+ apiKey: "your_secret_key",
397
+ foo: "bar=baz",
398
+ style: "bright",
399
+ attribution: '<a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap</a> contributors'
400
+ }
401
+ ).addTo(map);
402
+ ----
403
+
404
+ === Defining the static maps utility
405
+
406
+ For the static map functionality, you should preferrably use a service provider that is compatible with https://github.com/jperelli/osm-static-maps[osm-static-maps] which is already integrated with Decidim.
407
+
408
+ If this is not possible, you can also create a custom static maps utility for your own service provider by defining the following empty class to start with:
409
+
410
+ [source,ruby]
411
+ ----
412
+ module Decidim
413
+ module Map
414
+ module Provider
415
+ module StaticMap
416
+ class YourProvider < ::Decidim::Map::StaticMap
417
+ # ... add your customizations here ...
418
+ end
419
+ end
420
+ end
421
+ end
422
+ end
423
+ ----
424
+
425
+ If you want to use dynamic map elements for the static maps as well, you can leave the static map utility empty as shown above.
426
+ Decidim will create a dynamic map replacement for the static map image in case the static map utility will not return a proper map URL.
427
+
428
+ In case you want to customize the static map utility for your provider, you can define the following methods in the utility class:
429
+
430
+ * `link(latitude:, longitude:, options: {})` - Returns a link for the given geographic location where the static map image is linked to.
431
+ By default, this will return a link to www.openstreetmap.org.
432
+ * `url(latitude:, longitude:, options: {})` - Returns a URL for loading the static map image from the service provider.
433
+ By default, this will return a link to the configured static map URL with the following URL query parameters:
434
+ ** `latitude` - The value for the `latitude` option provided for the method.
435
+ ** `longitude` - The value for the `longitude` option provided for the method.
436
+ ** `zoom` - The value for key `:zoom` in the options hash (default: 15).
437
+ ** `width` - The value for key `:width` in the options hash (default: 120).
438
+ ** `height` - The value for key `:height` in the options hash (default: 120).
439
+ * `url_params(latitude:, longitude:, options: {})` - Returns a hash of prepared URL parameters for the `url` method.
440
+ For the default parameters, see the explanations above for the `url` method.
441
+ * `image_data(latitude:, longitude:, options: {})` - Does a request to the URL defined by the `url` method and returns the raw binary data in the response body of that request.
442
+ This data will be cached by Decidim once fetched from the API to speed up further displays of the same static map.
443
+
444
+ To see an example how to customize the static map utility, take a look at the link:/decidim-core/lib/decidim/map/provider/static_map/here.rb[HERE Maps static map utility].
445
+
446
+ In order to provide configuration options for the static maps, you can pass them directly through the maps configuration with the following syntax:
447
+
448
+ [source,ruby]
449
+ ----
450
+ config.maps = {
451
+ provider: :your_provider,
452
+ api_key: Rails.application.secrets.maps[:api_key],
453
+ static: {
454
+ url: "https://staticmap.example.org/",
455
+ foo: "bar",
456
+ style: "bright"
457
+ }
458
+ }
459
+ ----
460
+
461
+ And then you can use these options in your provider utility as follows e.g.
462
+ in the `url_params` method:
463
+
464
+ [source,ruby]
465
+ ----
466
+ def url_params(latitude:, longitude:, options: {})
467
+ super.merge(
468
+ style: configuration.fetch(:style, "dark"),
469
+ foo: configuration.fetch(:foo, "baz")
470
+ )
471
+ end
472
+ ----
473
+
474
+ When calling the `url` method with the latitude of `1.123` and longitude of `2.456`, the utility would now generate the following URL with these configurations and customizations:
475
+
476
+ [source,bash]
477
+ ----
478
+ https://staticmap.example.org/?latitude=1.123&longitude=2.456&zoom=15&width=120&height=120&style=bright&foo=bar
479
+ ----
480
+
481
+ If you want to use the dynamic map replacements for the static map images, do not configure `static` section for your maps:
482
+
483
+ [source,ruby]
484
+ ----
485
+ config.maps = {
486
+ provider: :your_provider,
487
+ api_key: Rails.application.secrets.maps[:api_key]
488
+ # static: { ... } # LEAVE THIS OUT
489
+ }
490
+ ----
491
+
492
+ Even if you decide to use the dynamic map replacements, you will still need to define the static map utility because it is used to generate the link where users will be pointed at when they click the map image.
493
+ In this case, the static map utility can be empty as you won't need any customization for it to work.
494
+
495
+ == Configuring your own map service provider
496
+
497
+ After you have finished all the steps shown above, you will need to configure your service provider for Decidim.
498
+ The configuration key for the example service provider referred to in this documentation would be `:your_provider`.
499
+ For configuration, refer to the xref:/docs/services/maps.adoc[maps and geocoding configuration] documentation.