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.
- checksums.yaml +4 -4
- data/README.md +22 -7
- data/app/assets/config/decidim_admin_decidim_awesome_manifest.js +1 -0
- data/app/assets/config/decidim_decidim_awesome_manifest.js +1 -1
- data/app/assets/javascripts/decidim/decidim_awesome/admin.js +1 -0
- data/app/assets/javascripts/decidim/decidim_awesome/admin/codemirror.js.es6 +15 -0
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/hashtags.js.es6 +48 -0
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/layers.js.es6 +106 -0
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/map.js.es6 +166 -170
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/markers.js.es6 +56 -0
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/meetings.js.es6 +6 -5
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/proposals.js.es6 +17 -4
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/utilities.js.es6 +48 -0
- data/app/assets/javascripts/decidim/decidim_awesome/editors/legacy_quill_editor.js.es6 +160 -0
- data/app/assets/javascripts/decidim/decidim_awesome/editors/quill_editor.js.es6 +16 -5
- data/app/assets/javascripts/decidim/decidim_awesome/legacy_admin.js +3 -0
- data/app/assets/javascripts/decidim/decidim_awesome/legacy_application.js +4 -0
- data/app/assets/stylesheets/decidim/decidim_awesome/admin.scss +10 -3
- data/app/assets/stylesheets/decidim/decidim_awesome/admin/codemirror.scss +16 -0
- data/app/assets/stylesheets/decidim/decidim_awesome/awesome_map/leaflet.scss.erb +9 -0
- data/app/assets/stylesheets/decidim/decidim_awesome/awesome_map/map.scss +95 -0
- data/app/assets/stylesheets/decidim/decidim_awesome/editors/markdown_editor.scss +1 -1
- data/app/awesome_overrides/presenters/decidim/menu_presenter_override.rb +39 -0
- data/app/awesome_overrides/presenters/decidim/proposals/proposal_presenter_override.rb +3 -9
- data/app/commands/decidim/decidim_awesome/admin/create_menu_hack.rb +51 -0
- data/app/commands/decidim/decidim_awesome/admin/destroy_menu_hack.rb +47 -0
- data/app/commands/decidim/decidim_awesome/admin/update_config.rb +5 -2
- data/app/commands/decidim/decidim_awesome/admin/update_menu_hack.rb +47 -0
- data/app/controllers/decidim/decidim_awesome/admin/application_controller.rb +4 -3
- data/app/controllers/decidim/decidim_awesome/admin/checks_controller.rb +1 -1
- data/app/controllers/decidim/decidim_awesome/admin/config_controller.rb +12 -3
- data/app/controllers/decidim/decidim_awesome/admin/constraints_controller.rb +13 -0
- data/app/controllers/decidim/decidim_awesome/admin/menu_hacks_controller.rb +116 -0
- data/app/controllers/decidim/decidim_awesome/map_component/map_controller.rb +1 -4
- data/app/forms/decidim/decidim_awesome/admin/config_form.rb +21 -2
- data/app/forms/decidim/decidim_awesome/admin/constraint_form.rb +0 -2
- data/app/forms/decidim/decidim_awesome/admin/intergram_form.rb +0 -2
- data/app/forms/decidim/decidim_awesome/admin/menu_form.rb +39 -0
- data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +5 -1
- data/app/helpers/decidim/decidim_awesome/map_helper.rb +12 -50
- data/app/permissions/decidim/decidim_awesome/admin/permissions.rb +19 -0
- data/app/permissions/decidim/decidim_awesome/permissions.rb +2 -0
- data/app/uploaders/decidim/decidim_awesome/image_uploader.rb +0 -5
- data/app/views/decidim/decidim_awesome/admin/checks/index.html.erb +1 -1
- data/app/views/decidim/decidim_awesome/admin/config/_form_styles.html.erb +1 -1
- data/app/views/decidim/decidim_awesome/admin/config/show.html.erb +1 -2
- data/app/views/decidim/decidim_awesome/admin/menu_hacks/_form.html.erb +7 -0
- data/app/views/decidim/decidim_awesome/admin/menu_hacks/edit.html.erb +13 -0
- data/app/views/decidim/decidim_awesome/admin/menu_hacks/index.html.erb +44 -0
- data/app/views/decidim/decidim_awesome/admin/menu_hacks/new.html.erb +13 -0
- data/app/views/decidim/decidim_awesome/map_component/map/show.html.erb +4 -31
- data/app/views/layouts/decidim/admin/decidim_awesome.html.erb +5 -0
- data/app/views/layouts/decidim/decidim_awesome/_awesome_config.html.erb +4 -1
- data/app/views/v0.23/layouts/decidim/_head.html.erb +1 -1
- data/app/views/v0.23/layouts/decidim/admin/_header.html.erb +1 -1
- data/app/views/{v0.22 → v0.24}/layouts/decidim/_head.html.erb +2 -0
- data/app/views/{v0.22 → v0.24}/layouts/decidim/admin/_header.html.erb +1 -0
- data/config/locales/ca.yml +70 -2
- data/config/locales/cs.yml +71 -3
- data/config/locales/en.yml +61 -4
- data/config/locales/es.yml +70 -2
- data/config/locales/eu.yml +225 -0
- data/config/locales/fr.yml +172 -104
- data/config/locales/nl.yml +225 -0
- data/config/locales/sv.yml +93 -25
- data/lib/decidim/decidim_awesome.rb +15 -0
- data/lib/decidim/decidim_awesome/admin_engine.rb +1 -0
- data/lib/decidim/decidim_awesome/awesome_helpers.rb +1 -1
- data/lib/decidim/decidim_awesome/checksums.yml +7 -4
- data/lib/decidim/decidim_awesome/config.rb +1 -3
- data/lib/decidim/decidim_awesome/engine.rb +3 -3
- data/lib/decidim/decidim_awesome/iframe_component/component.rb +1 -1
- data/lib/decidim/decidim_awesome/map_component/component.rb +8 -2
- data/lib/decidim/decidim_awesome/menu_hacker.rb +90 -0
- data/lib/decidim/decidim_awesome/system_checker.rb +1 -1
- data/lib/decidim/decidim_awesome/test/shared_examples/config_examples.rb +4 -2
- data/lib/decidim/decidim_awesome/test/shared_examples/menu_hack_contexts.rb +71 -0
- data/lib/decidim/decidim_awesome/version.rb +2 -2
- data/vendor/assets/javascripts/codemirror.js +9801 -0
- data/vendor/assets/javascripts/jquery.truncate.js +105 -0
- data/vendor/assets/javascripts/keymap/sublime.js +720 -0
- data/vendor/assets/javascripts/mode/css/css.js +864 -0
- data/vendor/assets/stylesheets/codemirror.css +350 -0
- data/vendor/assets/stylesheets/inscrybmde.min.scss +180 -0
- metadata +61 -20
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/legacy_map.js.es6 +0 -225
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/legacy_proposals.js.es6 +0 -82
- data/vendor/assets/stylesheets/inscrybmde.min.css +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 431402f5979263fb5886d2285f64cb81bea75efd183e461d87cc3fff5a5f31fd
|
4
|
+
data.tar.gz: 8b842985079085bd7ed837287e051572a6bbe51de233f8b1ccb5b0df63d35316
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99427312051b0d7f486ba7070cd8eaab79f370cdc8c200e7b0f38de3f90236399fa6c44d86204d2e90d97cda0f15ab62b42a778bbfa8114126df4e70b86b9605
|
7
|
+
data.tar.gz: 31cab4d0be0fc9d3add07cf9e33976cf6708ed96771d55c57415b9d0fcd060f09a8f1b2275fbeca284c7e9e168494849c40bc02bd1db6fedc0b03bbf2eb78100
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Decidim::DecidimAwesome
|
2
2
|
|
3
|
-
[![
|
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
|
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
|
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
|
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
|
110
|
+
#### 10. Custom CSS applied only according scoped restrictions
|
110
111
|
|
111
|
-
|
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.
|
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
|
|
@@ -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
|
2
|
-
// = require
|
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 {
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
//
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
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
|
-
//
|
115
|
-
map
|
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
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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
|
-
|
196
|
-
|
197
|
-
|
198
|
-
if(
|
199
|
-
|
200
|
-
|
201
|
-
|
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
|
-
|
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);
|