decidim-decidim_awesome 0.7.0 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +32 -9
  3. data/app/assets/config/decidim_admin_decidim_awesome_manifest.css +2 -2
  4. data/app/assets/config/decidim_admin_decidim_awesome_manifest.js +1 -2
  5. data/app/assets/config/decidim_decidim_awesome_manifest.css +2 -2
  6. data/app/assets/config/decidim_decidim_awesome_manifest.js +3 -2
  7. data/app/assets/config/legacy_decidim_admin_decidim_awesome_manifest.js +2 -0
  8. data/app/assets/config/legacy_decidim_decidim_awesome_manifest.js +4 -0
  9. data/app/assets/javascripts/decidim/decidim_awesome/admin/auto_edit.js.es6 +77 -0
  10. data/app/assets/javascripts/decidim/decidim_awesome/admin/codemirror.js.es6 +2 -3
  11. data/app/assets/javascripts/decidim/decidim_awesome/admin/form_builder.js.es6 +80 -0
  12. data/app/assets/javascripts/decidim/decidim_awesome/admin/legacy_form_builder.js.es6 +80 -0
  13. data/app/assets/javascripts/decidim/decidim_awesome/admin/user_picker.js.es6 +24 -0
  14. data/app/assets/javascripts/decidim/decidim_awesome/awesome_admin.js +7 -0
  15. data/app/assets/javascripts/decidim/decidim_awesome/{application.js → awesome_application.js} +1 -2
  16. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/layers.js.es6 +3 -2
  17. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/load_map.js.es6 +15 -0
  18. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/map.js.es6 +52 -56
  19. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/meetings.js.es6 +2 -2
  20. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/proposals.js.es6 +1 -1
  21. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/utilities.js.es6 +33 -24
  22. data/app/assets/javascripts/decidim/decidim_awesome/editors/legacy_quill_editor.js.es6 +14 -2
  23. data/app/assets/javascripts/decidim/decidim_awesome/editors/quill_editor.js.es6 +18 -4
  24. data/app/assets/javascripts/decidim/decidim_awesome/editors/tabs_focus.js.es6 +24 -0
  25. data/app/assets/javascripts/decidim/decidim_awesome/forms/custom_fields_builder.js.es6 +211 -0
  26. data/app/assets/javascripts/decidim/decidim_awesome/forms/rich_text_plugin.js.es6 +106 -0
  27. data/app/assets/javascripts/decidim/decidim_awesome/legacy_admin.js +5 -1
  28. data/app/assets/javascripts/decidim/decidim_awesome/legacy_application.js +0 -1
  29. data/app/assets/javascripts/decidim/decidim_awesome/proposals/custom_fields.js.es6 +21 -0
  30. data/app/assets/stylesheets/decidim/decidim_awesome/admin/auto_edits.scss +15 -0
  31. data/app/assets/stylesheets/decidim/decidim_awesome/admin/codemirror.scss +15 -4
  32. data/app/assets/stylesheets/decidim/decidim_awesome/admin/constraints.scss +12 -0
  33. data/app/assets/stylesheets/decidim/decidim_awesome/admin/custom_fields.scss +66 -0
  34. data/app/assets/stylesheets/decidim/decidim_awesome/admin/user_picker.scss +35 -0
  35. data/app/assets/stylesheets/decidim/decidim_awesome/{admin.scss → awesome_admin.scss} +12 -0
  36. data/app/assets/stylesheets/decidim/decidim_awesome/awesome_application.scss +22 -0
  37. data/app/assets/stylesheets/decidim/decidim_awesome/awesome_map/map.scss +0 -1
  38. data/app/assets/stylesheets/decidim/decidim_awesome/editors/quill_editor.scss +16 -1
  39. data/app/awesome_overrides/forms/decidim/proposals/proposal_wizard_create_step_form_override.rb +28 -0
  40. data/app/cells/decidim/decidim_awesome/content_blocks/map/show.erb +74 -0
  41. data/app/cells/decidim/decidim_awesome/content_blocks/map_cell.rb +54 -0
  42. data/app/cells/decidim/decidim_awesome/content_blocks/map_form/show.erb +61 -0
  43. data/app/cells/decidim/decidim_awesome/content_blocks/map_form_cell.rb +19 -0
  44. data/app/commands/concerns/decidim/decidim_awesome/admin/needs_constraint_helpers.rb +32 -0
  45. data/app/commands/decidim/decidim_awesome/admin/create_proposal_custom_field.rb +45 -0
  46. data/app/commands/decidim/decidim_awesome/admin/create_scoped_admin.rb +38 -0
  47. data/app/commands/decidim/decidim_awesome/admin/destroy_constraint.rb +4 -0
  48. data/app/commands/decidim/decidim_awesome/admin/destroy_proposal_custom_field.rb +40 -0
  49. data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_admin.rb +40 -0
  50. data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_style.rb +1 -1
  51. data/app/commands/decidim/decidim_awesome/admin/rename_scope_label.rb +58 -0
  52. data/app/commands/decidim/decidim_awesome/admin/update_config.rb +1 -0
  53. data/app/controllers/concerns/decidim/decidim_awesome/admin_not_found_redirect.rb +39 -0
  54. data/app/controllers/decidim/decidim_awesome/admin/config_controller.rb +31 -18
  55. data/app/controllers/decidim/decidim_awesome/admin/constraints_controller.rb +4 -0
  56. data/app/controllers/decidim/decidim_awesome/admin/proposal_custom_fields_controller.rb +38 -0
  57. data/app/controllers/decidim/decidim_awesome/admin/scoped_admins_controller.rb +38 -0
  58. data/app/controllers/decidim/decidim_awesome/admin/scoped_styles_controller.rb +38 -0
  59. data/app/forms/decidim/decidim_awesome/admin/config_form.rb +39 -0
  60. data/app/forms/decidim/decidim_awesome/admin/constraint_form.rb +3 -1
  61. data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +11 -7
  62. data/app/helpers/decidim/decidim_awesome/amendments_helper_override.rb +48 -0
  63. data/app/helpers/decidim/decidim_awesome/map_helper.rb +67 -16
  64. data/app/helpers/decidim/decidim_awesome/proposals/application_helper_override.rb +78 -0
  65. data/app/middleware/decidim/decidim_awesome/current_config.rb +182 -0
  66. data/app/models/decidim/decidim_awesome/awesome_config.rb +15 -0
  67. data/app/models/decidim/decidim_awesome/user_override.rb +25 -0
  68. data/app/permissions/decidim/decidim_awesome/admin/permissions.rb +2 -0
  69. data/app/views/decidim/decidim_awesome/admin/checks/index.html.erb +1 -1
  70. data/app/views/decidim/decidim_awesome/admin/config/_autoedit_box_label.html.erb +7 -0
  71. data/app/views/decidim/decidim_awesome/admin/config/_constraints.html.erb +2 -2
  72. data/app/views/decidim/decidim_awesome/admin/config/_form_admins.html.erb +21 -0
  73. data/app/views/decidim/decidim_awesome/admin/config/_form_editors.html.erb +0 -3
  74. data/app/views/decidim/decidim_awesome/admin/config/_form_proposal_custom_fields.html.erb +25 -0
  75. data/app/views/decidim/decidim_awesome/admin/config/_form_proposals.html.erb +0 -2
  76. data/app/views/decidim/decidim_awesome/admin/config/_form_styles.html.erb +4 -7
  77. data/app/views/decidim/decidim_awesome/admin/proposals/_editor.html.erb +4 -0
  78. data/app/views/decidim/decidim_awesome/custom_fields/_form_render.html.erb +6 -0
  79. data/app/views/decidim/decidim_awesome/map_component/map/show.html.erb +0 -2
  80. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +101 -0
  81. data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +83 -0
  82. data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +1 -0
  83. data/app/views/layouts/decidim/admin/decidim_awesome.html.erb +25 -11
  84. data/app/views/layouts/decidim/decidim_awesome/_awesome_config.html.erb +4 -0
  85. data/app/views/layouts/decidim/decidim_awesome/_custom_styles.html.erb +1 -1
  86. data/app/views/v0.23/decidim/proposals/collaborative_drafts/_show.html.erb +134 -0
  87. data/app/views/v0.23/layouts/decidim/_head.html.erb +1 -1
  88. data/app/views/v0.23/layouts/decidim/admin/_header.html.erb +1 -1
  89. data/app/views/v0.24/decidim/proposals/collaborative_drafts/_show.html.erb +128 -0
  90. data/app/views/v0.24/layouts/decidim/_head.html.erb +2 -2
  91. data/app/views/v0.24/layouts/decidim/admin/_header.html.erb +2 -2
  92. data/config/locales/ca.yml +62 -3
  93. data/config/locales/cs.yml +62 -3
  94. data/config/locales/en.yml +90 -11
  95. data/config/locales/es.yml +61 -2
  96. data/config/locales/eu.yml +63 -4
  97. data/config/locales/fr.yml +62 -3
  98. data/config/locales/it.yml +284 -0
  99. data/config/locales/ja.yml +284 -0
  100. data/config/locales/nl.yml +62 -3
  101. data/config/locales/sv.yml +62 -3
  102. data/db/migrate/20210628150825_change_awesome_config_var_type.rb +12 -0
  103. data/lib/decidim/decidim_awesome/admin_engine.rb +16 -4
  104. data/lib/decidim/decidim_awesome/awesome_helpers.rb +17 -10
  105. data/lib/decidim/decidim_awesome/checksums.yml +17 -4
  106. data/lib/decidim/decidim_awesome/config.rb +53 -6
  107. data/lib/decidim/decidim_awesome/context_analyzers/request_analyzer.rb +27 -21
  108. data/lib/decidim/decidim_awesome/custom_fields.rb +94 -0
  109. data/lib/decidim/decidim_awesome/engine.rb +62 -6
  110. data/lib/decidim/decidim_awesome/test/shared_examples/box_label_editor.rb +116 -0
  111. data/lib/decidim/decidim_awesome/test/shared_examples/current_config_examples.rb +143 -0
  112. data/lib/decidim/decidim_awesome/test/shared_examples/editor_examples.rb +4 -0
  113. data/lib/decidim/decidim_awesome/test/shared_examples/scoped_admins_examples.rb +428 -0
  114. data/lib/decidim/decidim_awesome/version.rb +1 -1
  115. data/lib/decidim/decidim_awesome.rb +41 -8
  116. data/vendor/assets/javascripts/delta.min.js +405 -0
  117. data/vendor/assets/javascripts/delta.min.js.map +1 -0
  118. data/vendor/assets/javascripts/europa.min.js +4 -0
  119. data/vendor/assets/javascripts/form-builder.min.js +19 -0
  120. data/vendor/assets/javascripts/form-render.min.js +19 -0
  121. data/vendor/assets/javascripts/inscrybmde.min.js +1 -1
  122. data/vendor/assets/javascripts/jquery-ui.min.js +13 -0
  123. data/vendor/assets/javascripts/select2.js +6147 -0
  124. data/vendor/assets/langs/en-US.lang +110 -0
  125. data/vendor/assets/stylesheets/inscrybmde.min.scss +14 -0
  126. data/vendor/assets/stylesheets/jquery-ui.min.css +7 -0
  127. data/vendor/assets/stylesheets/select2-foundation-theme.css +249 -0
  128. data/vendor/assets/stylesheets/select2.css +515 -0
  129. metadata +68 -27
  130. data/app/assets/images/decidim/decidim_awesome/loading.gif +0 -0
  131. data/app/assets/javascripts/decidim/decidim_awesome/admin.js +0 -3
  132. data/app/assets/javascripts/decidim/decidim_awesome/editors/markdown_view.js.es6 +0 -12
  133. data/app/assets/stylesheets/decidim/decidim_awesome/application.scss +0 -8
  134. data/app/assets/stylesheets/decidim/decidim_awesome/editors/markdown_view.scss +0 -27
  135. data/app/awesome_overrides/presenters/decidim/proposals/proposal_presenter_override.rb +0 -58
  136. data/lib/decidim/decidim_awesome/content_renderers/markdown_renderer.rb +0 -18
  137. data/lib/decidim/decidim_awesome/content_renderers.rb +0 -9
@@ -10,8 +10,12 @@ module Decidim
10
10
  def awesome_config_instance
11
11
  return @awesome_config_instance if @awesome_config_instance
12
12
 
13
- @awesome_config_instance = Config.new request.env["decidim.current_organization"]
14
- @awesome_config_instance.context_from_request request
13
+ # if already created in the middleware, reuse it as it might have additional constraints
14
+ @awesome_config_instance = request.env["decidim_awesome.current_config"]
15
+ unless @awesome_config_instance.is_a? Config
16
+ @awesome_config_instance = Config.new request.env["decidim.current_organization"]
17
+ @awesome_config_instance.context_from_request request
18
+ end
15
19
  @awesome_config_instance
16
20
  end
17
21
 
@@ -20,7 +24,7 @@ module Decidim
20
24
  end
21
25
 
22
26
  def javascript_config_vars
23
- awesome_config.except(:scoped_styles).to_json.html_safe
27
+ awesome_config.except(:scoped_styles, :proposal_custom_fields, :scoped_admins).to_json.html_safe
24
28
  end
25
29
 
26
30
  def show_public_intergram?
@@ -51,14 +55,17 @@ module Decidim
51
55
 
52
56
  # Collects all CSS that is applied in the current URL context
53
57
  def awesome_custom_styles
54
- return unless awesome_config[:scoped_styles]
55
- return @awesome_custom_styles if @awesome_custom_styles
58
+ @awesome_custom_styles ||= awesome_config_instance.collect_sub_configs_values("scoped_style")
59
+ end
56
60
 
57
- styles = awesome_config[:scoped_styles]&.filter do |key, _value|
58
- config = AwesomeConfig.find_by(var: "scoped_style_#{key}", organization: current_organization)
59
- @awesome_config_instance.valid_in_context?(config&.constraints)
60
- end
61
- @awesome_custom_styles = styles.values.join("\n")
61
+ # Collects all proposal custom fields that is applied in the current URL context
62
+ def awesome_scoped_admins
63
+ @awesome_scoped_admins ||= awesome_config_instance.collect_sub_configs_values("scoped_admin")
64
+ end
65
+
66
+ # Collects all proposal custom fields that is applied in the current URL context
67
+ def awesome_proposal_custom_fields
68
+ @awesome_proposal_custom_fields ||= awesome_config_instance.collect_sub_configs_values("proposal_custom_field")
62
69
  end
63
70
 
64
71
  def version_prefix
@@ -13,8 +13,21 @@ decidim-core:
13
13
  decidim-0.24: 284c96f19cd98df091d8178d6db5a8b3
14
14
  /app/presenters/decidim/menu_item_presenter.rb:
15
15
  decidim-0.23: 70db39954b5840924530bf94d2a0a73a
16
+ /app/helpers/decidim/amendments_helper.rb:
17
+ decidim-0.23: 75bd41c3186729c7c84911bc7c7e9677
16
18
  decidim-proposals:
17
- /app/presenters/decidim/proposals/proposal_presenter.rb:
18
- decidim-0.23: 437c0c25151f605401a4f14d090ba5ea
19
- decidim-0.23.1: 892021b2ce9ac10c2e1b738e6948cde0
20
- decidim-0.24: 0b6717a3eeecad03277cea5ed6ba1fb7
19
+ /app/forms/decidim/proposals/proposal_wizard_create_step_form.rb:
20
+ decidim-0.23: b99c3223f1e75f2a69a89ae9a3d28182
21
+ decidim-0.23.1: 13ebf86ec88fa64d2651ab9735d5de90
22
+ decidim-0.24: db69edd0ba8ffa3965a5c44a6bfaba8d
23
+ /app/helpers/decidim/proposals/application_helper.rb:
24
+ decidim-0.23: d923323e3db542b84f42db3a4f782a8d
25
+ decidim-0.24: c5f99f5fa7de9a6e45776983330e9d73
26
+ /app/views/decidim/proposals/collaborative_drafts/show.html.erb:
27
+ decidim-0.23: b0fc5dfaf056c1a1dc667f8ded1a4b2e
28
+ decidim-0.24: 2a7e0a4c65361f238fd1b917f39c8642
29
+ /app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb:
30
+ decidim-0.23: b0fc5dfaf056c1a1dc667f8ded1a4b2e
31
+ decidim-0.24: 6f717555a20e2ab3f555003c337d3003
32
+ /app/views/decidim/proposals/admin/proposals/_form.html.erb:
33
+ decidim-0.23: 022eef3e8f57ccc2136ed1289b0f217d
@@ -9,13 +9,14 @@ module Decidim
9
9
  @vars = AwesomeConfig.for_organization(organization).includes(:constraints)
10
10
  @context = {
11
11
  participatory_space_manifest: nil,
12
- participatory_slug: nil,
12
+ participatory_space_slug: nil,
13
13
  component_id: nil,
14
14
  component_manifest: nil
15
15
  }
16
+ @sub_configs = {}
16
17
  end
17
18
 
18
- attr_reader :context
19
+ attr_reader :context, :organization, :vars
19
20
  attr_writer :defaults
20
21
 
21
22
  def defaults
@@ -84,14 +85,60 @@ module Decidim
84
85
  # if no constraints defined, applies to everything
85
86
  return true if constraints.blank?
86
87
 
88
+ # if containts the "none" constraints, deactivate everything else
89
+ return false if constraints.detect { |c| c.settings["participatory_space_manifest"] == "none" }
90
+
87
91
  # check if current context matches some constraint
88
92
  constraints.detect do |constraint|
89
- # if some setting is different, rejects
90
- invalid = constraint.settings.detect { |key, val| context[key.to_sym].to_s != val.to_s }
91
- invalid.blank?
93
+ settings = constraint.settings.symbolize_keys
94
+ match_method = settings.delete(:match)
95
+ if match_method == "exclusive"
96
+ # all keys must match
97
+ settings == context
98
+ else
99
+ # constraints keys can match the context partially (ie: if slug is not specified, any space matches in the same manifest)
100
+ # if some setting is different, rejects
101
+ invalid = constraint.settings.detect { |key, val| context[key.to_sym].to_s != val.to_s }
102
+ invalid.blank?
103
+ end
92
104
  end
93
105
  end
94
106
 
107
+ # adds some custom constraints for the instance that can be generated dynamically
108
+ def inject_sub_config_constraints(singular_key, subkey, constraints)
109
+ sub_configs_for(singular_key)[subkey.to_sym]&.add_constraints constraints
110
+ end
111
+
112
+ # Merges all subconfigs values for custom_styles or any other scoped confs
113
+ # by default filtered according to the current scope, a block can be passed for custom filtering
114
+ # ie, collect everything:
115
+ # collect_sub_configs_values("scoped_style") { true }
116
+ def collect_sub_configs_values(singular_key)
117
+ plural_key = singular_key.pluralize.to_sym
118
+
119
+ fields = config[plural_key]&.filter do |key, _value|
120
+ subconfig = sub_configs_for(singular_key)[key]
121
+ # allow custom filtering if block given
122
+ if block_given?
123
+ yield subconfig
124
+ else
125
+ valid_in_context?(subconfig&.all_constraints)
126
+ end
127
+ end
128
+ fields.values
129
+ end
130
+
131
+ def sub_configs_for(singular_key)
132
+ return @sub_configs[singular_key] if @sub_configs[singular_key]
133
+
134
+ plural_key = singular_key.pluralize.to_sym
135
+ return {} unless config[plural_key]
136
+
137
+ @sub_configs[singular_key] = config[plural_key].map do |key, _value|
138
+ [key, AwesomeConfig.find_by(var: "#{singular_key}_#{key}", organization: @organization)]
139
+ end.to_h
140
+ end
141
+
95
142
  private
96
143
 
97
144
  def map_defaults
@@ -107,7 +154,7 @@ module Decidim
107
154
 
108
155
  def calculate_config
109
156
  # filter vars compliant with current context
110
- valid = @vars.filter { |item| enabled_for_organization?(item.var) && valid_in_context?(item.constraints) }
157
+ valid = @vars.filter { |item| enabled_for_organization?(item.var) && valid_in_context?(item.all_constraints) }
111
158
  .map { |v| [v.var.to_sym, v.value] }.to_h
112
159
 
113
160
  map_defaults do |key|
@@ -5,17 +5,32 @@ module Decidim
5
5
  module ContextAnalyzers
6
6
  # Translates some Decidim URL path to detected participatory spaces and components
7
7
  class RequestAnalyzer
8
+ class << self
9
+ def context_for(request)
10
+ analyzer = new request
11
+ analyzer.extract_context!
12
+ analyzer.context
13
+ end
14
+
15
+ # In the frontend there's no a 100% correspondence between url and manifest name
16
+ def participatory_spaces_routes
17
+ spaces = Decidim.participatory_space_manifests \
18
+ .filter { |space| !DecidimAwesome.config.participatory_spaces_routes_context.has_key?(space.name) } \
19
+ .map { |space| [space.name.to_s, space.name.to_s] }.to_h
20
+ DecidimAwesome.config.participatory_spaces_routes_context.each do |manifest, routes|
21
+ routes.each do |route|
22
+ spaces[route.to_s] = manifest.to_s
23
+ end
24
+ end
25
+ spaces
26
+ end
27
+ end
28
+
8
29
  def initialize(request)
9
30
  @request = request
10
31
  @context = {}
11
32
  end
12
33
 
13
- def self.context_for(request)
14
- analyzer = new request
15
- analyzer.extract_context!
16
- analyzer.context
17
- end
18
-
19
34
  attr_reader :request, :context
20
35
 
21
36
  def extract_context!
@@ -25,20 +40,8 @@ module Decidim
25
40
 
26
41
  private
27
42
 
28
- # In the frontend there's no a 100% correspondence between url and manifest name
29
- def participatory_spaces
30
- spaces = Decidim.participatory_space_manifests.map do |space|
31
- [space.name.to_s, space.name.to_s]
32
- end.to_h
33
- spaces.merge(
34
- "processes" => "participatory_processes",
35
- "participatory_process_groups" => "participatory_processes",
36
- "assemblies_types" => "assemblies"
37
- )
38
- end
39
-
40
43
  def process_admin_segments(segments)
41
- spaces = participatory_spaces
44
+ spaces = RequestAnalyzer.participatory_spaces_routes
42
45
  return unless spaces[segments[0]]
43
46
 
44
47
  @context[:participatory_space_manifest] = spaces[segments[0]]
@@ -53,7 +56,7 @@ module Decidim
53
56
  end
54
57
 
55
58
  def process_front_segments(segments)
56
- spaces = participatory_spaces
59
+ spaces = RequestAnalyzer.participatory_spaces_routes
57
60
  return unless spaces[segments[0]]
58
61
 
59
62
  @context[:participatory_space_manifest] = spaces[segments[0]]
@@ -70,8 +73,11 @@ module Decidim
70
73
  def system_manifest?(path)
71
74
  patterns = [
72
75
  %r{^/admin/newsletters},
76
+ %r{^/admin/moderations},
77
+ %r{^/admin/users},
73
78
  %r{^/admin/organization},
74
- %r{^/admin/static_pages}
79
+ %r{^/admin/static_pages},
80
+ %r{^/admin/logs}
75
81
  ]
76
82
  path.match(Regexp.union(patterns))
77
83
  end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ class CustomFields
6
+ def initialize(fields)
7
+ @fields = if fields.respond_to? :map
8
+ fields.map { |f| JSON.parse(f) }.flatten
9
+ else
10
+ JSON.parse(fields)
11
+ end
12
+ end
13
+
14
+ attr_reader :fields, :xml, :errors, :data
15
+
16
+ def apply_xml(xml)
17
+ parse_xml(xml)
18
+ map_fields!
19
+ rescue StandardError => e
20
+ @errors = e.message
21
+ end
22
+
23
+ def to_json(*_args)
24
+ @fields
25
+ end
26
+
27
+ def translate!
28
+ translate_values!
29
+ end
30
+
31
+ private
32
+
33
+ def parse_xml(xml)
34
+ @xml = xml
35
+ @data = Nokogiri.XML(xml).xpath("//dl/dd")
36
+ return if @data.present?
37
+
38
+ apply_to_first_textarea
39
+ end
40
+
41
+ def map_fields!
42
+ return unless data
43
+
44
+ @fields.map! do |field|
45
+ if field["name"] # ignore headers/paragraphs
46
+ value = data.search("##{field["name"]} div")
47
+ field["userData"] = value.map { |v| v.attribute("alt")&.value || v.inner_html(encoding: "UTF-8") } if value.present?
48
+ end
49
+
50
+ field
51
+ end
52
+ end
53
+
54
+ # Finds the first textarea and applies non-xml compatible content
55
+ # when textarea has not wysiwyg assigned, strips html
56
+ def apply_to_first_textarea
57
+ # quill editor might leave html traces without any user content
58
+ # so we won't process it if there is no text (html free) result
59
+ text = Nokogiri.HTML(xml).html? ? Nokogiri.HTML(xml).text.strip : text.strip
60
+ return if text.blank?
61
+
62
+ textarea = @fields.find { |field| field["type"] == "textarea" }
63
+ @errors = I18n.t(".invalid_xml", scope: "decidim.decidim_awesome.custom_fields.errors")
64
+ return unless textarea
65
+
66
+ textarea["userData"] = [textarea["subtype"] == "textarea" ? text : xml]
67
+ @errors = I18n.t(".invalid_fields", scope: "decidim.decidim_awesome.custom_fields.errors", field: textarea["label"] || textarea["name"])
68
+ end
69
+
70
+ def translate_values!
71
+ deep_transform_values!(@fields) do |value|
72
+ next value unless value.is_a? String
73
+ next value unless (match = value.match(/^(.*\..*)$/))
74
+
75
+ I18n.t(match[1], raise: true)
76
+ rescue I18n::MissingTranslationData
77
+ value
78
+ end
79
+ @fields
80
+ end
81
+
82
+ def deep_transform_values!(object, &block)
83
+ case object
84
+ when Hash
85
+ object.transform_values! { |value| deep_transform_values!(value, &block) }
86
+ when Array
87
+ object.map! { |e| deep_transform_values!(e, &block) }
88
+ else
89
+ yield(object)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -8,30 +8,86 @@ module Decidim
8
8
  module DecidimAwesome
9
9
  # This is the engine that runs on the public interface of decidim_awesome.
10
10
  class Engine < ::Rails::Engine
11
+ include AwesomeHelpers
12
+
11
13
  isolate_namespace Decidim::DecidimAwesome
12
14
 
13
15
  routes do
14
16
  post :editor_images, to: "editor_images#create"
15
17
  end
16
18
 
19
+ initializer "decidim.middleware" do |app|
20
+ app.config.middleware.insert_after Decidim::CurrentOrganization, Decidim::DecidimAwesome::CurrentConfig
21
+ end
22
+
23
+ # Prepare a zone to create overrides
24
+ # https://edgeguides.rubyonrails.org/engines.html#overriding-models-and-controllers
25
+ # overrides
26
+ config.to_prepare do
27
+ if DecidimAwesome.config[:scoped_admins] != :disabled
28
+ # override user's admin property
29
+ Decidim::User.include(UserOverride)
30
+ # redirect unauthorized scoped admins to allowed places
31
+ Decidim::ErrorsController.include(AdminNotFoundRedirect)
32
+ end
33
+
34
+ Decidim::Proposals::ApplicationHelper.include(Decidim::DecidimAwesome::Proposals::ApplicationHelperOverride)
35
+ Decidim::AmendmentsHelper.include(Decidim::DecidimAwesome::AmendmentsHelperOverride)
36
+
37
+ # TODO: move to include overrides
38
+ Dir.glob("#{Engine.root}/app/awesome_overrides/**/*_override.rb").each do |override|
39
+ require_dependency override
40
+ end
41
+ end
42
+
17
43
  initializer "decidim_awesome.view_helpers" do
18
44
  ActionView::Base.include AwesomeHelpers
19
45
  end
20
46
 
21
47
  initializer "decidim_decidim_awesome.assets" do |app|
22
- app.config.assets.precompile += %w(decidim_decidim_awesome_manifest.js decidim_decidim_awesome_manifest.css)
48
+ app.config.assets.precompile += if version_prefix == "v0.23"
49
+ %w(legacy_decidim_decidim_awesome_manifest.js decidim_decidim_awesome_manifest.css)
50
+ else
51
+ %w(decidim_decidim_awesome_manifest.js decidim_decidim_awesome_manifest.css)
52
+ end
23
53
  # add to precompile any present theme asset
24
54
  Dir.glob(Rails.root.join("app/assets/themes/*.*")).each do |path|
25
55
  app.config.assets.precompile << path
26
56
  end
27
57
  end
28
58
 
29
- # Prepare a zone to create overrides
30
- # https://edgeguides.rubyonrails.org/engines.html#overriding-models-and-controllers
31
- config.to_prepare do
32
- Dir.glob("#{Engine.root}/app/awesome_overrides/**/*_override.rb").each do |override|
33
- require_dependency override
59
+ initializer "decidim_decidim_awesome.add_cells_view_paths" do
60
+ Cell::ViewModel.view_paths << File.expand_path("#{Decidim::DecidimAwesome::Engine.root}/app/cells")
61
+ Cell::ViewModel.view_paths << File.expand_path("#{Decidim::DecidimAwesome::Engine.root}/app/views")
62
+ end
63
+
64
+ initializer "decidim_decidim_awesome.content_blocks" do |_app|
65
+ # === Home Map block ===
66
+ Decidim.content_blocks.register(:homepage, :awesome_map) do |content_block|
67
+ content_block.cell = "decidim/decidim_awesome/content_blocks/map"
68
+ content_block.settings_form_cell = "decidim/decidim_awesome/content_blocks/map_form"
69
+ content_block.public_name_key = "decidim.decidim_awesome.content_blocks.map.name"
70
+
71
+ content_block.settings do |settings|
72
+ settings.attribute :title, type: :text, translated: true
73
+
74
+ settings.attribute :map_height, type: :integer, default: 500
75
+ settings.attribute :map_center, type: :string, default: ""
76
+ settings.attribute :map_zoom, type: :integer, default: 8
77
+ settings.attribute :truncate, type: :integer, default: 255
78
+ settings.attribute :collapse, type: :boolean, default: false
79
+ settings.attribute :menu_amendments, type: :boolean, default: true
80
+ settings.attribute :menu_meetings, type: :boolean, default: true
81
+ settings.attribute :menu_hashtags, type: :boolean, default: true
82
+
83
+ settings.attribute :show_not_answered, type: :boolean, default: true
84
+ settings.attribute :show_accepted, type: :boolean, default: true
85
+ settings.attribute :show_withdrawn, type: :boolean, default: false
86
+ settings.attribute :show_evaluating, type: :boolean, default: true
87
+ settings.attribute :show_rejected, type: :boolean, default: false
88
+ end
34
89
  end
90
+ # === TODO: processes groups map block ===
35
91
  end
36
92
  end
37
93
  end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples "edits box label inline" do |test_case, key|
4
+ let(:data) { '[{"type":"text","label":"Short Name","subtype":"text","className":"form-control","name":"text-1476748004559"}]' }
5
+
6
+ it "updates the label when no changes" do
7
+ link = find("[data-key=#{key}] a.awesome-auto-edit", match: :first)
8
+ expect(page).not_to have_css("input.awesome-auto-edit")
9
+ link.click
10
+ expect(page).to have_css("input.awesome-auto-edit")
11
+ find("body").click
12
+ expect(page).not_to have_css("input.awesome-auto-edit")
13
+ link.click
14
+ input = find("[data-key=#{key}] input.awesome-auto-edit")
15
+ input.fill_in with: "A new làbel\n"
16
+ sleep 1
17
+ expect(page).not_to have_css("input.awesome-auto-edit")
18
+ expect(page).to have_css("span.awesome-auto-edit[data-key=a_new_label]")
19
+
20
+ find("*[type=submit]").click
21
+ case test_case
22
+ when :css
23
+ expect(page).to have_content("body {background: red;}")
24
+ when :fields
25
+ expect(page).to have_content("Occupation")
26
+ expect(page).to have_content("Street Sweeper")
27
+ expect(page).not_to have_content("Short Bio")
28
+ when :admins
29
+ expect(page).not_to have_content(user.name.to_s)
30
+ expect(page).to have_content(user2.name.to_s)
31
+ expect(page).to have_content(user3.name.to_s)
32
+ end
33
+ expect(page).to have_css("span.awesome-auto-edit[data-key=a_new_label]")
34
+ expect(page).not_to have_css("span.awesome-auto-edit[data-key=#{key}]")
35
+ end
36
+
37
+ it "updates the label with previous changes" do
38
+ case test_case
39
+ when :css
40
+ sleep 1
41
+ page.execute_script("document.querySelector(\"[data-key=#{key}] .CodeMirror\").CodeMirror.setValue(\"div {background: brown;}\");")
42
+ when :fields
43
+ sleep 2
44
+ page.execute_script("$('.proposal_custom_fields_container[data-key=#{key}] .proposal_custom_fields_editor')[0].FormBuilder.actions.setData(#{data})")
45
+ when :admins
46
+ sleep 1
47
+ page.execute_script("$('.multiusers-select:first').append(new Option('#{user.name}', #{user.id}, true, true)).trigger('change');")
48
+ end
49
+
50
+ link = find("[data-key=#{key}] a.awesome-auto-edit", match: :first)
51
+ expect(page).not_to have_css("input.awesome-auto-edit")
52
+ link.click
53
+ expect(page).to have_css("input.awesome-auto-edit")
54
+ find("body").click
55
+ expect(page).not_to have_css("input.awesome-auto-edit")
56
+ link.click
57
+ input = find("[data-key=#{key}] input.awesome-auto-edit")
58
+ input.fill_in with: "A new làbel\n"
59
+ sleep 1
60
+ expect(page).not_to have_css("input.awesome-auto-edit")
61
+ expect(page).to have_css("span.awesome-auto-edit[data-key=a_new_label]")
62
+
63
+ find("*[type=submit]").click
64
+ case test_case
65
+ when :css
66
+ expect(page).to have_admin_callout("updated successfully")
67
+ expect(page).to have_content("div {background: brown;}")
68
+ when :fields
69
+ expect(page).to have_content("Short Name")
70
+ when :admins
71
+ expect(page).to have_content(user.name.to_s)
72
+ expect(page).to have_content(user2.name.to_s)
73
+ expect(page).to have_content(user3.name.to_s)
74
+ end
75
+ expect(page).to have_css("span.awesome-auto-edit[data-key=a_new_label]")
76
+ expect(page).not_to have_css("span.awesome-auto-edit[data-key=#{key}]")
77
+ end
78
+
79
+ it "updates the label with post changes" do
80
+ link = find("[data-key=#{key}] a.awesome-auto-edit", match: :first)
81
+ expect(page).not_to have_css("input.awesome-auto-edit")
82
+ link.click
83
+ expect(page).to have_css("input.awesome-auto-edit")
84
+ find("body").click
85
+ expect(page).not_to have_css("input.awesome-auto-edit")
86
+ link.click
87
+ input = find("[data-key=#{key}] input.awesome-auto-edit")
88
+ input.fill_in with: "A new làbel\n"
89
+ sleep 1
90
+ expect(page).not_to have_css("input.awesome-auto-edit")
91
+ expect(page).to have_css("span.awesome-auto-edit[data-key=a_new_label]")
92
+
93
+ case test_case
94
+ when :css
95
+ sleep 1
96
+ page.execute_script('document.querySelector("[data-key=a_new_label] .CodeMirror").CodeMirror.setValue("body {background: lilac;}");')
97
+ find("*[type=submit]").click
98
+ expect(page).to have_admin_callout("updated successfully")
99
+ expect(page).to have_content("body {background: lilac;}")
100
+ when :fields
101
+ expect(page).to have_content("Full Name")
102
+ sleep 2
103
+ page.execute_script("$('.proposal_custom_fields_container[data-key=a_new_label] .proposal_custom_fields_editor')[0].FormBuilder.actions.setData(#{data})")
104
+ find("*[type=submit]").click
105
+ expect(page).to have_content("Short Name")
106
+ when :admins
107
+ page.execute_script("$('.multiusers-select:first').append(new Option('#{user.name}', #{user.id}, true, true)).trigger('change');")
108
+ find("*[type=submit]").click
109
+ expect(page).to have_content(user.name.to_s)
110
+ expect(page).to have_content(user2.name.to_s)
111
+ expect(page).to have_content(user3.name.to_s)
112
+ end
113
+ expect(page).to have_css("span.awesome-auto-edit[data-key=a_new_label]")
114
+ expect(page).not_to have_css("span.awesome-auto-edit[data-key=#{key}]")
115
+ end
116
+ end