decidim-decidim_awesome 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +22 -7
  3. data/app/assets/config/decidim_admin_decidim_awesome_manifest.js +1 -0
  4. data/app/assets/config/decidim_decidim_awesome_manifest.js +1 -1
  5. data/app/assets/javascripts/decidim/decidim_awesome/admin.js +1 -0
  6. data/app/assets/javascripts/decidim/decidim_awesome/admin/codemirror.js.es6 +15 -0
  7. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/hashtags.js.es6 +48 -0
  8. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/layers.js.es6 +106 -0
  9. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/map.js.es6 +166 -170
  10. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/markers.js.es6 +56 -0
  11. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/meetings.js.es6 +6 -5
  12. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/proposals.js.es6 +17 -4
  13. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/utilities.js.es6 +48 -0
  14. data/app/assets/javascripts/decidim/decidim_awesome/editors/legacy_quill_editor.js.es6 +160 -0
  15. data/app/assets/javascripts/decidim/decidim_awesome/editors/quill_editor.js.es6 +16 -5
  16. data/app/assets/javascripts/decidim/decidim_awesome/legacy_admin.js +3 -0
  17. data/app/assets/javascripts/decidim/decidim_awesome/legacy_application.js +4 -0
  18. data/app/assets/stylesheets/decidim/decidim_awesome/admin.scss +10 -3
  19. data/app/assets/stylesheets/decidim/decidim_awesome/admin/codemirror.scss +16 -0
  20. data/app/assets/stylesheets/decidim/decidim_awesome/awesome_map/leaflet.scss.erb +9 -0
  21. data/app/assets/stylesheets/decidim/decidim_awesome/awesome_map/map.scss +95 -0
  22. data/app/assets/stylesheets/decidim/decidim_awesome/editors/markdown_editor.scss +1 -1
  23. data/app/awesome_overrides/presenters/decidim/menu_presenter_override.rb +39 -0
  24. data/app/awesome_overrides/presenters/decidim/proposals/proposal_presenter_override.rb +3 -9
  25. data/app/commands/decidim/decidim_awesome/admin/create_menu_hack.rb +51 -0
  26. data/app/commands/decidim/decidim_awesome/admin/destroy_menu_hack.rb +47 -0
  27. data/app/commands/decidim/decidim_awesome/admin/update_config.rb +5 -2
  28. data/app/commands/decidim/decidim_awesome/admin/update_menu_hack.rb +47 -0
  29. data/app/controllers/decidim/decidim_awesome/admin/application_controller.rb +4 -3
  30. data/app/controllers/decidim/decidim_awesome/admin/checks_controller.rb +1 -1
  31. data/app/controllers/decidim/decidim_awesome/admin/config_controller.rb +12 -3
  32. data/app/controllers/decidim/decidim_awesome/admin/constraints_controller.rb +13 -0
  33. data/app/controllers/decidim/decidim_awesome/admin/menu_hacks_controller.rb +116 -0
  34. data/app/controllers/decidim/decidim_awesome/map_component/map_controller.rb +1 -4
  35. data/app/forms/decidim/decidim_awesome/admin/config_form.rb +21 -2
  36. data/app/forms/decidim/decidim_awesome/admin/constraint_form.rb +0 -2
  37. data/app/forms/decidim/decidim_awesome/admin/intergram_form.rb +0 -2
  38. data/app/forms/decidim/decidim_awesome/admin/menu_form.rb +39 -0
  39. data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +5 -1
  40. data/app/helpers/decidim/decidim_awesome/map_helper.rb +12 -50
  41. data/app/permissions/decidim/decidim_awesome/admin/permissions.rb +19 -0
  42. data/app/permissions/decidim/decidim_awesome/permissions.rb +2 -0
  43. data/app/uploaders/decidim/decidim_awesome/image_uploader.rb +0 -5
  44. data/app/views/decidim/decidim_awesome/admin/checks/index.html.erb +1 -1
  45. data/app/views/decidim/decidim_awesome/admin/config/_form_styles.html.erb +1 -1
  46. data/app/views/decidim/decidim_awesome/admin/config/show.html.erb +1 -2
  47. data/app/views/decidim/decidim_awesome/admin/menu_hacks/_form.html.erb +7 -0
  48. data/app/views/decidim/decidim_awesome/admin/menu_hacks/edit.html.erb +13 -0
  49. data/app/views/decidim/decidim_awesome/admin/menu_hacks/index.html.erb +44 -0
  50. data/app/views/decidim/decidim_awesome/admin/menu_hacks/new.html.erb +13 -0
  51. data/app/views/decidim/decidim_awesome/map_component/map/show.html.erb +4 -31
  52. data/app/views/layouts/decidim/admin/decidim_awesome.html.erb +5 -0
  53. data/app/views/layouts/decidim/decidim_awesome/_awesome_config.html.erb +4 -1
  54. data/app/views/v0.23/layouts/decidim/_head.html.erb +1 -1
  55. data/app/views/v0.23/layouts/decidim/admin/_header.html.erb +1 -1
  56. data/app/views/{v0.22 → v0.24}/layouts/decidim/_head.html.erb +2 -0
  57. data/app/views/{v0.22 → v0.24}/layouts/decidim/admin/_header.html.erb +1 -0
  58. data/config/locales/ca.yml +70 -2
  59. data/config/locales/cs.yml +71 -3
  60. data/config/locales/en.yml +61 -4
  61. data/config/locales/es.yml +70 -2
  62. data/config/locales/eu.yml +225 -0
  63. data/config/locales/fr.yml +172 -104
  64. data/config/locales/nl.yml +225 -0
  65. data/config/locales/sv.yml +93 -25
  66. data/lib/decidim/decidim_awesome.rb +15 -0
  67. data/lib/decidim/decidim_awesome/admin_engine.rb +1 -0
  68. data/lib/decidim/decidim_awesome/awesome_helpers.rb +1 -1
  69. data/lib/decidim/decidim_awesome/checksums.yml +7 -4
  70. data/lib/decidim/decidim_awesome/config.rb +1 -3
  71. data/lib/decidim/decidim_awesome/engine.rb +3 -3
  72. data/lib/decidim/decidim_awesome/iframe_component/component.rb +1 -1
  73. data/lib/decidim/decidim_awesome/map_component/component.rb +8 -2
  74. data/lib/decidim/decidim_awesome/menu_hacker.rb +90 -0
  75. data/lib/decidim/decidim_awesome/system_checker.rb +1 -1
  76. data/lib/decidim/decidim_awesome/test/shared_examples/config_examples.rb +4 -2
  77. data/lib/decidim/decidim_awesome/test/shared_examples/menu_hack_contexts.rb +71 -0
  78. data/lib/decidim/decidim_awesome/version.rb +2 -2
  79. data/vendor/assets/javascripts/codemirror.js +9801 -0
  80. data/vendor/assets/javascripts/jquery.truncate.js +105 -0
  81. data/vendor/assets/javascripts/keymap/sublime.js +720 -0
  82. data/vendor/assets/javascripts/mode/css/css.js +864 -0
  83. data/vendor/assets/stylesheets/codemirror.css +350 -0
  84. data/vendor/assets/stylesheets/inscrybmde.min.scss +180 -0
  85. metadata +61 -20
  86. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/legacy_map.js.es6 +0 -225
  87. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/legacy_proposals.js.es6 +0 -82
  88. data/vendor/assets/stylesheets/inscrybmde.min.css +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7731085ea63b1e475bc932df6a856fb15f4895ebaec108aacac0ef51698f80bb
4
- data.tar.gz: 633a38263369173bc782046137a3a91a6b0a0759690a39d5759f8eb6abb2bb3a
3
+ metadata.gz: 431402f5979263fb5886d2285f64cb81bea75efd183e461d87cc3fff5a5f31fd
4
+ data.tar.gz: 8b842985079085bd7ed837287e051572a6bbe51de233f8b1ccb5b0df63d35316
5
5
  SHA512:
6
- metadata.gz: '08415d52fa955527e623c3efca7f04a1d5456cedc8cbaca918329700cc4dd963bcc5c895eccc496b67ffa04410ad36067d380d71152f545c698e9fb334c521dc'
7
- data.tar.gz: c9d394b5f3080b25c0e7d1ba88b1d55ce668f537e2ee07c2401ebff37acfff5d6e49ece69bc6bf518d38b468e1ee430ab7c193e0b1489f1ed8395ccea4fbcb66
6
+ metadata.gz: 99427312051b0d7f486ba7070cd8eaab79f370cdc8c200e7b0f38de3f90236399fa6c44d86204d2e90d97cda0f15ab62b42a778bbfa8114126df4e70b86b9605
7
+ data.tar.gz: 31cab4d0be0fc9d3add07cf9e33976cf6708ed96771d55c57415b9d0fcd060f09a8f1b2275fbeca284c7e9e168494849c40bc02bd1db6fedc0b03bbf2eb78100
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Decidim::DecidimAwesome
2
2
 
3
- [![Build](https://github.com/Platoniq/decidim-module-decidim_awesome/workflows/Build/badge.svg)](https://github.com/Platoniq/decidim-module-decidim_awesome/actions)
3
+ [![[CI] Test 0.24](https://github.com/Platoniq/decidim-module-decidim_awesome/actions/workflows/test%20-24.yml/badge.svg)](https://github.com/Platoniq/decidim-module-decidim_awesome/actions/workflows/test%20-24.yml)
4
+ [![[CI] Test 0.23](https://github.com/Platoniq/decidim-module-decidim_awesome/actions/workflows/test%20-23.yml/badge.svg)](https://github.com/Platoniq/decidim-module-decidim_awesome/actions/workflows/test%20-23.yml)
4
5
  [![Maintainability](https://api.codeclimate.com/v1/badges/2dada53525dd5a944089/maintainability)](https://codeclimate.com/github/Platoniq/decidim-module-decidim_awesome/maintainability)
5
6
  [![Test Coverage](https://codecov.io/gh/Platoniq/decidim-module-decidim_awesome/branch/master/graph/badge.svg?token=TFBMCLLZJG)](undefined)
6
7
 
@@ -33,7 +34,7 @@ Each hack can be scoped to one or more specific participatory spaces or componen
33
34
 
34
35
  #### 1. Image support for the Quill editor
35
36
 
36
- Modifies the WYSIWYG editor in Decidim by adding the possibility to insert images. When uploading images, Drag & Drop is supported. Images will be uploaded to the server and inserted as external resources (it doesn't use base64 inline encoding).
37
+ Modifies the WYSIWYG editor in Decidim by adding the possibility to insert images. When uploading images, Drag & Drop is supported. Images will be uploaded to the server and inserted as external resources (it doesn't use base64 in-line encoding).
37
38
 
38
39
  This feature allows you use images in newsletters as well.
39
40
 
@@ -71,13 +72,13 @@ Many scopes can be defined for every tweak.
71
72
 
72
73
  This is a component you can add in any participatory space. It retrieves all the geolocated content in that participatory space (meetings or proposals) and displays it in a big map.
73
74
 
74
- It also provides a simple search by category, each category is assignated to a different color.
75
+ It also provides a simple search by category, each category is assigned to a different color.
75
76
 
76
77
  ![Awesome map](examples/awesome-map.png)
77
78
 
78
79
  #### 7. Allow Decidim to use custom CSS themes for every tenant
79
80
 
80
- When customizind CSS for a Decidim installation, each change affects all the organizations (tenant).
81
+ When customizing CSS for a Decidim installation, each change affects all the organizations (tenant).
81
82
 
82
83
  This feature allows to customize each organization css without affecting the others in the same Decidim installation.
83
84
 
@@ -106,12 +107,20 @@ With this feature you can have a support chat in Decidim. It is linked to a [Tel
106
107
 
107
108
  ![Intergram screenshot](examples/intergram.png)
108
109
 
109
- #### 10. Custom CSS applied only according scopes restrictions
110
+ #### 10. Custom CSS applied only according scoped restrictions
110
111
 
111
- For instance, with this feature you can create directly from the admin a CSS snipped that is only applied globally, in a particular assembly or even a single proposal!
112
+ With this feature you can create directly in the admin a CSS snipped that is only applied globally, in a particular assembly or even a single proposal!
112
113
 
113
114
  ![CSS screenshot](examples/custom_styles.png)
114
115
 
116
+ #### 11. Change the main menu of Decidim entirely!
117
+
118
+ Feel free to hide, modify or add items in the Decidim's main menu. You can also change the order, establish some conditions (like showing only for logged users) or open in a new window.
119
+
120
+ ![Menu hacks screenshot](examples/menu-1.png)
121
+ ![Menu hacks screenshot](examples/menu-2.png)
122
+ ![Menu hacks screenshot](examples/menu-3.png)
123
+ ![Menu hacks screenshot](examples/menu-4.png)
115
124
 
116
125
  #### To be continued...
117
126
 
@@ -127,7 +136,7 @@ Some things in the road-map:
127
136
  Add this line to your application's Gemfile:
128
137
 
129
138
  ```ruby
130
- gem "decidim-decidim_awesome", "~> 0.6.3"
139
+ gem "decidim-decidim_awesome", "~> 0.7.0"
131
140
  ```
132
141
 
133
142
  And then execute:
@@ -144,6 +153,7 @@ Depending on your Decidim version, choose the corresponding Awesome version to e
144
153
  |---|---|
145
154
  | 0.5.x | 0.21.x, 0.22.x |
146
155
  | 0.6.x | 0.22.x, 0.23.x |
156
+ | 0.7.x | 0.23.x, 0.24.x |
147
157
 
148
158
  ## Configuration
149
159
 
@@ -152,6 +162,8 @@ admins do not even see it.
152
162
 
153
163
  In order to personalize default values, create an initializer such as:
154
164
 
165
+ > **NOTE**: this is not necessary unless you want to **disable** some features. All features are enabled by default.
166
+
155
167
  ```ruby
156
168
  # config/initializers/awesome_defaults.rb
157
169
 
@@ -165,6 +177,9 @@ Decidim::DecidimAwesome.configure do |config|
165
177
 
166
178
  # De-activated, admins don't even see it as an option
167
179
  config.use_markdown_editor = :disabled
180
+
181
+ # any other config var from lib/decidim/decidim_awesome.rb
182
+ ...
168
183
  end
169
184
  ```
170
185
 
@@ -1,2 +1,3 @@
1
1
  // = link decidim/decidim_awesome/admin.js
2
+ // = link decidim/decidim_awesome/legacy_admin.js
2
3
  // = link decidim/decidim_awesome/admin/form_exit_warn.js
@@ -1,3 +1,3 @@
1
+ // = link decidim/decidim_awesome/legacy_application.js
1
2
  // = link decidim/decidim_awesome/application.js
2
- // = link decidim/decidim_awesome/awesome_map/legacy_map.js
3
3
  // = link decidim/decidim_awesome/awesome_map/map.js
@@ -1,2 +1,3 @@
1
1
  // = require decidim/decidim_awesome/admin/constraints
2
+ // = require decidim/decidim_awesome/admin/codemirror
2
3
  // = require decidim/decidim_awesome/editors/quill_editor
@@ -0,0 +1,15 @@
1
+ // = require codemirror
2
+ // = require mode/css/css
3
+ // = require keymap/sublime
4
+ // = require_self
5
+
6
+ $(() => {
7
+ $(".awesome-edit-config .scoped-style textarea").each((_idx, el) => {
8
+ console.log(el)
9
+ var editor = CodeMirror.fromTextArea(el, {
10
+ lineNumbers: true,
11
+ mode: "css",
12
+ keymap: "sublime"
13
+ });
14
+ })
15
+ });
@@ -0,0 +1,48 @@
1
+ ((exports) => {
2
+ const hashtags = [];
3
+
4
+ const collectHashtags = (text) => {
5
+ let tags = [];
6
+ if(text) {
7
+ const gids = text.match(/gid:\/\/[^\s<]+/g)
8
+ if(gids) {
9
+ tags = gids.filter(gid => gid.indexOf("/Decidim::Hashtag/") != -1).map(gid => {
10
+ const parts = gid.split("/");
11
+ const fromSelector = parts[5].charAt(0) == '_';
12
+ const tag = fromSelector ? parts[5].substr(1) : parts[5];
13
+ const name = '#' + tag;
14
+ const html = `<a href="/search?term=${name}">${name}</a>`;
15
+ const hashtag = {
16
+ color: getComputedStyle(document.documentElement).getPropertyValue('--secondary'),
17
+ gid: gid,
18
+ id: parseInt(parts[4], 10),
19
+ fromSelector: fromSelector,
20
+ tag: tag,
21
+ name: name,
22
+ html: html
23
+ }
24
+ hashtags.push(hashtag)
25
+ return hashtag;
26
+ });
27
+ }
28
+ }
29
+ return tags;
30
+ };
31
+
32
+ const removeHashtags = (text) => {
33
+ return text.replace(/gid:\/\/[^\s<]+/g, "");
34
+ };
35
+
36
+ const appendHtmlHashtags = (text, tags) => {
37
+ tags.forEach(tag => {
38
+ text += ` ${tag.html}`;
39
+ });
40
+ return text;
41
+ };
42
+
43
+ exports.AwesomeMap = exports.AwesomeMap || {};
44
+ exports.AwesomeMap.hashtags = hashtags;
45
+ exports.AwesomeMap.collectHashtags = collectHashtags;
46
+ exports.AwesomeMap.appendHtmlHashtags = appendHtmlHashtags;
47
+ exports.AwesomeMap.removeHashtags = removeHashtags;
48
+ })(window);
@@ -0,0 +1,106 @@
1
+ // = require leaflet.featuregroup.subgroup
2
+ // = require decidim/decidim_awesome/awesome_map/utilities
3
+ // = require decidim/decidim_awesome/awesome_map/categories
4
+ // = require decidim/decidim_awesome/awesome_map/hashtags
5
+
6
+ ((exports) => {
7
+ const { collapsedMenu, options, categories } = exports.AwesomeMap;
8
+ const layers = {};
9
+ const cluster = L.markerClusterGroup();
10
+
11
+ const control = L.control.layers(null, null, {
12
+ position: 'topleft',
13
+ sortLayers: false,
14
+ collapsed: collapsedMenu,
15
+ // hideSingleBase: true
16
+ });
17
+
18
+ const addProposalsControls = (map, component) => {
19
+ // add control layer for proposals
20
+ layers.proposals = {
21
+ label: `<span class="awesome_map-component" id="awesome_map-component_${component.id}" title="0">${component.name || window.DecidimAwesome.texts.proposals}</span>`,
22
+ group: L.featureGroup.subGroup(cluster)
23
+ };
24
+ control.addOverlay(layers.proposals.group, layers.proposals.label);
25
+ layers.proposals.group.addTo(map);
26
+
27
+ // add control layer for amendments if any
28
+ if(options.menu.amendments && component.amendments) {
29
+ layers.amendments = {
30
+ label: `<span class="awesome_map-component" id="awesome_map-amendments_${component.id}" title="0">${window.DecidimAwesome.texts.amendments}</span>`,
31
+ group: L.featureGroup.subGroup(cluster)
32
+ }
33
+ control.addOverlay(layers.amendments.group, layers.amendments.label);
34
+ layers.amendments.group.addTo(map);
35
+ }
36
+ };
37
+
38
+ const addMeetingsControls = (map, component) => {
39
+ // add control layer for meetings
40
+ layers.meetings = {
41
+ label: `<span class="awesome_map-component" id="awesome_map-component_${component.id}" title="0">${component.name || window.DecidimAwesome.texts.meetings}</span>`,
42
+ group: L.featureGroup.subGroup(cluster)
43
+ };
44
+ control.addOverlay(layers.meetings.group, layers.meetings.label);
45
+ layers.meetings.group.addTo(map);
46
+ };
47
+
48
+ const addSearchControls = () => {
49
+ $(control.getContainer()).contents("form").after(`<div id="awesome_map-categories-control" class="active"><b class="awesome_map-title-control">${window.DecidimAwesome.texts.categories}</b><div class="categories-container"></div></div>
50
+ <div id="awesome_map-hashtags-control"><b class="awesome_map-title-control">${window.DecidimAwesome.texts.hashtags}</b><div class="hashtags-container"></div><a href="#" class="awesome_map-toggle_all_tags">${window.DecidimAwesome.texts.select_deselect_all}</a></div>`);
51
+ };
52
+
53
+ const addCategoriesControls = (map) => {
54
+ if(categories && categories.length) {
55
+ categories.forEach((category) => {
56
+ // add control layer for this category
57
+ const label = `<i class="awesome_map-category-${category.id}"></i> ${category.name}`;
58
+ layers[category.id] = {
59
+ label: label,
60
+ group: L.featureGroup.subGroup(cluster)
61
+ };
62
+ layers[category.id].group.addTo(map);
63
+ // In the next iteration to be sure layers are rendered
64
+ setTimeout(() => {
65
+ $('#awesome_map-categories-control .categories-container').append(`<label data-layer="${category.id}" class="awesome_map-category-${category.id}${category.parent?" subcategory":""}"><input type="checkbox" class="awesome_map-categories-selector" checked><span>${label}</span></label>`);
66
+ });
67
+ });
68
+ }
69
+ };
70
+
71
+ // Hashtags are collected directly from proposals (this is different than categories)
72
+ const addHashtagsControls = (map, hashtags, marker) => {
73
+ // show hashtag layer
74
+ if(hashtags && hashtags.length) {
75
+ $('#awesome_map-hashtags-control').show();
76
+ hashtags.forEach(hashtag => {
77
+ // Add layer if not exists, otherwise just add the marker to the group
78
+ if(!layers[hashtag.tag]) {
79
+ layers[hashtag.tag] = {
80
+ label: hashtag.name,
81
+ group: L.featureGroup.subGroup(cluster)
82
+ };
83
+ layers[hashtag.tag].group.addTo(map);
84
+ $('#awesome_map-hashtags-control .hashtags-container').append(`<label data-layer="${hashtag.tag}" class="awesome_map-hashtag-${hashtag.tag}"><input type="checkbox" class="awesome_map-hashtags-selector" checked><span>${hashtag.name}</span></label>`);
85
+ // Call a trigger, might be in service for customizations
86
+ exports.AwesomeMap.hashtagAdded(hashtag, $('#awesome_map-hashtags-control .hashtags-container'));
87
+ }
88
+ marker.addTo(layers[hashtag.tag].group);
89
+
90
+ const $label = $(`label.awesome_map-hashtag-${hashtag.tag}`);
91
+ // update number of items
92
+ $label.attr("title", (parseInt($label.attr("title") || 0) + 1) + " " + window.DecidimAwesome.texts.items);
93
+ });
94
+ }
95
+ };
96
+
97
+ exports.AwesomeMap.layers = layers;
98
+ exports.AwesomeMap.control = control;
99
+ exports.AwesomeMap.cluster = cluster;
100
+ exports.AwesomeMap.addProposalsControls = addProposalsControls;
101
+ exports.AwesomeMap.addMeetingsControls = addMeetingsControls;
102
+ exports.AwesomeMap.addSearchControls = addSearchControls;
103
+ exports.AwesomeMap.addCategoriesControls = addCategoriesControls;
104
+ exports.AwesomeMap.addHashtagsControls = addHashtagsControls;
105
+ exports.AwesomeMap.hashtagAdded = $.noop;
106
+ })(window);
@@ -1,82 +1,41 @@
1
- // = require jsrender.min
2
- // = require leaflet.featuregroup.subgroup
1
+ // = require decidim/decidim_awesome/awesome_map/layers
2
+ // = require decidim/decidim_awesome/awesome_map/utilities
3
+ // = require decidim/decidim_awesome/awesome_map/markers
3
4
  // = require decidim/decidim_awesome/awesome_map/categories
4
5
  // = require decidim/decidim_awesome/awesome_map/proposals
5
6
  // = require decidim/decidim_awesome/awesome_map/meetings
6
7
  // = require_self
7
8
 
8
9
  ((exports) => {
9
- const { fetchProposals, fetchMeetings, getCategory } = exports.AwesomeMap;
10
-
11
- const collapsedMenu = $("#awesome-map").data("collapsed");
12
- const show = {
13
- withdrawn: $("#awesome-map").data("show-withdrawn"),
14
- accepted: $("#awesome-map").data("show-accepted"),
15
- evaluating: $("#awesome-map").data("show-evaluating"),
16
- notAnswered: $("#awesome-map").data("show-not-answered"),
17
- rejected: $("#awesome-map").data("show-rejected")
18
- };
19
- const components = $("#awesome-map").data("components");
20
- const popupMeetingTemplateId = "marker-meeting-popup";
21
- const popupProposalTemplateId = "marker-proposal-popup";
22
-
23
- const cluster = L.markerClusterGroup();
24
- const amendments = [];
25
-
26
- const layers = {};
27
-
28
- const control = L.control.layers(null, null, {
29
- position: 'topleft',
30
- sortLayers: false,
31
- collapsed: collapsedMenu,
32
- // hideSingleBase: true
33
- });
34
- const allMarkers = [];
35
-
36
- const drawMarker = (element, marker, component) => {
37
- let tmpl = component.type === "proposals" ? popupProposalTemplateId : popupMeetingTemplateId,
38
- node = document.createElement("div");
39
-
40
- $($.templates(`#${tmpl}`).render(element)).appendTo(node);
41
-
42
- marker.bindPopup(node, {
43
- maxwidth: 640,
44
- minWidth: 500,
45
- keepInView: true,
46
- className: "map-info"
47
- }).openPopup();
48
-
49
- allMarkers.push({
50
- marker: marker,
51
- component: component,
52
- element: element
53
- });
54
-
55
- // Check if it has amendments, add it to a list
56
- if(element.amendments && element.amendments.length) {
57
- element.amendments.forEach((amendment) => {
58
- amendments.push(amendment.emendation.id);
59
- });
60
- }
61
- // Add to category layer
62
- let cat = getCategory(element.category);
63
- if(layers[cat.id]) {
64
- marker.addTo(layers[cat.id].group);
65
- // show category if hidden
66
- const $label = $(`.awesome_map-category_${cat.id}`).closest("label");
67
- const $parent = $(`.awesome_map-category_${cat.parent}`).closest("label");
68
- $label.show();
69
- // update number of items
70
- $label.attr("title", parseInt($label.attr("title") || 0) + 1);
71
- // show parent if apply
72
- $parent.show();
73
- $parent.attr("title", parseInt($parent.attr("title") || 0) + 1);
74
- // update component stats
75
- const $component = $(`#awesome_map-component-${component.id}`);
76
- $component.attr("title", parseInt($component.attr("title") || 0) + 1);
10
+ const {
11
+ layers,
12
+ cluster,
13
+ control,
14
+ addProposalsControls,
15
+ addMeetingsControls,
16
+ addSearchControls,
17
+ addCategoriesControls,
18
+ addHashtagsControls,
19
+ fetchProposals,
20
+ fetchMeetings,
21
+ options,
22
+ show,
23
+ components,
24
+ amendments,
25
+ allMarkers,
26
+ drawMarker,
27
+ getCategory
28
+ } = exports.AwesomeMap;
29
+
30
+ exports.AwesomeMap.allMarkersLoaded = $.noop;
31
+
32
+ const autoResizeMap = (map) => {
33
+ // Setup center/zoom options if specified, otherwise fitbounds
34
+ if(options.center) {
35
+ map.setView(options.center, options.zoom);
36
+ } else {
37
+ map.fitBounds(cluster.getBounds(), { padding: [50, 50] });
77
38
  }
78
-
79
- return marker;
80
39
  };
81
40
 
82
41
  const loadElements = (map) => {
@@ -85,131 +44,168 @@
85
44
  cluster.addTo(map);
86
45
 
87
46
  // Load markers
88
- components.forEach((component) => {
47
+ components.forEach((component) => {
89
48
  if(component.type == "proposals") {
90
- // add control layer for proposals
91
- layers.proposals = {
92
- label: `<span id="awesome_map-component-${component.id}" title="0">${component.name || window.DecidimAwesome.texts.proposals}</span>`,
93
- group: L.featureGroup.subGroup(cluster)
94
- };
95
- control.addOverlay(layers.proposals.group, layers.proposals.label);
96
- layers.proposals.group.addTo(map);
97
-
98
- // add control layer for amendments if any
99
- if(component.amendments) {
100
- layers.amendments = {
101
- label: `<span id="awesome_map-component-${component.d}" title="0">${window.DecidimAwesome.texts.amendments}</span>`,
102
- group: L.featureGroup.subGroup(cluster)
103
- }
104
- control.addOverlay(layers.amendments.group, layers.amendments.label);
105
- layers.amendments.group.addTo(map);
106
- }
49
+ addProposalsControls(map, component);
107
50
 
108
51
  fetchProposals(component, '', (element, marker) => {
109
- console.log(element.state, show[element.state || 'notAnswered'], show, element);
52
+ // console.log(element.state, show[element.state || 'notAnswered'], show, element);
110
53
  if(show[element.state || 'notAnswered']) {
111
- drawMarker(element, marker, component).addTo(layers.proposals.group)
54
+ drawMarker(element, marker, component).addTo(layers.proposals.group);
55
+ // Add hashtags menu items here, only hashtags with proposals associated will be present
56
+ if(options.menu.hashtags) {
57
+ addHashtagsControls(map, element.hashtags, marker);
58
+ }
112
59
  }
113
- }, () => {
114
- // finall call
115
- map.fitBounds(cluster.getBounds(), { padding: [50, 50] });
60
+ }, () => { // final call
61
+ // Setup center/zoom options if specified, otherwise fitbounds
62
+ autoResizeMap(map);
63
+
116
64
  allMarkers.forEach((item) => {
117
65
  // add marker to amendments layers if it's an amendment
118
66
  if(amendments.find((a) => a == item.element.id)) {
119
67
  item.marker.removeFrom(layers.proposals.group);
120
- item.marker.addTo(layers.amendments.group);
68
+ if(options.menu.amendments) {
69
+ item.marker.addTo(layers.amendments.group);
70
+ }
121
71
  }
122
72
  });
73
+ // Call a trigger, might be useful for customizations
74
+ exports.AwesomeMap.allMarkersLoaded();
123
75
  });
124
- }
125
-
126
- if(component.type == "meetings") {
127
- // add control layer for meetings
128
- layers.meetings = {
129
- label: `<span id="awesome_map-component-${component.id}" title="0">${component.name || window.DecidimAwesome.texts.meetings}</span>`,
130
- group: L.featureGroup.subGroup(cluster)
131
- };
132
- control.addOverlay(layers.meetings.group, layers.meetings.label);
133
- layers.meetings.group.addTo(map);
134
-
135
- fetchMeetings(component, '', (element, marker) => {
76
+ }
77
+
78
+ if(options.menu.meetings && component.type == "meetings") {
79
+ addMeetingsControls(map, component);
80
+
81
+ fetchMeetings(component, '', (element, marker) => {
136
82
  drawMarker(element, marker, component).addTo(layers.meetings.group);
137
- }, () => {
138
- map.fitBounds(cluster.getBounds(), { padding: [50, 50] });
83
+ }, () => autoResizeMap(map) );
84
+ }
85
+ });
86
+
87
+ /*
88
+ * We add all categories and hide those that have no proposals
89
+ * This is done this way to ensure all parent categories are displayed
90
+ * even if the have not proposals associated
91
+ */
92
+ addSearchControls(map);
93
+ addCategoriesControls(map);
94
+
95
+ // category events
96
+ $("#awesome-map").on("change", ".awesome_map-categories-selector", (e) => {
97
+ e.preventDefault();
98
+ e.stopPropagation();
99
+ const id = $(e.target).closest("label").data("layer");
100
+ const cat = getCategory(id);
101
+ // console.log("changed, layer", id, "cat", cat, "checked", e.target.checked, e);
102
+ if(cat) {
103
+ const layer = layers[cat.id];
104
+ if(e.target.checked) {
105
+ // show group of markers
106
+ map.addLayer(layer.group);
107
+
108
+ // if it's a children, put the parent to indeterminate
109
+ indeterminateInput(cat.parent);
110
+ } else {
111
+ // hide group of markers
112
+ map.removeLayer(layer.group);
113
+ // if it's a children, put the parent to indeterminate
114
+ cat.children().forEach((c) => {
115
+ let $el = $(`.awesome_map-category-${c.id}`);
116
+ if($el.parent().prev().prop("checked")) {
117
+ $el.click();
118
+ }
139
119
  });
120
+ }
121
+ // sync tags
122
+ updateHashtagLayers();
140
123
  }
141
124
  });
142
125
 
143
-
144
- // add categories control layers
145
- if(window.AwesomeMap.categories.length) {
146
- let lastLayer = layers[Object.keys(layers)[Object.keys(layers).length - 1]];
147
- // Add Categories "title"
148
- if(lastLayer) {
149
- lastLayer.label = `${lastLayer.label}<hr><b>${window.DecidimAwesome.texts.categories}</b>`;
150
- control.removeLayer(lastLayer.group);
151
- control.addOverlay(lastLayer.group, lastLayer.label);
126
+ const indeterminateInput = (id) => {
127
+ $('[class^="awesome_map-category-"]').parent().prev().prop("indeterminate", false);
128
+ if(id) {
129
+ let $input = $(`.awesome_map-category-${id}`).parent().prev();
130
+ if(!$input.prop("checked")) {
131
+ $input.prop("indeterminate", true);
132
+ }
152
133
  }
153
-
154
- window.AwesomeMap.categories.forEach((category) => {
155
- // add control layer for this category
156
- layers[category.id] = {
157
- label: `<i class="awesome_map-category_${category.id}"></i> ${category.name}`,
158
- group: L.featureGroup.subGroup(cluster)
159
- };
160
- layers[category.id].group.addTo(map);
161
- control.addOverlay(layers[category.id].group, layers[category.id].label);
162
- // hide layer by default, it will be activated if there's any marker in it
163
- setTimeout(() => {
164
- $(`.awesome_map-category_${category.id}`).closest("label").hide();
165
- });
134
+ };
135
+
136
+ const updateHashtagLayers = () => {
137
+ // hide all
138
+ $(".awesome_map-hashtags-selector").each((_idx, el) => {
139
+ const layer = layers[$(el).closest("label").data("layer")];
140
+ if(layer) {
141
+ map.removeLayer(layer.group);
142
+ }
166
143
  });
167
-
168
- // watch events for subcategories syncronitzation
169
- const getCatFromClass = (name) => {
170
- let id = name.match(/awesome_map-category_(\d+)/)
171
- if(!id) return;
172
- const cat = getCategory(id[1]);
173
- if(!cat || !cat.name) return;
174
-
175
- return cat;
176
- };
177
-
178
- const indeterminateInput = (id) => {
179
- $('[class^="awesome_map-category_"]').parent().prev().prop("indeterminate", false);
180
- if(id) {
181
- let $input = $(`.awesome_map-category_${id}`).parent().prev();
182
- if(!$input.prop("checked")) {
183
- $input.prop("indeterminate", true);
184
- }
144
+ // show selected only
145
+ $(".awesome_map-hashtags-selector:checked").each((_idx, el) => {
146
+ const layer = layers[$(el).closest("label").data("layer")];
147
+ if(layer) {
148
+ map.addLayer(layer.group);
185
149
  }
186
- };
187
-
188
- map.on('overlayadd', (e) => {
189
- const cat = getCatFromClass(e.name);
190
- if(!cat) return;
191
- // if it's a children, put the parent to indeterminate
192
- indeterminateInput(cat.parent);
193
150
  });
194
-
195
- // on remove a parent category, remove all children
196
- map.on('overlayremove', (e) => {
197
- const cat = getCatFromClass(e.name);
198
- if(!cat) return;
199
- cat.children().forEach((c) => {
200
- let $el = $(`.awesome_map-category_${c.id}`);
201
- if($el.parent().prev().prop("checked")) {
202
- $el.click();
203
- }
204
- });
151
+ // hide non-selected categories
152
+ $(".awesome_map-categories-selector:not(:checked)").each((_idx, el) => {
153
+ const layer = layers[$(el).closest("label").data("layer")];
154
+ console.log(el, layer, map)
155
+ if(layer) {
156
+ map.addLayer(layer.group);
157
+ map.removeLayer(layer.group);
158
+ }
205
159
  });
160
+ };
161
+
162
+ // hashtag events
163
+ $("#awesome-map").on("change", ".awesome_map-hashtags-selector", (e) => {
164
+ e.preventDefault();
165
+ e.stopPropagation();
166
+ const tag = $(e.target).closest("label").data("layer");
167
+ // console.log("changed, layer", tag, "checked", e.target.checked, e);
168
+ if(tag) {
169
+ updateHashtagLayers();
170
+ }
171
+ });
206
172
 
207
- }
173
+ // select/deselect all tags
174
+ $("#awesome-map").on("click", ".awesome_map-toggle_all_tags", (e) => {
175
+ e.preventDefault();
176
+ e.stopPropagation();
177
+ $("#awesome-map .awesome_map-hashtags-selector").prop("checked", $("#awesome-map .awesome_map-hashtags-selector:checked").length < $("#awesome-map .awesome_map-hashtags-selector").length);
178
+ updateHashtagLayers();
179
+ });
208
180
 
181
+ // sub-layer hashtag title toggle
182
+ $("#awesome-map").on("click", ".awesome_map-title-control", (e) => {
183
+ e.preventDefault();
184
+ e.stopPropagation();
185
+ $("#awesome_map-hashtags-control").toggleClass("active");
186
+ });
209
187
  };
210
188
 
211
- $("#map").on("ready.decidim", (ev, map) => {
189
+
190
+ $("#map").on("ready.decidim", (_e, map) => {
191
+ if(options.center) {
192
+ map.setView(options.center, options.zoom);
193
+ }
212
194
  loadElements(map);
195
+
196
+ // order hashtags alphabetically
197
+ exports.AwesomeMap.hashtagAdded = (_hashtag, $div) => {
198
+ let $last = $div.contents("label:last");
199
+ if($last.prev("label").length) {
200
+ // move the label to order it alphabetically
201
+ $div.contents("label").each((_idx, el) => {
202
+ if($(el).text().localeCompare($last.text()) > 0) {
203
+ $(el).before($last);
204
+ return false;
205
+ }
206
+ });
207
+ }
208
+ };
213
209
  });
214
210
 
215
211
  })(window);