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.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/README.md +54 -45
  4. data/Rakefile +1 -1
  5. data/app/commands/decidim/decidim_awesome/admin/create_constraint.rb +1 -1
  6. data/app/commands/decidim/decidim_awesome/admin/create_custom_redirect.rb +1 -1
  7. data/app/commands/decidim/decidim_awesome/admin/create_menu_hack.rb +1 -1
  8. data/app/commands/decidim/decidim_awesome/admin/create_proposal_custom_field.rb +1 -1
  9. data/app/commands/decidim/decidim_awesome/admin/create_scoped_admin.rb +1 -1
  10. data/app/commands/decidim/decidim_awesome/admin/create_scoped_style.rb +1 -1
  11. data/app/commands/decidim/decidim_awesome/admin/destroy_constraint.rb +1 -1
  12. data/app/commands/decidim/decidim_awesome/admin/destroy_custom_redirect.rb +1 -1
  13. data/app/commands/decidim/decidim_awesome/admin/destroy_menu_hack.rb +1 -1
  14. data/app/commands/decidim/decidim_awesome/admin/destroy_proposal_custom_field.rb +1 -1
  15. data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_admin.rb +1 -1
  16. data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_style.rb +1 -1
  17. data/app/commands/decidim/decidim_awesome/admin/rename_scope_label.rb +1 -1
  18. data/app/commands/decidim/decidim_awesome/admin/update_config.rb +2 -3
  19. data/app/commands/decidim/decidim_awesome/admin/update_constraint.rb +2 -2
  20. data/app/commands/decidim/decidim_awesome/admin/update_custom_redirect.rb +1 -1
  21. data/app/commands/decidim/decidim_awesome/admin/update_menu_hack.rb +1 -1
  22. data/app/commands/decidim/decidim_awesome/command.rb +14 -0
  23. data/app/commands/decidim/decidim_awesome/create_editor_image.rb +1 -1
  24. data/app/controllers/concerns/decidim/decidim_awesome/admin_accountability/admin/filterable.rb +67 -0
  25. data/app/controllers/concerns/decidim/decidim_awesome/admin_accountability/admin/filterable_helper.rb +37 -0
  26. data/app/controllers/decidim/decidim_awesome/admin/admin_accountability_controller.rb +51 -0
  27. data/app/controllers/decidim/decidim_awesome/admin/checks_controller.rb +6 -3
  28. data/app/controllers/decidim/decidim_awesome/admin/config_controller.rb +2 -0
  29. data/app/controllers/decidim/decidim_awesome/admin/custom_redirects_controller.rb +2 -0
  30. data/app/controllers/decidim/decidim_awesome/admin/menu_hacks_controller.rb +2 -0
  31. data/app/controllers/decidim/decidim_awesome/editor_images_controller.rb +0 -2
  32. data/app/forms/decidim/decidim_awesome/admin/config_form.rb +14 -0
  33. data/app/forms/decidim/decidim_awesome/admin/menu_form.rb +1 -1
  34. data/app/forms/decidim/decidim_awesome/proposals/proposal_wizard_create_step_form_override.rb +26 -8
  35. data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +12 -8
  36. data/app/helpers/decidim/decidim_awesome/map_helper.rb +14 -11
  37. data/app/jobs/decidim/decidim_awesome/export_admin_actions_job.rb +28 -0
  38. data/app/middleware/decidim/decidim_awesome/current_config.rb +4 -0
  39. data/app/models/decidim/decidim_awesome/awesome_config.rb +0 -1
  40. data/app/models/decidim/decidim_awesome/config_constraint.rb +0 -2
  41. data/app/models/decidim/decidim_awesome/editor_image.rb +0 -3
  42. data/app/models/decidim/decidim_awesome/paper_trail_version.rb +99 -0
  43. data/app/packs/entrypoints/decidim_admin_decidim_awesome.js +3 -2
  44. data/app/packs/images/decidim/decidim_awesome/pokecode-logo.png +0 -0
  45. data/app/packs/src/decidim/decidim_awesome/admin/auto_edit.js +7 -7
  46. data/app/packs/src/decidim/decidim_awesome/admin/check_redirections.js +2 -2
  47. data/app/packs/src/decidim/decidim_awesome/admin/constraints.js +5 -5
  48. data/app/packs/src/decidim/decidim_awesome/admin/custom_fields_builder.js +11 -10
  49. data/app/packs/src/decidim/decidim_awesome/admin/form_exit_warn.js +1 -0
  50. data/app/packs/src/decidim/decidim_awesome/admin/user_picker.js +1 -0
  51. data/app/packs/src/decidim/decidim_awesome/awesome_map/api/fetcher.js +13 -13
  52. data/app/packs/src/decidim/decidim_awesome/awesome_map/awesome_map.js +14 -12
  53. data/app/packs/src/decidim/decidim_awesome/awesome_map/controllers/controller.js +16 -12
  54. data/app/packs/src/decidim/decidim_awesome/awesome_map/controllers/proposals_controller.js +3 -3
  55. data/app/packs/src/decidim/decidim_awesome/awesome_map/controls_ui.js +25 -26
  56. data/app/packs/src/decidim/decidim_awesome/awesome_map/load_map.js +1 -0
  57. data/app/packs/src/decidim/decidim_awesome/editors/editor.js +33 -12
  58. data/app/packs/src/decidim/decidim_awesome/forms/autosave.js +8 -12
  59. data/app/packs/src/decidim/decidim_awesome/forms/custom_fields_renderer.js +36 -27
  60. data/app/packs/src/decidim/decidim_awesome/forms/rich_text_plugin.js +6 -4
  61. data/app/packs/src/decidim/decidim_awesome/proposals/custom_fields.js +7 -7
  62. data/app/packs/src/decidim/decidim_awesome/proposals/images.js +2 -2
  63. data/app/packs/stylesheets/decidim/decidim_awesome/awesome_admin.scss +8 -5
  64. data/app/permissions/decidim/decidim_awesome/admin/permissions.rb +15 -1
  65. data/app/permissions/decidim/decidim_awesome/permissions.rb +4 -6
  66. data/app/presenters/decidim/decidim_awesome/paper_trail_base_presenter.rb +28 -0
  67. data/app/presenters/decidim/decidim_awesome/participatory_space_role_presenter.rb +45 -0
  68. data/app/presenters/decidim/decidim_awesome/role_base_presenter.rb +102 -0
  69. data/app/presenters/decidim/decidim_awesome/user_entity_presenter.rb +50 -0
  70. data/app/serializers/decidim/decidim_awesome/paper_trail_version_serializer.rb +37 -0
  71. data/app/validators/concerns/decidim/decidim_awesome/etiquette_validator_override.rb +41 -0
  72. data/app/views/decidim/decidim_awesome/admin/admin_accountability/index.html.erb +59 -0
  73. data/app/views/decidim/decidim_awesome/admin/checks/_assets_tester.html.erb +2 -0
  74. data/app/views/decidim/decidim_awesome/admin/config/_form_proposals.html.erb +82 -2
  75. data/app/views/decidim/decidim_awesome/admin/shared/_filters_with_date.html.erb +56 -0
  76. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +1 -1
  77. data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +9 -17
  78. data/app/views/layouts/decidim/admin/decidim_awesome.html.erb +1 -1
  79. data/app/views/{v0.25 → v0.27}/layouts/decidim/_head.html.erb +12 -4
  80. data/config/i18n-tasks.yml +4 -0
  81. data/config/locales/ca.yml +22 -2
  82. data/config/locales/cs.yml +7 -2
  83. data/config/locales/de.yml +20 -1
  84. data/config/locales/en.yml +90 -1
  85. data/config/locales/es.yml +2 -2
  86. data/config/locales/fr.yml +22 -2
  87. data/config/locales/it.yml +2 -2
  88. data/config/locales/ja.yml +3 -2
  89. data/config/locales/nl.yml +1 -1
  90. data/config/locales/pt-BR.yml +2 -2
  91. data/db/seeds.rb +1 -1
  92. data/lib/decidim/decidim_awesome/admin_engine.rb +15 -1
  93. data/lib/decidim/decidim_awesome/awesome.rb +55 -1
  94. data/lib/decidim/decidim_awesome/checksums.yml +13 -3
  95. data/lib/decidim/decidim_awesome/config.rb +14 -14
  96. data/lib/decidim/decidim_awesome/context_analyzers/request_analyzer.rb +1 -1
  97. data/lib/decidim/decidim_awesome/engine.rb +36 -9
  98. data/lib/decidim/decidim_awesome/iframe_component/component.rb +2 -1
  99. data/lib/decidim/decidim_awesome/menu_hacker.rb +6 -0
  100. data/lib/decidim/decidim_awesome/system_checker.rb +2 -0
  101. data/lib/decidim/decidim_awesome/test/factories.rb +7 -0
  102. data/lib/decidim/decidim_awesome/test/initializer.rb +10 -2
  103. data/lib/decidim/decidim_awesome/test/shared_examples/action_log_presenter_examples.rb +61 -0
  104. data/lib/decidim/decidim_awesome/test/shared_examples/scoped_admins_examples.rb +7 -4
  105. data/lib/decidim/decidim_awesome/test/shared_examples/summary_examples.rb +2 -2
  106. data/lib/decidim/decidim_awesome/version.rb +2 -2
  107. data/lib/tasks/decidim_awesome_active_storage_migrations_tasks.rake +1 -3
  108. data/package.json +21 -164
  109. metadata +39 -39
  110. data/app/packs/images/decidim/decidim_awesome/platoniq-logo.png +0 -0
  111. data/app/packs/src/vendor/image-resize.min.js +0 -1
  112. data/app/packs/src/vendor/image-upload.min.js +0 -6
  113. data/app/packs/src/vendor/leaflet.featuregroup.subgroup.js +0 -184
  114. /data/app/views/{v0.25 → v0.27}/decidim/proposals/collaborative_drafts/_show.html.erb +0 -0
  115. /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
- import "src/decidim/map/icon.js" // comes with Decidim
2
+ // comes with Decidim
3
+ import "src/decidim/map/icon.js"
3
4
  import "src/decidim/vendor/leaflet-tilelayer-here"
4
- import "leaflet.markercluster"; // Comes with Decidim
5
- import "leaflet.featuregroup.subgroup" // included in this package.json
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 == 0) {
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
- ? parseInt(category.id, 10)
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((c) => c.parent === cat.id);
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 == "proposals") {
111
+ if (component.type === "proposals") {
111
112
  controller = new ProposalsController(this, component);
112
113
  }
113
- if (component.type == "meetings" && this.config.menu.meetings) {
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 || !this.component.name
18
- ? window.DecidimAwesome.texts[this.component.type]
19
- : this.component.name;
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(collection.edges.map((item) => item.node.marker));
34
- } catch (e) {
35
- console.error("Failed marker collection assignation", collection);
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
- collection.edges.forEach((item) => {
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.awesomeMap.map.addLayer(this.controls.group);
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 (e) {
98
- console.error("Failed category marker assignation", marker, e.message);
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 (e) {
109
- console.error("Failed hashtags marker assignation", marker, e.message);
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 == amendment[0]);
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 (e) {
73
- console.error("error removeFrom marker", marker, "layer", this.controls.group, e);
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", (e) => {
37
- e.preventDefault();
38
- e.stopPropagation();
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", (e) => {
45
- e.preventDefault();
46
- e.stopPropagation();
47
- const tag = $(e.target).closest("label").data("layer");
48
- // console.log("changed, layer", tag, "checked", e.target.checked, e);
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", (e) => {
56
- e.preventDefault();
57
- e.stopPropagation();
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", (e) => {
84
- e.preventDefault();
85
- e.stopPropagation();
83
+ $("#awesome-map").on("change", ".awesome_map-categories-selector", (evt) => {
84
+ evt.preventDefault();
85
+ evt.stopPropagation();
86
86
 
87
- const id = $(e.target).closest("label").data("layer");
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", e.target.checked, e);
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 (e.target.checked) {
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 num_checked = $subcats.contents("input:checked").length;
204
- $input.prop("indeterminate", num_checked != $subcats.length && num_checked != 0);
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
  }
@@ -12,6 +12,7 @@ $(() => {
12
12
  }
13
13
  }
14
14
  }
15
+ return null;
15
16
  };
16
17
 
17
18
  const config = {
@@ -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
- // In 0.26 these files come with Decidim in the folder src/decidim/vendor so the awesome one's could be removed
18
- import "src/vendor/image-resize.min"
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, class_name) => (class_name.match(/(^|\s)ql-\S+/g) || []).join(" "));
31
- $(container).removeClass((index, class_name) => (class_name.match(/(^|\s)ql-\S+/g) || []).join(" "));
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: $(container).data("uploadImagesPath") || DecidimAwesome.editor_uploader_path,
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
- console.error(`Image upload error: ${serverError.message}`);
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 t = DecidimAwesome.texts.drag_and_drop_image;
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;">${t}</span>`);
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
- '[type="checkbox"]' // there are problems with matrix questions
36
+ // there are problems with matrix questions
37
+ '[type="checkbox"]'
37
38
  ]
38
39
  });
39
40
 
40
- const showMsg = (msg, error = false, default_time = 700) => {
41
- const time = error
42
- ? 5000
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 (e) {
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(container_selector) {
6
- this.container_selector = container_selector || ".proposal_custom_field:last";
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, $div, $dt, key, l, label, text, val;
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 == "textarea" && data[key].subtype == "richtext") {
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
- l = data[key].values.find((v) => v.value == label);
81
- if (l) {
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 = l.label;
90
+ label = datum.label;
84
91
  }
85
- } else if (data[key].type == "date" && label) {
86
- l = new Date(label).toLocaleDateString();
87
- if (l) {
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 = l;
96
+ label = datum;
90
97
  }
91
98
  }
92
99
  // console.log("userData", text, "label", label, 'key', key, 'data', data)
93
- if (data[key].type == "textarea" && data[key].subtype == "richtext") {
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((a) => a.type == "checkbox-group");
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 other_option = $(".other-option", inputs.parent())[0];
142
- const other_val = $(".other-val", inputs.parent())[0];
143
- const other_text = values.join(" ");
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 (other_option) {
146
- if (other_text) {
147
- other_option.checked = true;
148
- other_option.value = other_text;
149
- other_val.value = other_text;
152
+ if (otherOption) {
153
+ if (otherText) {
154
+ otherOption.checked = true;
155
+ otherOption.value = otherText;
156
+ otherVal.value = otherText;
150
157
  } else {
151
- other_option.checked = false;
152
- other_option.value = "";
153
- other_val.value = "";
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.container_selector);
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
- * @returndefinition object
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 wrapper_attrs = {...attrs, "data-toolbar": "full" };
72
- // console.log("build value", value, "userData", userData, "attrs", attrs, attrs.id, "wrapper_attrs", wrapper_attrs);
73
- this.wrapper = this.markup("div", null, wrapper_attrs);
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
- $el = $el.length
9
- ? $el
10
- : $(".proposal_custom_field:first");
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", (e) => {
14
- if (e.target.checkValidity()) {
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
- e.preventDefault();
19
- e.target.reportValidity();
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 t = window.DecidimAwesome.texts.drag_and_drop_image;
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">${t}</p>`);
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
- .platoniq-credits {
10
- position: absolute;
11
- bottom: 0;
12
- right: 0;
13
- margin: 1em;
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