decidim-decidim_awesome 0.8.3 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of decidim-decidim_awesome might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +54 -45
- data/Rakefile +1 -1
- data/app/commands/decidim/decidim_awesome/admin/create_constraint.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/create_custom_redirect.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/create_menu_hack.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/create_proposal_custom_field.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/create_scoped_admin.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/create_scoped_style.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/destroy_constraint.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/destroy_custom_redirect.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/destroy_menu_hack.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/destroy_proposal_custom_field.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_admin.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_style.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/rename_scope_label.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/update_config.rb +2 -3
- data/app/commands/decidim/decidim_awesome/admin/update_constraint.rb +2 -2
- data/app/commands/decidim/decidim_awesome/admin/update_custom_redirect.rb +1 -1
- data/app/commands/decidim/decidim_awesome/admin/update_menu_hack.rb +1 -1
- data/app/commands/decidim/decidim_awesome/command.rb +14 -0
- data/app/commands/decidim/decidim_awesome/create_editor_image.rb +1 -1
- data/app/controllers/concerns/decidim/decidim_awesome/admin_accountability/admin/filterable.rb +67 -0
- data/app/controllers/concerns/decidim/decidim_awesome/admin_accountability/admin/filterable_helper.rb +37 -0
- data/app/controllers/decidim/decidim_awesome/admin/admin_accountability_controller.rb +51 -0
- data/app/controllers/decidim/decidim_awesome/admin/checks_controller.rb +6 -3
- data/app/controllers/decidim/decidim_awesome/admin/config_controller.rb +2 -0
- data/app/controllers/decidim/decidim_awesome/admin/custom_redirects_controller.rb +2 -0
- data/app/controllers/decidim/decidim_awesome/admin/menu_hacks_controller.rb +2 -0
- data/app/controllers/decidim/decidim_awesome/editor_images_controller.rb +0 -2
- data/app/forms/decidim/decidim_awesome/admin/config_form.rb +14 -0
- data/app/forms/decidim/decidim_awesome/admin/menu_form.rb +1 -1
- data/app/forms/decidim/decidim_awesome/proposals/proposal_wizard_create_step_form_override.rb +26 -8
- data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +12 -8
- data/app/helpers/decidim/decidim_awesome/map_helper.rb +14 -11
- data/app/jobs/decidim/decidim_awesome/export_admin_actions_job.rb +28 -0
- data/app/middleware/decidim/decidim_awesome/current_config.rb +4 -0
- data/app/models/decidim/decidim_awesome/awesome_config.rb +0 -1
- data/app/models/decidim/decidim_awesome/config_constraint.rb +0 -2
- data/app/models/decidim/decidim_awesome/editor_image.rb +0 -3
- data/app/models/decidim/decidim_awesome/paper_trail_version.rb +99 -0
- data/app/packs/entrypoints/decidim_admin_decidim_awesome.js +3 -2
- data/app/packs/images/decidim/decidim_awesome/pokecode-logo.png +0 -0
- data/app/packs/src/decidim/decidim_awesome/admin/auto_edit.js +7 -7
- data/app/packs/src/decidim/decidim_awesome/admin/check_redirections.js +2 -2
- data/app/packs/src/decidim/decidim_awesome/admin/constraints.js +5 -5
- data/app/packs/src/decidim/decidim_awesome/admin/custom_fields_builder.js +11 -10
- data/app/packs/src/decidim/decidim_awesome/admin/form_exit_warn.js +1 -0
- data/app/packs/src/decidim/decidim_awesome/admin/user_picker.js +1 -0
- data/app/packs/src/decidim/decidim_awesome/awesome_map/api/fetcher.js +13 -13
- data/app/packs/src/decidim/decidim_awesome/awesome_map/awesome_map.js +14 -12
- data/app/packs/src/decidim/decidim_awesome/awesome_map/controllers/controller.js +16 -12
- data/app/packs/src/decidim/decidim_awesome/awesome_map/controllers/proposals_controller.js +3 -3
- data/app/packs/src/decidim/decidim_awesome/awesome_map/controls_ui.js +25 -26
- data/app/packs/src/decidim/decidim_awesome/awesome_map/load_map.js +1 -0
- data/app/packs/src/decidim/decidim_awesome/editors/editor.js +33 -12
- data/app/packs/src/decidim/decidim_awesome/forms/autosave.js +8 -12
- data/app/packs/src/decidim/decidim_awesome/forms/custom_fields_renderer.js +36 -27
- data/app/packs/src/decidim/decidim_awesome/forms/rich_text_plugin.js +6 -4
- data/app/packs/src/decidim/decidim_awesome/proposals/custom_fields.js +7 -7
- data/app/packs/src/decidim/decidim_awesome/proposals/images.js +2 -2
- data/app/packs/stylesheets/decidim/decidim_awesome/awesome_admin.scss +8 -5
- data/app/permissions/decidim/decidim_awesome/admin/permissions.rb +15 -1
- data/app/permissions/decidim/decidim_awesome/permissions.rb +4 -6
- data/app/presenters/decidim/decidim_awesome/paper_trail_base_presenter.rb +28 -0
- data/app/presenters/decidim/decidim_awesome/participatory_space_role_presenter.rb +45 -0
- data/app/presenters/decidim/decidim_awesome/role_base_presenter.rb +102 -0
- data/app/presenters/decidim/decidim_awesome/user_entity_presenter.rb +50 -0
- data/app/serializers/decidim/decidim_awesome/paper_trail_version_serializer.rb +37 -0
- data/app/validators/concerns/decidim/decidim_awesome/etiquette_validator_override.rb +41 -0
- data/app/views/decidim/decidim_awesome/admin/admin_accountability/index.html.erb +59 -0
- data/app/views/decidim/decidim_awesome/admin/checks/_assets_tester.html.erb +2 -0
- data/app/views/decidim/decidim_awesome/admin/config/_form_proposals.html.erb +82 -2
- data/app/views/decidim/decidim_awesome/admin/shared/_filters_with_date.html.erb +56 -0
- data/app/views/decidim/proposals/admin/proposals/_form.html.erb +1 -1
- data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +9 -17
- data/app/views/layouts/decidim/admin/decidim_awesome.html.erb +1 -1
- data/app/views/{v0.25 → v0.27}/layouts/decidim/_head.html.erb +12 -4
- data/config/i18n-tasks.yml +4 -0
- data/config/locales/ca.yml +22 -2
- data/config/locales/cs.yml +7 -2
- data/config/locales/de.yml +20 -1
- data/config/locales/en.yml +90 -1
- data/config/locales/es.yml +2 -2
- data/config/locales/fr.yml +22 -2
- data/config/locales/it.yml +2 -2
- data/config/locales/ja.yml +3 -2
- data/config/locales/nl.yml +1 -1
- data/config/locales/pt-BR.yml +2 -2
- data/db/seeds.rb +1 -1
- data/lib/decidim/decidim_awesome/admin_engine.rb +15 -1
- data/lib/decidim/decidim_awesome/awesome.rb +55 -1
- data/lib/decidim/decidim_awesome/checksums.yml +13 -3
- data/lib/decidim/decidim_awesome/config.rb +14 -14
- data/lib/decidim/decidim_awesome/context_analyzers/request_analyzer.rb +1 -1
- data/lib/decidim/decidim_awesome/engine.rb +36 -9
- data/lib/decidim/decidim_awesome/iframe_component/component.rb +2 -1
- data/lib/decidim/decidim_awesome/menu_hacker.rb +6 -0
- data/lib/decidim/decidim_awesome/system_checker.rb +2 -0
- data/lib/decidim/decidim_awesome/test/factories.rb +7 -0
- data/lib/decidim/decidim_awesome/test/initializer.rb +10 -2
- data/lib/decidim/decidim_awesome/test/shared_examples/action_log_presenter_examples.rb +61 -0
- data/lib/decidim/decidim_awesome/test/shared_examples/scoped_admins_examples.rb +7 -4
- data/lib/decidim/decidim_awesome/test/shared_examples/summary_examples.rb +2 -2
- data/lib/decidim/decidim_awesome/version.rb +2 -2
- data/lib/tasks/decidim_awesome_active_storage_migrations_tasks.rake +1 -3
- data/package.json +21 -164
- metadata +39 -39
- data/app/packs/images/decidim/decidim_awesome/platoniq-logo.png +0 -0
- data/app/packs/src/vendor/image-resize.min.js +0 -1
- data/app/packs/src/vendor/image-upload.min.js +0 -6
- data/app/packs/src/vendor/leaflet.featuregroup.subgroup.js +0 -184
- /data/app/views/{v0.25 → v0.27}/decidim/proposals/collaborative_drafts/_show.html.erb +0 -0
- /data/app/views/{v0.25 → v0.27}/layouts/decidim/admin/_header.html.erb +0 -0
@@ -1,8 +1,11 @@
|
|
1
1
|
import * as L from "leaflet";
|
2
|
-
|
2
|
+
// comes with Decidim
|
3
|
+
import "src/decidim/map/icon.js"
|
3
4
|
import "src/decidim/vendor/leaflet-tilelayer-here"
|
4
|
-
|
5
|
-
import "leaflet.
|
5
|
+
// Comes with Decidim
|
6
|
+
import "leaflet.markercluster";
|
7
|
+
// included in this package.json
|
8
|
+
import "leaflet.featuregroup.subgroup"
|
6
9
|
import "src/vendor/jquery.truncate"
|
7
10
|
import "jsrender"
|
8
11
|
|
@@ -60,7 +63,7 @@ export default class AwesomeMap {
|
|
60
63
|
this.loading.pop();
|
61
64
|
this.autoResize();
|
62
65
|
|
63
|
-
if (this.loading.length
|
66
|
+
if (this.loading.length === 0) {
|
64
67
|
this.controls.$loading.hide();
|
65
68
|
// call trigger as all loads are finished
|
66
69
|
this.onFinished();
|
@@ -90,13 +93,11 @@ export default class AwesomeMap {
|
|
90
93
|
};
|
91
94
|
|
92
95
|
if (category) {
|
93
|
-
let id = category.id
|
94
|
-
|
95
|
-
: parseInt(category, 10);
|
96
|
-
let cat = this.categories.find((c) => c.id == id);
|
96
|
+
let id = category.id ? parseInt(category.id, 10) : parseInt(category, 10); // eslint-disable-line no-ternary, multiline-ternary
|
97
|
+
let cat = this.categories.find((ct) => ct.id === id);
|
97
98
|
if (cat) {
|
98
99
|
cat.children = () => {
|
99
|
-
return this.categories.filter((
|
100
|
+
return this.categories.filter((ct) => ct.parent === cat.id);
|
100
101
|
}
|
101
102
|
return cat;
|
102
103
|
}
|
@@ -105,12 +106,12 @@ export default class AwesomeMap {
|
|
105
106
|
}
|
106
107
|
|
107
108
|
_getController(component) {
|
108
|
-
let controller;
|
109
|
+
let controller = null;
|
109
110
|
|
110
|
-
if (component.type
|
111
|
+
if (component.type === "proposals") {
|
111
112
|
controller = new ProposalsController(this, component);
|
112
113
|
}
|
113
|
-
if (component.type
|
114
|
+
if (component.type === "meetings" && this.config.menu.meetings) {
|
114
115
|
controller = new MeetingsController(this, component);
|
115
116
|
}
|
116
117
|
|
@@ -125,5 +126,6 @@ export default class AwesomeMap {
|
|
125
126
|
this.controllers[component.type] = controller;
|
126
127
|
return this.controllers[component.type]
|
127
128
|
}
|
129
|
+
return null;
|
128
130
|
}
|
129
131
|
}
|
@@ -14,9 +14,10 @@ export default class Controller {
|
|
14
14
|
}
|
15
15
|
|
16
16
|
getLabel() {
|
17
|
-
let text = this.awesomeMap.config.menu.mergeComponents ||
|
18
|
-
|
19
|
-
|
17
|
+
let text = this.awesomeMap.config.menu.mergeComponents || this.component.name;
|
18
|
+
if (!text) {
|
19
|
+
text = window.DecidimAwesome.texts[this.component.type];
|
20
|
+
}
|
20
21
|
return `<span class="awesome_map-component" id="awesome_map-component_${this.component.id}" title="0" data-layer="${this.component.type}">${text}</span>`
|
21
22
|
}
|
22
23
|
|
@@ -29,13 +30,15 @@ export default class Controller {
|
|
29
30
|
this.fetcher.onCollection = (collection) => {
|
30
31
|
if (collection && collection.edges) {
|
31
32
|
// Add markers to the main cluster group
|
33
|
+
const collectionEdges = collection.edges.filter((item) => item.node.coordinates && item.node.coordinates.latitude && item.node.coordinates.longitude);
|
32
34
|
try {
|
33
|
-
this.awesomeMap.cluster.addLayers(
|
34
|
-
} catch (
|
35
|
-
console.error("Failed marker collection assignation",
|
35
|
+
this.awesomeMap.cluster.addLayers(collectionEdges.map((item) => item.node.marker));
|
36
|
+
} catch (evt) {
|
37
|
+
console.error("Failed marker collection assignation", collectionEdges, "error", evt);
|
36
38
|
}
|
37
39
|
// subgroups don't have th addLayers utility
|
38
|
-
|
40
|
+
collectionEdges.forEach((item) => {
|
41
|
+
this.awesomeMap.layers[this.component.type].group.addLayer(item.node.marker);
|
39
42
|
this.addMarkerCategory(item.node.marker, item.node.category);
|
40
43
|
this.addMarkerHashtags(item.node.marker, item.node.hashtags);
|
41
44
|
});
|
@@ -45,7 +48,8 @@ export default class Controller {
|
|
45
48
|
|
46
49
|
addControls() {
|
47
50
|
this.awesomeMap.controls.main.addOverlay(this.controls.group, this.controls.label);
|
48
|
-
this.
|
51
|
+
this.controls.group.addTo(this.awesomeMap.map);
|
52
|
+
this.awesomeMap.layers[this.component.type] = this.controls;
|
49
53
|
}
|
50
54
|
|
51
55
|
loadNodes() {
|
@@ -94,8 +98,8 @@ export default class Controller {
|
|
94
98
|
try {
|
95
99
|
this.awesomeMap.layers[cat.id].group.addLayer(marker);
|
96
100
|
this.awesomeMap.controls.showCategory(cat);
|
97
|
-
} catch (
|
98
|
-
console.error("Failed category marker assignation", marker,
|
101
|
+
} catch (evt) {
|
102
|
+
console.error("Failed category marker assignation", marker, evt.message);
|
99
103
|
}
|
100
104
|
}
|
101
105
|
}
|
@@ -105,8 +109,8 @@ export default class Controller {
|
|
105
109
|
if (this.awesomeMap.config.menu.hashtags) {
|
106
110
|
try {
|
107
111
|
this.awesomeMap.controls.addHashtagsControls(hashtags, marker);
|
108
|
-
} catch (
|
109
|
-
console.error("Failed hashtags marker assignation", marker,
|
112
|
+
} catch (evt) {
|
113
|
+
console.error("Failed hashtags marker assignation", marker, evt.message);
|
110
114
|
}
|
111
115
|
}
|
112
116
|
}
|
@@ -62,15 +62,15 @@ export default class ProposalsController extends Controller {
|
|
62
62
|
|
63
63
|
// Process all amendments
|
64
64
|
iterableAmendments.forEach((amendment) => {
|
65
|
-
const marker = this.allNodes.find((node) => node.id
|
65
|
+
const marker = this.allNodes.find((node) => node.id === amendment[0]);
|
66
66
|
const parent = amendment[1];
|
67
67
|
// console.log("marker", marker, "parent proposal", parent)
|
68
68
|
// add marker to amendments layers and remove it from proposals
|
69
69
|
if (marker) {
|
70
70
|
try {
|
71
71
|
marker.marker.removeFrom(this.controls.group)
|
72
|
-
} catch (
|
73
|
-
console.error("error removeFrom marker", marker, "layer", this.controls.group,
|
72
|
+
} catch (evt) {
|
73
|
+
console.error("error removeFrom marker", marker, "layer", this.controls.group, evt);
|
74
74
|
}
|
75
75
|
if (this.awesomeMap.config.menu.amendments) {
|
76
76
|
marker.marker.addTo(this.awesomeMap.layers.amendments.group);
|
@@ -1,3 +1,5 @@
|
|
1
|
+
/* eslint-disable no-ternary, multiline-ternary */
|
2
|
+
|
1
3
|
import * as L from "leaflet";
|
2
4
|
|
3
5
|
export default class ControlsUI {
|
@@ -33,28 +35,28 @@ export default class ControlsUI {
|
|
33
35
|
}
|
34
36
|
|
35
37
|
// sub-layer hashtag title toggle
|
36
|
-
$("#awesome-map").on("click", ".awesome_map-title-control", (
|
37
|
-
|
38
|
-
|
38
|
+
$("#awesome-map").on("click", ".awesome_map-title-control", (evt) => {
|
39
|
+
evt.preventDefault();
|
40
|
+
evt.stopPropagation();
|
39
41
|
$("#awesome_map-categories-control").toggleClass("active");
|
40
42
|
$("#awesome_map-hashtags-control").toggleClass("active");
|
41
43
|
});
|
42
44
|
|
43
45
|
// hashtag events
|
44
|
-
$("#awesome-map").on("change", ".awesome_map-hashtags-selector", (
|
45
|
-
|
46
|
-
|
47
|
-
const tag = $(
|
48
|
-
// console.log("changed, layer", tag, "checked",
|
46
|
+
$("#awesome-map").on("change", ".awesome_map-hashtags-selector", (evt) => {
|
47
|
+
evt.preventDefault();
|
48
|
+
evt.stopPropagation();
|
49
|
+
const tag = $(evt.target).closest("label").data("layer");
|
50
|
+
// console.log("changed, layer", tag, "checked", evt.target.checked, e);
|
49
51
|
if (tag) {
|
50
52
|
this.updateHashtagLayers();
|
51
53
|
}
|
52
54
|
});
|
53
55
|
|
54
56
|
// select/deselect all tags
|
55
|
-
$("#awesome-map").on("click", ".awesome_map-toggle_all_tags", (
|
56
|
-
|
57
|
-
|
57
|
+
$("#awesome-map").on("click", ".awesome_map-toggle_all_tags", (evt) => {
|
58
|
+
evt.preventDefault();
|
59
|
+
evt.stopPropagation();
|
58
60
|
$("#awesome-map .awesome_map-hashtags-selector").prop("checked", $("#awesome-map .awesome_map-hashtags-selector:checked").length < $("#awesome-map .awesome_map-hashtags-selector").length);
|
59
61
|
this.updateHashtagLayers();
|
60
62
|
});
|
@@ -74,22 +76,20 @@ export default class ControlsUI {
|
|
74
76
|
group: new L.FeatureGroup.SubGroup(this.awesomeMap.cluster)
|
75
77
|
};
|
76
78
|
this.awesomeMap.layers[category.id].group.addTo(this.awesomeMap.map);
|
77
|
-
$("#awesome_map-categories-control .categories-container").append(`<label data-layer="${category.id}" class="awesome_map-category-${category.id}${category.parent
|
78
|
-
? " subcategory"
|
79
|
-
: ""}" data-parent="${category.parent}"><input type="checkbox" class="awesome_map-categories-selector" checked><span>${label}</span></label>`);
|
79
|
+
$("#awesome_map-categories-control .categories-container").append(`<label data-layer="${category.id}" class="awesome_map-category-${category.id}${category.parent ? " subcategory" : ""}" data-parent="${category.parent}"><input type="checkbox" class="awesome_map-categories-selector" checked><span>${label}</span></label>`);
|
80
80
|
})
|
81
81
|
|
82
82
|
// category events
|
83
|
-
$("#awesome-map").on("change", ".awesome_map-categories-selector", (
|
84
|
-
|
85
|
-
|
83
|
+
$("#awesome-map").on("change", ".awesome_map-categories-selector", (evt) => {
|
84
|
+
evt.preventDefault();
|
85
|
+
evt.stopPropagation();
|
86
86
|
|
87
|
-
const id = $(
|
87
|
+
const id = $(evt.target).closest("label").data("layer");
|
88
88
|
const cat = this.awesomeMap.getCategory(id);
|
89
|
-
// console.log("changed, layer", id, "cat", cat, "checked",
|
89
|
+
// console.log("changed, layer", id, "cat", cat, "checked", evt.target.checked, e);
|
90
90
|
if (cat) {
|
91
91
|
const layer = this.awesomeMap.layers[cat.id];
|
92
|
-
if (
|
92
|
+
if (evt.target.checked) {
|
93
93
|
// show group of markers
|
94
94
|
this.awesomeMap.map.addLayer(layer.group);
|
95
95
|
} else {
|
@@ -131,7 +131,7 @@ export default class ControlsUI {
|
|
131
131
|
|
132
132
|
const $label = $(`label.awesome_map-hashtag-${hashtag.tag}`);
|
133
133
|
// update number of items
|
134
|
-
$label.attr("title", `${parseInt($label.attr("title") || 0) + 1} ${window.DecidimAwesome.texts.items}`);
|
134
|
+
$label.attr("title", `${parseInt($label.attr("title") || 0, 10) + 1} ${window.DecidimAwesome.texts.items}`);
|
135
135
|
});
|
136
136
|
}
|
137
137
|
}
|
@@ -143,10 +143,10 @@ export default class ControlsUI {
|
|
143
143
|
const $parent = $(`label.awesome_map-category-${cat.parent}`);
|
144
144
|
$label.show();
|
145
145
|
// update number of items
|
146
|
-
$label.attr("title", `${parseInt($label.attr("title") || 0) + 1} ${window.DecidimAwesome.texts.items}`);
|
146
|
+
$label.attr("title", `${parseInt($label.attr("title") || 0, 10) + 1} ${window.DecidimAwesome.texts.items}`);
|
147
147
|
// show parent if apply
|
148
148
|
$parent.show();
|
149
|
-
$parent.attr("title", `${parseInt($parent.attr("title") || 0) + 1} ${window.DecidimAwesome.texts.items}`);
|
149
|
+
$parent.attr("title", `${parseInt($parent.attr("title") || 0, 10) + 1} ${window.DecidimAwesome.texts.items}`);
|
150
150
|
}
|
151
151
|
|
152
152
|
removeHiddenComponents() {
|
@@ -200,8 +200,8 @@ export default class ControlsUI {
|
|
200
200
|
if (cat.parent) {
|
201
201
|
let $input = $(`.awesome_map-category-${cat.parent}`).contents("input");
|
202
202
|
let $subcats = $(`[class^="awesome_map-category-"][data-parent="${cat.parent}"]:visible`);
|
203
|
-
let
|
204
|
-
$input.prop("indeterminate",
|
203
|
+
let numChecked = $subcats.contents("input:checked").length;
|
204
|
+
$input.prop("indeterminate", numChecked !== $subcats.length && numChecked !== 0);
|
205
205
|
}
|
206
206
|
}
|
207
207
|
|
@@ -213,7 +213,6 @@ export default class ControlsUI {
|
|
213
213
|
$div.contents("label").each((_idx, el) => {
|
214
214
|
if ($(el).text().localeCompare($last.text()) > 0) {
|
215
215
|
$(el).before($last);
|
216
|
-
return false;
|
217
216
|
}
|
218
217
|
});
|
219
218
|
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
/* eslint-disable require-jsdoc */
|
1
|
+
/* eslint-disable require-jsdoc, func-style */
|
2
2
|
|
3
3
|
/*
|
4
4
|
* Since version 0.25 we follow a different strategy and opt to destroy and override completely the original editor
|
@@ -13,10 +13,9 @@ import "inline-attachment/src/codemirror-4.inline-attachment";
|
|
13
13
|
import "inline-attachment/src/jquery.inline-attachment";
|
14
14
|
import hljs from "highlight.js";
|
15
15
|
import "highlight.js/styles/github.css";
|
16
|
-
|
17
|
-
|
18
|
-
import "src/vendor/image-
|
19
|
-
import "src/vendor/image-upload.min"
|
16
|
+
import "src/decidim/editor/clipboard_override"
|
17
|
+
import "src/decidim/vendor/image-resize.min"
|
18
|
+
import "src/decidim/vendor/image-upload.min"
|
20
19
|
|
21
20
|
const DecidimAwesome = window.DecidimAwesome || {};
|
22
21
|
const quillFormats = ["bold", "italic", "link", "underline", "header", "list", "video", "image", "alt", "break", "width", "style", "code", "blockquote", "indent"];
|
@@ -27,8 +26,8 @@ export function destroyQuillEditor(container) {
|
|
27
26
|
const content = $(container).find(".ql-editor").html();
|
28
27
|
$(container).html(content);
|
29
28
|
$(container).siblings(".ql-toolbar").remove();
|
30
|
-
$(container).find("*[class*='ql-']").removeClass((index,
|
31
|
-
$(container).removeClass((index,
|
29
|
+
$(container).find("*[class*='ql-']").removeClass((index, className) => (className.match(/(^|\s)ql-\S+/g) || []).join(" "));
|
30
|
+
$(container).removeClass((index, className) => (className.match(/(^|\s)ql-\S+/g) || []).join(" "));
|
32
31
|
if ($(container).next().is("p.help-text")) {
|
33
32
|
$(container).next().remove();
|
34
33
|
}
|
@@ -41,6 +40,7 @@ export function destroyQuillEditor(container) {
|
|
41
40
|
export function createQuillEditor(container) {
|
42
41
|
const toolbar = $(container).data("toolbar");
|
43
42
|
const disabled = $(container).data("disabled");
|
43
|
+
const allowedEmptyContentSelector = "iframe";
|
44
44
|
|
45
45
|
let quillToolbar = [
|
46
46
|
["bold", "italic", "underline", "linebreak"],
|
@@ -93,7 +93,7 @@ export function createQuillEditor(container) {
|
|
93
93
|
modules: ["Resize", "DisplaySize"]
|
94
94
|
}
|
95
95
|
modules.imageUpload = {
|
96
|
-
url:
|
96
|
+
url: DecidimAwesome.editor_uploader_path,
|
97
97
|
method: "POST",
|
98
98
|
name: "image",
|
99
99
|
withCredentials: false,
|
@@ -104,7 +104,18 @@ export function createQuillEditor(container) {
|
|
104
104
|
},
|
105
105
|
callbackKO: (serverError) => {
|
106
106
|
$("div.ql-toolbar").last().removeClass("editor-loading")
|
107
|
-
|
107
|
+
let msg = serverError && serverError.body;
|
108
|
+
try {
|
109
|
+
msg = JSON.parse(msg).message;
|
110
|
+
} catch (evt) { console.error("Parsing error", evt); }
|
111
|
+
console.error(`Image upload error: ${msg}`);
|
112
|
+
let $p = $(`<p class="text-alert help-text">${msg}</p>`);
|
113
|
+
$(container).after($p)
|
114
|
+
setTimeout(() => {
|
115
|
+
$p.fadeOut(1000, () => {
|
116
|
+
$p.destroy();
|
117
|
+
});
|
118
|
+
}, 3000);
|
108
119
|
},
|
109
120
|
checkBeforeSend: (file, next) => {
|
110
121
|
$("div.ql-toolbar").last().addClass("editor-loading")
|
@@ -137,6 +148,16 @@ export function createQuillEditor(container) {
|
|
137
148
|
} else {
|
138
149
|
$input.val(quill.root.innerHTML);
|
139
150
|
}
|
151
|
+
if ((text === "\n" || text === "\n\n") && quill.root.querySelectorAll(allowedEmptyContentSelector).length === 0) {
|
152
|
+
$input.val("");
|
153
|
+
} else {
|
154
|
+
const emptyParagraph = "<p><br></p>";
|
155
|
+
const cleanHTML = quill.root.innerHTML.replace(
|
156
|
+
new RegExp(`^${emptyParagraph}|${emptyParagraph}$`, "g"),
|
157
|
+
""
|
158
|
+
);
|
159
|
+
$input.val(cleanHTML);
|
160
|
+
}
|
140
161
|
});
|
141
162
|
// After editor is ready, linebreak_module deletes two extraneous new lines
|
142
163
|
quill.emitter.emit("editor-ready");
|
@@ -153,7 +174,7 @@ export function createQuillEditor(container) {
|
|
153
174
|
}
|
154
175
|
|
155
176
|
export function createMarkdownEditor(container) {
|
156
|
-
const
|
177
|
+
const text = DecidimAwesome.texts.drag_and_drop_image;
|
157
178
|
const token = $('meta[name="csrf-token"]').attr("content");
|
158
179
|
const $input = $(container).siblings('input[type="hidden"]');
|
159
180
|
const $faker = $('<textarea name="faker-inscrybmde"/>');
|
@@ -174,8 +195,8 @@ export function createMarkdownEditor(container) {
|
|
174
195
|
|
175
196
|
// Allow image upload
|
176
197
|
if (DecidimAwesome.allow_images_in_markdown_editor) {
|
177
|
-
$(inscrybmde.gui.statusbar).prepend(`<span class="help-text" style="float:left;margin:0;text-align:left;">${
|
178
|
-
inlineAttachment.editors.codemirror4.attach(inscrybmde.codemirror, {
|
198
|
+
$(inscrybmde.gui.statusbar).prepend(`<span class="help-text" style="float:left;margin:0;text-align:left;">${text}</span>`);
|
199
|
+
window.inlineAttachment.editors.codemirror4.attach(inscrybmde.codemirror, {
|
179
200
|
uploadUrl: DecidimAwesome.editor_uploader_path,
|
180
201
|
uploadFieldName: "image",
|
181
202
|
jsonFieldName: "url",
|
@@ -33,18 +33,14 @@ $(() => {
|
|
33
33
|
'[name="utf8"]',
|
34
34
|
'[name="authenticity_token"]',
|
35
35
|
"[disabled]",
|
36
|
-
|
36
|
+
// there are problems with matrix questions
|
37
|
+
'[type="checkbox"]'
|
37
38
|
]
|
38
39
|
});
|
39
40
|
|
40
|
-
const showMsg = (msg, error = false,
|
41
|
-
const time = error
|
42
|
-
|
43
|
-
: default_time;
|
44
|
-
const $div = $(`<div class="awesome_autosave-notice${error
|
45
|
-
? " error"
|
46
|
-
: ""}">${msg}</div>`).
|
47
|
-
appendTo($form);
|
41
|
+
const showMsg = (msg, error = false, defaultTime = 700) => {
|
42
|
+
const time = error ? 5000 : defaultTime; // eslint-disable-line no-ternary, multiline-ternary
|
43
|
+
const $div = $(`<div class="awesome_autosave-notice${error ? " error" : ""}">${msg}</div>`).appendTo($form); // eslint-disable-line no-ternary, multiline-ternary
|
48
44
|
setTimeout(() => {
|
49
45
|
$div.fadeOut(500, () => {
|
50
46
|
$div.remove();
|
@@ -62,14 +58,14 @@ $(() => {
|
|
62
58
|
}
|
63
59
|
|
64
60
|
// restore if available
|
65
|
-
store.apply();
|
61
|
+
store.apply(); // eslint-disable-line prefer-reflect
|
66
62
|
// restore checkboxes
|
67
63
|
try {
|
68
64
|
let checkboxes = JSON.parse(window.localStorage.getItem(storeCheckboxesId));
|
69
|
-
for (let id in checkboxes) {
|
65
|
+
for (let id in checkboxes) { // eslint-disable-line guard-for-in
|
70
66
|
$(`#${id}`).prop("checked", checkboxes[id]);
|
71
67
|
}
|
72
|
-
} catch (
|
68
|
+
} catch (evt) {
|
73
69
|
console.log("No checkboxes found");
|
74
70
|
}
|
75
71
|
// this trigger the "change" event, it seems that it is too much
|
@@ -2,8 +2,8 @@ require("formBuilder/dist/form-render.min.js")
|
|
2
2
|
import "src/decidim/decidim_awesome/forms/rich_text_plugin"
|
3
3
|
|
4
4
|
export default class CustomFieldsRenderer { // eslint-disable-line no-unused-vars
|
5
|
-
constructor(
|
6
|
-
this.
|
5
|
+
constructor(containerSelector) {
|
6
|
+
this.containerSelector = containerSelector || ".proposal_custom_field:last";
|
7
7
|
this.lang = this.getLang($("html").attr("lang"));
|
8
8
|
}
|
9
9
|
|
@@ -56,14 +56,21 @@ export default class CustomFieldsRenderer { // eslint-disable-line no-unused-var
|
|
56
56
|
*/
|
57
57
|
dataToXML(data) {
|
58
58
|
const $dl = $("<dl/>");
|
59
|
-
let $dd
|
59
|
+
let $dd = null,
|
60
|
+
$div = null,
|
61
|
+
$dt = null,
|
62
|
+
datum = null,
|
63
|
+
key = null,
|
64
|
+
label = null,
|
65
|
+
text = null,
|
66
|
+
val = null;
|
60
67
|
$dl.attr("class", "decidim_awesome-custom_fields");
|
61
68
|
$dl.attr("data-generator", "decidim_awesome");
|
62
69
|
$dl.attr("data-version", window.DecidimAwesome.version);
|
63
|
-
for (key in data) {
|
70
|
+
for (key in data) { // eslint-disable-line guard-for-in
|
64
71
|
// console.log("get the data!", key, data[key]);
|
65
72
|
// Richtext plugin does not saves userdata, so we get it from the hidden input
|
66
|
-
if (data[key].type
|
73
|
+
if (data[key].type === "textarea" && data[key].subtype === "richtext") {
|
67
74
|
data[key].userData = [$(`#${data[key].name}-input`).val()];
|
68
75
|
}
|
69
76
|
if (data[key].userData && data[key].userData.length) {
|
@@ -72,25 +79,25 @@ export default class CustomFieldsRenderer { // eslint-disable-line no-unused-var
|
|
72
79
|
$dt.attr("name", data[key].name);
|
73
80
|
$dd = $("<dd/>");
|
74
81
|
// console.log("data for", key, data[key].name, data[key])
|
75
|
-
for (val in data[key].userData) {
|
82
|
+
for (val in data[key].userData) { // eslint-disable-line guard-for-in
|
76
83
|
$div = $("<div/>");
|
77
84
|
label = data[key].userData[val];
|
78
85
|
text = null;
|
79
86
|
if (data[key].values) {
|
80
|
-
|
81
|
-
if (
|
87
|
+
datum = data[key].values.find((obj) => obj.value === label); // eslint-disable-line no-loop-func
|
88
|
+
if (datum) { // eslint-disable-line max-depth
|
82
89
|
text = label;
|
83
|
-
label =
|
90
|
+
label = datum.label;
|
84
91
|
}
|
85
|
-
} else if (data[key].type
|
86
|
-
|
87
|
-
if (
|
92
|
+
} else if (data[key].type === "date" && label) {
|
93
|
+
datum = new Date(label).toLocaleDateString();
|
94
|
+
if (datum) { // eslint-disable-line max-depth
|
88
95
|
text = label;
|
89
|
-
label =
|
96
|
+
label = datum;
|
90
97
|
}
|
91
98
|
}
|
92
99
|
// console.log("userData", text, "label", label, 'key', key, 'data', data)
|
93
|
-
if (data[key].type
|
100
|
+
if (data[key].type === "textarea" && data[key].subtype === "richtext") {
|
94
101
|
$div.html(label);
|
95
102
|
} else {
|
96
103
|
$div.text(label);
|
@@ -120,7 +127,7 @@ export default class CustomFieldsRenderer { // eslint-disable-line no-unused-var
|
|
120
127
|
*/
|
121
128
|
this.$container.find(".formbuilder-checkbox-group").each((_key, group) => {
|
122
129
|
const inputs = $(".formbuilder-checkbox input", group);
|
123
|
-
const data = this.spec.find((
|
130
|
+
const data = this.spec.find((obj) => obj.type === "checkbox-group");
|
124
131
|
let values = data.userData;
|
125
132
|
if (!inputs.length || !data || !values) {
|
126
133
|
return;
|
@@ -138,19 +145,19 @@ export default class CustomFieldsRenderer { // eslint-disable-line no-unused-var
|
|
138
145
|
});
|
139
146
|
|
140
147
|
// Fill "other" option
|
141
|
-
const
|
142
|
-
const
|
143
|
-
const
|
148
|
+
const otherOption = $(".other-option", inputs.parent())[0];
|
149
|
+
const otherVal = $(".other-val", inputs.parent())[0];
|
150
|
+
const otherText = values.join(" ");
|
144
151
|
|
145
|
-
if (
|
146
|
-
if (
|
147
|
-
|
148
|
-
|
149
|
-
|
152
|
+
if (otherOption) {
|
153
|
+
if (otherText) {
|
154
|
+
otherOption.checked = true;
|
155
|
+
otherOption.value = otherText;
|
156
|
+
otherVal.value = otherText;
|
150
157
|
} else {
|
151
|
-
|
152
|
-
|
153
|
-
|
158
|
+
otherOption.checked = false;
|
159
|
+
otherOption.value = "";
|
160
|
+
otherVal.value = "";
|
154
161
|
}
|
155
162
|
}
|
156
163
|
});
|
@@ -169,6 +176,7 @@ export default class CustomFieldsRenderer { // eslint-disable-line no-unused-var
|
|
169
176
|
}
|
170
177
|
});
|
171
178
|
});
|
179
|
+
return this;
|
172
180
|
}
|
173
181
|
|
174
182
|
// Saves xml to the hidden input
|
@@ -184,13 +192,14 @@ export default class CustomFieldsRenderer { // eslint-disable-line no-unused-var
|
|
184
192
|
this.$element.data("spec", this.spec);
|
185
193
|
}
|
186
194
|
// console.log("storeData spec", this.spec, "$body", $body,"$form",$form,"this",this);
|
195
|
+
return this;
|
187
196
|
}
|
188
197
|
|
189
198
|
init($element) {
|
190
199
|
this.$element = $element;
|
191
200
|
this.spec = $element.data("spec");
|
192
201
|
if (!this.$container) {
|
193
|
-
this.$container = $(this.
|
202
|
+
this.$container = $(this.containerSelector);
|
194
203
|
}
|
195
204
|
// console.log("init", $element, "this", this)
|
196
205
|
// always use the last field (in case of multilang tabs we only render one form due a limitation of the library to handle several instances)
|
@@ -24,7 +24,7 @@ window.fbControls.push(function(controlClass, allControlClasses) {
|
|
24
24
|
|
25
25
|
/**
|
26
26
|
* Class configuration - return the icons & label related to this control
|
27
|
-
* @
|
27
|
+
* @return {JSON} definition object
|
28
28
|
*/
|
29
29
|
static get definition() {
|
30
30
|
return {
|
@@ -37,6 +37,7 @@ window.fbControls.push(function(controlClass, allControlClasses) {
|
|
37
37
|
|
38
38
|
/**
|
39
39
|
* configure the richtext editor requirements
|
40
|
+
* @return {void}
|
40
41
|
*/
|
41
42
|
configure() {
|
42
43
|
window.fbEditors.richtext = {};
|
@@ -68,15 +69,16 @@ window.fbControls.push(function(controlClass, allControlClasses) {
|
|
68
69
|
`,
|
69
70
|
{ type: "text/css" }
|
70
71
|
);
|
71
|
-
const
|
72
|
-
// console.log("build value", value, "userData", userData, "attrs", attrs, attrs.id, "
|
73
|
-
this.wrapper = this.markup("div", null,
|
72
|
+
const wrapperAttrs = {...attrs, "data-toolbar": "full" };
|
73
|
+
// console.log("build value", value, "userData", userData, "attrs", attrs, attrs.id, "wrapperAttrs", wrapperAttrs);
|
74
|
+
this.wrapper = this.markup("div", null, wrapperAttrs);
|
74
75
|
return this.markup("div", [css, this.input, this.wrapper], attrs);
|
75
76
|
}
|
76
77
|
|
77
78
|
/**
|
78
79
|
* When the element is rendered into the DOM, execute the following code to initialise it
|
79
80
|
* @param {Object} evt - event
|
81
|
+
* @return {Object} evt - event
|
80
82
|
*/
|
81
83
|
onRender(evt) {
|
82
84
|
// const value = this.config.value || '';
|
@@ -5,18 +5,18 @@ window.DecidimAwesome.CustomFieldsRenderer = window.DecidimAwesome.CustomFieldsR
|
|
5
5
|
$(() => {
|
6
6
|
// use admin multilang specs if exists
|
7
7
|
let $el = $("proposal_custom_field:first", ".tabs-title.is-active");
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
if (!$el.length) {
|
9
|
+
$el = $(".proposal_custom_field:first");
|
10
|
+
}
|
11
11
|
window.DecidimAwesome.CustomFieldsRenderer.init($el);
|
12
12
|
|
13
|
-
window.DecidimAwesome.CustomFieldsRenderer.$container.closest("form").on("submit", (
|
14
|
-
if (
|
13
|
+
window.DecidimAwesome.CustomFieldsRenderer.$container.closest("form").on("submit", (evt) => {
|
14
|
+
if (evt.target.checkValidity()) {
|
15
15
|
// save current editor
|
16
16
|
window.DecidimAwesome.CustomFieldsRenderer.storeData();
|
17
17
|
} else {
|
18
|
-
|
19
|
-
|
18
|
+
evt.preventDefault();
|
19
|
+
evt.target.reportValidity();
|
20
20
|
}
|
21
21
|
});
|
22
22
|
});
|
@@ -3,7 +3,7 @@ $(() => {
|
|
3
3
|
|
4
4
|
const token = $('meta[name="csrf-token"]').attr("content");
|
5
5
|
const $textarea = $("textarea#proposal_body");
|
6
|
-
const
|
6
|
+
const text = window.DecidimAwesome.texts.drag_and_drop_image;
|
7
7
|
|
8
8
|
if (!$textarea.length) {
|
9
9
|
return;
|
@@ -12,7 +12,7 @@ $(() => {
|
|
12
12
|
if (window.DecidimAwesome.allow_images_in_proposals) {
|
13
13
|
// Add the capability to upload images only (they will be presented as links)
|
14
14
|
|
15
|
-
$textarea.after(`<p class="help-text">${
|
15
|
+
$textarea.after(`<p class="help-text">${text}</p>`);
|
16
16
|
$textarea.inlineattachment({
|
17
17
|
uploadUrl: window.DecidimAwesome.editor_uploader_path,
|
18
18
|
uploadFieldName: "image",
|
@@ -6,11 +6,14 @@
|
|
6
6
|
@import "stylesheets/decidim/decidim_awesome/editors/markdown_editor";
|
7
7
|
@import "stylesheets/decidim/decidim_awesome/editors/quill_editor";
|
8
8
|
|
9
|
-
.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
.pokecode-credits {
|
10
|
+
float: right;
|
11
|
+
margin: 0 1em .5em 0;
|
12
|
+
|
13
|
+
// position: absolute;
|
14
|
+
// bottom: 0;
|
15
|
+
// right: 0;
|
16
|
+
// margin: 1em;
|
14
17
|
font-size: .8em;
|
15
18
|
}
|
16
19
|
|