decidim-decidim_awesome 0.6.2 → 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -6
- data/app/assets/config/decidim_admin_decidim_awesome_manifest.js +1 -0
- 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/admin/form_exit_warn.js.es6 +30 -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/legacy_map.js.es6 +12 -19
- data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/legacy_proposals.js.es6 +3 -2
- 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 +4 -3
- 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/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/commands/decidim/decidim_awesome/admin/create_menu_hack.rb +51 -0
- data/app/commands/decidim/decidim_awesome/admin/create_scoped_style.rb +34 -0
- data/app/commands/decidim/decidim_awesome/admin/destroy_menu_hack.rb +47 -0
- data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_style.rb +40 -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/config_controller.rb +40 -4
- 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/forms/decidim/decidim_awesome/admin/config_form.rb +22 -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 +9 -3
- data/app/permissions/decidim/decidim_awesome/admin/permissions.rb +19 -0
- data/app/permissions/decidim/decidim_awesome/permissions.rb +2 -0
- data/app/views/decidim/decidim_awesome/admin/config/_form_styles.html.erb +28 -0
- data/app/views/decidim/decidim_awesome/admin/config/show.html.erb +2 -3
- 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 +9 -6
- data/app/views/layouts/decidim/admin/decidim_awesome.html.erb +10 -0
- data/app/views/layouts/decidim/decidim_awesome/_awesome_config.html.erb +5 -2
- data/app/views/layouts/decidim/decidim_awesome/_custom_styles.html.erb +3 -0
- data/app/views/v0.22/layouts/decidim/_head.html.erb +1 -0
- data/app/views/v0.23/layouts/decidim/_head.html.erb +1 -0
- data/config/locales/ca.yml +70 -2
- data/config/locales/cs.yml +71 -3
- data/config/locales/en.yml +75 -2
- 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 +27 -0
- data/lib/decidim/decidim_awesome/admin_engine.rb +3 -0
- data/lib/decidim/decidim_awesome/awesome_helpers.rb +16 -0
- data/lib/decidim/decidim_awesome/checksums.yml +6 -0
- data/lib/decidim/decidim_awesome/config.rb +13 -12
- data/lib/decidim/decidim_awesome/engine.rb +1 -1
- data/lib/decidim/decidim_awesome/map_component/component.rb +7 -1
- data/lib/decidim/decidim_awesome/menu_hacker.rb +90 -0
- 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 +1 -1
- 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 +48 -3
- 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: 32cc1fc0147bd8a5daf75a5deab25f18ede902f0ceb8c9a4a0073528dec97568
|
4
|
+
data.tar.gz: 2ed32bdc25c0e2ab7b5b8b7362adad7a191634290b896e6f3e0f630687ba0824
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df2b4b28994f8ad2f11e87080c683edb9fc8f215c76a7b6e15ebd27df018317fb64daf5f1c9b3910d2bd6c676d746caadec6defdaeb57716509cb9b3b33b67d8
|
7
|
+
data.tar.gz: 95a51e3cf9e87c8b2c9756ad6ab11ab1ee90d252b16f99740a20e190742bb0017e88bb36357ac2031d588bcf792b86d1337fe0685c7dfb309789beb4a7aa6797
|
data/README.md
CHANGED
@@ -33,7 +33,7 @@ Each hack can be scoped to one or more specific participatory spaces or componen
|
|
33
33
|
|
34
34
|
#### 1. Image support for the Quill editor
|
35
35
|
|
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
|
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 in-line encoding).
|
37
37
|
|
38
38
|
This feature allows you use images in newsletters as well.
|
39
39
|
|
@@ -71,13 +71,13 @@ Many scopes can be defined for every tweak.
|
|
71
71
|
|
72
72
|
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
73
|
|
74
|
-
It also provides a simple search by category, each category is
|
74
|
+
It also provides a simple search by category, each category is assigned to a different color.
|
75
75
|
|
76
76
|
![Awesome map](examples/awesome-map.png)
|
77
77
|
|
78
78
|
#### 7. Allow Decidim to use custom CSS themes for every tenant
|
79
79
|
|
80
|
-
When
|
80
|
+
When customizing CSS for a Decidim installation, each change affects all the organizations (tenant).
|
81
81
|
|
82
82
|
This feature allows to customize each organization css without affecting the others in the same Decidim installation.
|
83
83
|
|
@@ -106,14 +106,28 @@ With this feature you can have a support chat in Decidim. It is linked to a [Tel
|
|
106
106
|
|
107
107
|
![Intergram screenshot](examples/intergram.png)
|
108
108
|
|
109
|
+
#### 10. Custom CSS applied only according scoped restrictions
|
110
|
+
|
111
|
+
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
|
+
![CSS screenshot](examples/custom_styles.png)
|
114
|
+
|
115
|
+
#### 11. Change the main menu of Decidim entirely!
|
116
|
+
|
117
|
+
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.
|
118
|
+
|
119
|
+
![Menu hacks screenshot](examples/menu-1.png)
|
120
|
+
![Menu hacks screenshot](examples/menu-2.png)
|
121
|
+
![Menu hacks screenshot](examples/menu-3.png)
|
122
|
+
![Menu hacks screenshot](examples/menu-4.png)
|
109
123
|
|
110
124
|
#### To be continued...
|
111
125
|
|
112
126
|
Some things in the road-map:
|
113
127
|
|
114
128
|
1. Improve the conversation in comments by allowing images
|
115
|
-
1.
|
116
|
-
1.
|
129
|
+
1. Allow to create non-private surveys where the responding user is known by admins
|
130
|
+
1. Manipulate menus (reorder, change texts, add new items)
|
117
131
|
1. Propose something! or even better send a PR!
|
118
132
|
|
119
133
|
## Installation
|
@@ -121,7 +135,7 @@ Some things in the road-map:
|
|
121
135
|
Add this line to your application's Gemfile:
|
122
136
|
|
123
137
|
```ruby
|
124
|
-
gem "decidim-decidim_awesome", "~> 0.6.
|
138
|
+
gem "decidim-decidim_awesome", "~> 0.6.6"
|
125
139
|
```
|
126
140
|
|
127
141
|
And then execute:
|
@@ -146,6 +160,8 @@ admins do not even see it.
|
|
146
160
|
|
147
161
|
In order to personalize default values, create an initializer such as:
|
148
162
|
|
163
|
+
> **NOTE**: this is not necessary unless you want to **disable** some features. All features are enabled by default.
|
164
|
+
|
149
165
|
```ruby
|
150
166
|
# config/initializers/awesome_defaults.rb
|
151
167
|
|
@@ -159,6 +175,9 @@ Decidim::DecidimAwesome.configure do |config|
|
|
159
175
|
|
160
176
|
# De-activated, admins don't even see it as an option
|
161
177
|
config.use_markdown_editor = :disabled
|
178
|
+
|
179
|
+
# any other config var from lib/decidim/decidim_awesome.rb
|
180
|
+
...
|
162
181
|
end
|
163
182
|
```
|
164
183
|
|
@@ -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,30 @@
|
|
1
|
+
// = require_self
|
2
|
+
|
3
|
+
$(() => {
|
4
|
+
const $form = $("form.awesome-edit-config");
|
5
|
+
if ($form.length > 0) {
|
6
|
+
$form.find("input, textarea, select").on("change", () => {
|
7
|
+
$form.data("changed", true);
|
8
|
+
});
|
9
|
+
|
10
|
+
const safePath = $form.data("safe-path").split("?")[0];
|
11
|
+
$(document).on("click", "a", (event) => {
|
12
|
+
window.exitUrl = event.currentTarget.href;
|
13
|
+
});
|
14
|
+
$(document).on("submit", "form", (event) => {
|
15
|
+
window.exitUrl = event.currentTarget.action;
|
16
|
+
});
|
17
|
+
|
18
|
+
window.addEventListener("beforeunload", (event) => {
|
19
|
+
const exitUrl = window.exitUrl;
|
20
|
+
const hasChanged = $form.data("changed");
|
21
|
+
window.exitUrl = null;
|
22
|
+
|
23
|
+
if (!hasChanged || (exitUrl && exitUrl.includes(safePath))) {
|
24
|
+
return null;
|
25
|
+
}
|
26
|
+
|
27
|
+
event.returnValue = true;
|
28
|
+
});
|
29
|
+
}
|
30
|
+
});
|
@@ -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,13 +1,14 @@
|
|
1
1
|
// = require jsrender.min
|
2
2
|
// = require decidim/map
|
3
3
|
// = require leaflet.featuregroup.subgroup
|
4
|
+
// = require decidim/decidim_awesome/awesome_map/utilities
|
4
5
|
// = require decidim/decidim_awesome/awesome_map/categories
|
5
6
|
// = require decidim/decidim_awesome/awesome_map/legacy_proposals
|
6
7
|
// = require decidim/decidim_awesome/awesome_map/meetings
|
7
8
|
// = require_self
|
8
9
|
|
9
10
|
((exports) => {
|
10
|
-
const { fetchProposals, fetchMeetings, getCategory } = exports.AwesomeMap;
|
11
|
+
const { fetchProposals, fetchMeetings, getCategory, amendments } = exports.AwesomeMap;
|
11
12
|
|
12
13
|
const collapsedMenu = $("#map").data("collapsed");
|
13
14
|
const show = {
|
@@ -22,14 +23,12 @@
|
|
22
23
|
const popupProposalTemplateId = "legacy-marker-proposal-popup";
|
23
24
|
|
24
25
|
const cluster = L.markerClusterGroup();
|
25
|
-
const amendments = [];
|
26
|
-
|
27
26
|
const layers = {};
|
28
27
|
|
29
28
|
const control = L.control.layers(null, null, {
|
30
|
-
position: 'topleft',
|
29
|
+
position: 'topleft',
|
31
30
|
sortLayers: false,
|
32
|
-
collapsed: collapsedMenu,
|
31
|
+
collapsed: collapsedMenu,
|
33
32
|
// hideSingleBase: true
|
34
33
|
});
|
35
34
|
const allMarkers = [];
|
@@ -39,26 +38,20 @@
|
|
39
38
|
node = document.createElement("div");
|
40
39
|
|
41
40
|
$($.templates(`#${tmpl}`).render(element)).appendTo(node);
|
42
|
-
|
41
|
+
|
43
42
|
marker.bindPopup(node, {
|
44
43
|
maxwidth: 640,
|
45
44
|
minWidth: 500,
|
46
45
|
keepInView: true,
|
47
46
|
className: "map-info"
|
48
47
|
}).openPopup();
|
49
|
-
|
48
|
+
|
50
49
|
allMarkers.push({
|
51
50
|
marker: marker,
|
52
51
|
component: component,
|
53
52
|
element: element
|
54
53
|
});
|
55
54
|
|
56
|
-
// Check if it has amendments, add it to a list
|
57
|
-
if(element.amendments && element.amendments.length) {
|
58
|
-
element.amendments.forEach((amendment) => {
|
59
|
-
amendments.push(amendment.emendation.id);
|
60
|
-
});
|
61
|
-
}
|
62
55
|
// Add to category layer
|
63
56
|
let cat = getCategory(element.category);
|
64
57
|
if(layers[cat.id]) {
|
@@ -86,7 +79,7 @@
|
|
86
79
|
cluster.addTo(map);
|
87
80
|
|
88
81
|
// Load markers
|
89
|
-
components.forEach((component) => {
|
82
|
+
components.forEach((component) => {
|
90
83
|
if(component.type == "proposals") {
|
91
84
|
// add control layer for proposals
|
92
85
|
layers.proposals = {
|
@@ -108,7 +101,7 @@
|
|
108
101
|
|
109
102
|
fetchProposals(component, '', (element, marker) => {
|
110
103
|
if(show[element.state || 'notAnswered']) {
|
111
|
-
drawMarker(element, marker, component).addTo(layers.proposals.group)
|
104
|
+
drawMarker(element, marker, component).addTo(layers.proposals.group)
|
112
105
|
}
|
113
106
|
}, () => {
|
114
107
|
// finall call
|
@@ -122,7 +115,7 @@
|
|
122
115
|
});
|
123
116
|
});
|
124
117
|
}
|
125
|
-
|
118
|
+
|
126
119
|
if(component.type == "meetings") {
|
127
120
|
// add control layer for meetings
|
128
121
|
layers.meetings = {
|
@@ -131,7 +124,7 @@
|
|
131
124
|
};
|
132
125
|
control.addOverlay(layers.meetings.group, layers.meetings.label);
|
133
126
|
layers.meetings.group.addTo(map);
|
134
|
-
|
127
|
+
|
135
128
|
fetchMeetings(component, '', (element, marker) => {
|
136
129
|
drawMarker(element, marker, component).addTo(layers.meetings.group);
|
137
130
|
}, () => {
|
@@ -167,12 +160,12 @@
|
|
167
160
|
|
168
161
|
// watch events for subcategories syncronitzation
|
169
162
|
const getCatFromClass = (name) => {
|
170
|
-
let id = name.match(/awesome_map-category_(\d+)/)
|
163
|
+
let id = name.match(/awesome_map-category_(\d+)/)
|
171
164
|
if(!id) return;
|
172
165
|
const cat = getCategory(id[1]);
|
173
166
|
if(!cat || !cat.name) return;
|
174
167
|
|
175
|
-
return cat;
|
168
|
+
return cat;
|
176
169
|
};
|
177
170
|
|
178
171
|
const indeterminateInput = (id) => {
|
@@ -1,8 +1,9 @@
|
|
1
1
|
// = require decidim/decidim_awesome/awesome_map/api_fetcher
|
2
2
|
// = require decidim/decidim_awesome/awesome_map/categories
|
3
|
+
// = require decidim/decidim_awesome/awesome_map/utilities
|
3
4
|
|
4
5
|
((exports) => {
|
5
|
-
const { getCategory } = exports.AwesomeMap;
|
6
|
+
const { getCategory, truncate } = exports.AwesomeMap;
|
6
7
|
const query = `query ($id: ID!, $after: String!) {
|
7
8
|
component(id: $id) {
|
8
9
|
id
|
@@ -48,7 +49,7 @@
|
|
48
49
|
})
|
49
50
|
});
|
50
51
|
|
51
|
-
element.body = element.body.replace(/\n/g, "<br>");
|
52
|
+
element.body = truncate(element.body.replace(/\n/g, "<br>"));
|
52
53
|
callback(element, marker);
|
53
54
|
};
|
54
55
|
|
@@ -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);
|