decidim-decidim_awesome 0.6.0 → 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -14
  3. data/app/assets/config/decidim_admin_decidim_awesome_manifest.js +1 -0
  4. data/app/assets/javascripts/decidim/decidim_awesome/admin/form_exit_warn.js.es6 +30 -0
  5. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/legacy_map.js.es6 +14 -4
  6. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/legacy_proposals.js.es6 +82 -0
  7. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/map.js.es6 +13 -2
  8. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/meetings.js.es6 +15 -13
  9. data/app/assets/javascripts/decidim/decidim_awesome/awesome_map/proposals.js.es6 +29 -13
  10. data/app/assets/javascripts/decidim/decidim_awesome/editors/quill_editor.js.es6 +1 -1
  11. data/app/assets/stylesheets/decidim/decidim_awesome/admin.scss +4 -0
  12. data/app/awesome_overrides/presenters/decidim/menu_presenter_override.rb +31 -0
  13. data/app/awesome_overrides/presenters/decidim/proposals/proposal_presenter_override.rb +31 -5
  14. data/app/commands/decidim/decidim_awesome/admin/create_menu_hack.rb +51 -0
  15. data/app/commands/decidim/decidim_awesome/admin/create_scoped_style.rb +34 -0
  16. data/app/commands/decidim/decidim_awesome/admin/destroy_menu_hack.rb +47 -0
  17. data/app/commands/decidim/decidim_awesome/admin/destroy_scoped_style.rb +40 -0
  18. data/app/commands/decidim/decidim_awesome/admin/update_config.rb +1 -1
  19. data/app/commands/decidim/decidim_awesome/admin/update_menu_hack.rb +47 -0
  20. data/app/commands/decidim/decidim_awesome/create_editor_image.rb +5 -3
  21. data/app/controllers/decidim/decidim_awesome/admin/application_controller.rb +4 -3
  22. data/app/controllers/decidim/decidim_awesome/admin/config_controller.rb +38 -2
  23. data/app/controllers/decidim/decidim_awesome/admin/constraints_controller.rb +13 -0
  24. data/app/controllers/decidim/decidim_awesome/admin/menu_hacks_controller.rb +116 -0
  25. data/app/controllers/decidim/decidim_awesome/editor_images_controller.rb +1 -1
  26. data/app/forms/decidim/decidim_awesome/admin/config_form.rb +11 -2
  27. data/app/forms/decidim/decidim_awesome/admin/constraint_form.rb +0 -2
  28. data/app/forms/decidim/decidim_awesome/admin/intergram_form.rb +0 -2
  29. data/app/forms/decidim/decidim_awesome/admin/menu_form.rb +39 -0
  30. data/app/forms/decidim/decidim_awesome/editor_image_form.rb +2 -0
  31. data/app/helpers/decidim/decidim_awesome/admin/config_constraints_helpers.rb +5 -1
  32. data/app/helpers/decidim/decidim_awesome/map_helper.rb +11 -1
  33. data/app/models/decidim/decidim_awesome/editor_image.rb +4 -3
  34. data/app/permissions/decidim/decidim_awesome/admin/permissions.rb +19 -0
  35. data/app/permissions/decidim/decidim_awesome/permissions.rb +2 -0
  36. data/app/uploaders/decidim/decidim_awesome/image_uploader.rb +9 -0
  37. data/app/views/decidim/decidim_awesome/admin/config/_form_styles.html.erb +27 -0
  38. data/app/views/decidim/decidim_awesome/admin/config/show.html.erb +1 -1
  39. data/app/views/decidim/decidim_awesome/admin/menu_hacks/_form.html.erb +7 -0
  40. data/app/views/decidim/decidim_awesome/admin/menu_hacks/edit.html.erb +13 -0
  41. data/app/views/decidim/decidim_awesome/admin/menu_hacks/index.html.erb +44 -0
  42. data/app/views/decidim/decidim_awesome/admin/menu_hacks/new.html.erb +13 -0
  43. data/app/views/decidim/decidim_awesome/iframe_component/iframe/show.html.erb +6 -1
  44. data/app/views/decidim/decidim_awesome/map_component/map/show.html.erb +40 -18
  45. data/app/views/layouts/decidim/admin/decidim_awesome.html.erb +10 -0
  46. data/app/views/layouts/decidim/decidim_awesome/_awesome_config.html.erb +1 -1
  47. data/app/views/layouts/decidim/decidim_awesome/_custom_styles.html.erb +3 -0
  48. data/app/views/v0.22/layouts/decidim/_head.html.erb +1 -0
  49. data/app/views/v0.23/layouts/decidim/_head.html.erb +1 -0
  50. data/config/locales/ca.yml +96 -9
  51. data/config/locales/cs.yml +91 -4
  52. data/config/locales/en.yml +70 -4
  53. data/config/locales/es.yml +125 -38
  54. data/config/locales/eu.yml +212 -0
  55. data/config/locales/fr.yml +90 -3
  56. data/config/locales/nl.yml +212 -0
  57. data/config/locales/sv.yml +90 -3
  58. data/lib/decidim/decidim_awesome.rb +27 -0
  59. data/lib/decidim/decidim_awesome/admin_engine.rb +3 -0
  60. data/lib/decidim/decidim_awesome/awesome_helpers.rb +16 -0
  61. data/lib/decidim/decidim_awesome/checksums.yml +8 -0
  62. data/lib/decidim/decidim_awesome/config.rb +13 -12
  63. data/lib/decidim/decidim_awesome/engine.rb +1 -1
  64. data/lib/decidim/decidim_awesome/iframe_component/component.rb +3 -3
  65. data/lib/decidim/decidim_awesome/map_component/component.rb +6 -0
  66. data/lib/decidim/decidim_awesome/menu_hacker.rb +88 -0
  67. data/lib/decidim/decidim_awesome/test/factories.rb +1 -1
  68. data/lib/decidim/decidim_awesome/test/shared_examples/config_examples.rb +4 -2
  69. data/lib/decidim/decidim_awesome/test/shared_examples/editor_examples.rb +71 -0
  70. data/lib/decidim/decidim_awesome/test/shared_examples/menu_hack_contexts.rb +71 -0
  71. data/lib/decidim/decidim_awesome/version.rb +1 -2
  72. data/vendor/assets/javascripts/jsrender.min.js +4 -0
  73. metadata +26 -3
@@ -18,6 +18,7 @@ module Decidim
18
18
  autoload :SystemChecker, "decidim/decidim_awesome/system_checker"
19
19
  autoload :ContentRenderes, "decidim/decidim_awesome/content_renderers"
20
20
  autoload :ContextAnalyzers, "decidim/decidim_awesome/context_analyzers"
21
+ autoload :MenuHacker, "decidim/decidim_awesome/menu_hacker"
21
22
 
22
23
  # Boolean configuration options
23
24
  #
@@ -59,6 +60,32 @@ module Decidim
59
60
  false
60
61
  end
61
62
 
63
+ # allows admins to created specific CSS snippets affecting only some specific parts
64
+ # Valid values differ a little from the previous convention:
65
+ # :disabled => false and non available, hidden from admins
66
+ # Hash => hash of different css text, each key will be used for the contraints
67
+ # Admins create this hash dynamically but some pre-defined css boxes can be created here as:
68
+ # {
69
+ # some_identifier: ".wrapper { background: red; }"
70
+ # }
71
+ config_accessor :scoped_styles do
72
+ {}
73
+ end
74
+
75
+ # allows to keep modifications for the main menu
76
+ # can return :disabled to completly remove this feature
77
+ # otherwise it should be an array (some overrides can be specified by default):
78
+ # [
79
+ # {
80
+ # url: "/a-new-link",
81
+ # label: { "en" => "The label to show in the menu" },
82
+ # position: 10
83
+ # }
84
+ # ]
85
+ config_accessor :menu do
86
+ []
87
+ end
88
+
62
89
  # these settings do not follow the :disabled convention but
63
90
  # depends on the previous intergram configurations
64
91
  config_accessor :intergram_url do
@@ -12,7 +12,10 @@ module Decidim
12
12
  routes do
13
13
  # Add admin engine routes here
14
14
  resources :constraints
15
+ resources :menu_hacks, except: [:show]
15
16
  resources :config, param: :var, only: [:show, :update]
17
+ post :new_scoped_style, to: "config#new_scoped_style"
18
+ post :destroy_scoped_style, param: :key, to: "config#destroy_scoped_style"
16
19
  get :checks, to: "checks#index"
17
20
  root to: "config#show", var: :editors
18
21
  end
@@ -19,6 +19,10 @@ module Decidim
19
19
  @awesome_config ||= awesome_config_instance.config
20
20
  end
21
21
 
22
+ def javascript_config_vars
23
+ awesome_config.except(:scoped_styles).to_json.html_safe
24
+ end
25
+
22
26
  def show_public_intergram?
23
27
  return unless awesome_config[:intergram_for_public]
24
28
  return true unless awesome_config[:intergram_for_public_settings][:require_login]
@@ -45,6 +49,18 @@ module Decidim
45
49
  return @tenant_stylesheets = current_organization.host.to_s if File.exist?("#{prefix}.css") || File.exist?("#{prefix}.scss") || File.exist?("#{prefix}.scss.erb")
46
50
  end
47
51
 
52
+ # Collects all CSS that is applied in the current URL context
53
+ def awesome_custom_styles
54
+ return unless awesome_config[:scoped_styles]
55
+ return @awesome_custom_styles if @awesome_custom_styles
56
+
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")
62
+ end
63
+
48
64
  def version_prefix
49
65
  "v#{Decidim.version[0..3]}"
50
66
  end
@@ -9,7 +9,15 @@ decidim-core:
9
9
  /app/assets/javascripts/decidim/editor.js.es6:
10
10
  decidim-0.22: 797d0ec1c9e79453cf6718f82d2fdd27
11
11
  decidim-0.23: cb059b8ff0ffc62c67eb99d8d7a6637b
12
+ decidim-0.23.1: 4787f73f0f33661e3897404f10019d26
13
+ /app/presenters/decidim/menu_presenter.rb:
14
+ decidim-0.22: 042743c44a2aff284b493c7bebbccbb3
15
+ decidim-0.23: 042743c44a2aff284b493c7bebbccbb3
16
+ /app/presenters/decidim/menu_item_presenter.rb:
17
+ decidim-0.22: 70db39954b5840924530bf94d2a0a73a
18
+ decidim-0.23: 70db39954b5840924530bf94d2a0a73a
12
19
  decidim-proposals:
13
20
  /app/presenters/decidim/proposals/proposal_presenter.rb:
14
21
  decidim-0.22: 7d60c8310d7fa4e38d9a27080c22b12c
15
22
  decidim-0.23: 437c0c25151f605401a4f14d090ba5ea
23
+ decidim-0.23.1: 892021b2ce9ac10c2e1b738e6948cde0
@@ -79,6 +79,19 @@ module Decidim
79
79
  config[setting]
80
80
  end
81
81
 
82
+ # checks if some constraint blocks the validity fot the current context
83
+ def valid_in_context?(constraints)
84
+ # if no constraints defined, applies to everything
85
+ return true if constraints.blank?
86
+
87
+ # check if current context matches some constraint
88
+ 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?
92
+ end
93
+ end
94
+
82
95
  private
83
96
 
84
97
  def map_defaults
@@ -112,18 +125,6 @@ module Decidim
112
125
  end
113
126
  true
114
127
  end
115
-
116
- def valid_in_context?(constraints)
117
- # if no constraints defined, applies to everything
118
- return true if constraints.blank?
119
-
120
- # check if current context matches some constraint
121
- constraints.detect do |constraint|
122
- # if some setting is different, rejects
123
- invalid = constraint.settings.detect { |key, val| context[key.to_sym] != val }
124
- invalid.blank?
125
- end
126
- end
127
128
  end
128
129
  end
129
130
  end
@@ -20,7 +20,7 @@ module Decidim
20
20
 
21
21
  initializer "decidim_decidim_awesome.assets" do |app|
22
22
  app.config.assets.precompile += %w(decidim_decidim_awesome_manifest.js decidim_decidim_awesome_manifest.css)
23
- # add to precompile any present
23
+ # add to precompile any present theme asset
24
24
  Dir.glob(Rails.root.join("app", "assets", "themes", "*.*")).each do |path|
25
25
  app.config.assets.precompile << path
26
26
  end
@@ -14,7 +14,7 @@ Decidim.register_component(:awesome_iframe) do |component|
14
14
  component.settings(:global) do |settings|
15
15
  # Add your global settings
16
16
  # Available types: :integer, :boolean
17
- # settings.attribute :announcement, type: :text, translated: true, editor: true
17
+ settings.attribute :announcement, type: :text, translated: true, editor: true
18
18
  settings.attribute :iframe, type: :text
19
19
  settings.attribute :viewport_width, type: :boolean, default: false
20
20
  settings.attribute :no_margins, type: :boolean, default: false
@@ -22,7 +22,7 @@ Decidim.register_component(:awesome_iframe) do |component|
22
22
 
23
23
  component.settings(:step) do |settings|
24
24
  # Add your settings per step
25
- # settings.attribute :announcement, type: :text, translated: true, editor: true
25
+ settings.attribute :announcement, type: :text, translated: true, editor: true
26
26
  settings.attribute :iframe, type: :text
27
27
  end
28
28
 
@@ -31,7 +31,7 @@ Decidim.register_component(:awesome_iframe) do |component|
31
31
  # end
32
32
 
33
33
  component.seeds do |participatory_space|
34
- # Create a Iframe and a few geolocated proposals
34
+ # Create a Iframe component in all participatory spaces
35
35
  admin_user = Decidim::User.find_by(
36
36
  organization: participatory_space.organization,
37
37
  email: "admin@example.org"
@@ -22,6 +22,12 @@ Decidim.register_component(:awesome_map) do |component|
22
22
  component.settings(:step) do |settings|
23
23
  # Add your settings per step
24
24
  settings.attribute :announcement, type: :text, translated: true, editor: true
25
+ settings.attribute :show_not_answered, type: :boolean, default: true
26
+ settings.attribute :show_evaluating, type: :boolean, default: true
27
+ settings.attribute :show_accepted, type: :boolean, default: true
28
+ # Not possible yet (needs graphql update):
29
+ # settings.attribute :show_rejected, type: :boolean, default: false
30
+ settings.attribute :show_withdrawn, type: :boolean, default: false
25
31
  end
26
32
 
27
33
  # component.register_stat :some_stat do |context, start_at, end_at|
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DecidimAwesome
5
+ class MenuHacker
6
+ include Decidim::TranslatableAttributes
7
+ def initialize(name, view)
8
+ @name = name
9
+ @organization = view.try(:current_organization)
10
+ @user = view.try(:current_user)
11
+ @view = view
12
+ end
13
+
14
+ # returns a combined array of the Decidim defined menu and the hacked stored as config vars
15
+ def items(include_invisible = false)
16
+ return @items if @items
17
+
18
+ @items = default_items
19
+ menu_overrides.each do |item|
20
+ default = default_items.find { |i| i.url.gsub(/\?.*/, "") == item.url }
21
+ if default
22
+ item.send("overrided?=", true)
23
+ @items.reject! { |i| i.url.gsub(/\?.*/, "") == item.url }
24
+ end
25
+ @items << item if include_invisible || visible?(item)
26
+ end
27
+
28
+ @items.sort_by!(&:position)
29
+ end
30
+
31
+ private
32
+
33
+ attr_accessor :organization, :user
34
+ attr_reader :name, :view
35
+
36
+ def visible?(item)
37
+ case item.visibility
38
+ when "hidden"
39
+ false
40
+ when "logged"
41
+ user.present?
42
+ when "non_logged"
43
+ user.blank?
44
+ else
45
+ true
46
+ end
47
+ end
48
+
49
+ def default_items
50
+ @default_items ||= build_menu.instance_variable_get(:@items).map do |item|
51
+ item.instance_variable_set(:@active, method(:activate?)) unless item.active == :exact
52
+ item
53
+ end
54
+ end
55
+
56
+ def build_menu
57
+ menu = Decidim::Menu.new(name)
58
+ menu.build_for(view)
59
+ menu
60
+ end
61
+
62
+ def menu_overrides
63
+ @menu_overrides ||= current_config.map do |item|
64
+ OpenStruct.new(
65
+ label: translated_attribute(item["label"], organization),
66
+ raw_label: item["label"],
67
+ url: item["url"],
68
+ position: item["position"] || 1,
69
+ # see options in https://github.com/comfy/active_link_to
70
+ active: method(:activate?),
71
+ visibility: item["visibility"],
72
+ target: item["target"],
73
+ overrided?: false
74
+ )
75
+ end
76
+ end
77
+
78
+ def activate?(url, view)
79
+ urls = @items.map(&:url).sort_by(&:length).reverse
80
+ url == urls.find { |u| view.request.original_fullpath.start_with?(u) }
81
+ end
82
+
83
+ def current_config
84
+ @current_config ||= (AwesomeConfig.find_by(var: name, organization: organization)&.value || []).filter { |i| i.is_a? Hash }
85
+ end
86
+ end
87
+ end
88
+ end
@@ -16,7 +16,7 @@ FactoryBot.define do
16
16
  end
17
17
 
18
18
  factory :editor_image, class: "Decidim::DecidimAwesome::EditorImage" do
19
- image { Faker::Hacker.noun }
19
+ image { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
20
20
  path { Faker::Internet.url(host: "", scheme: "") }
21
21
  author { create :user }
22
22
  organization { create :organization }
@@ -9,17 +9,19 @@ shared_examples "javascript config vars" do
9
9
  end
10
10
 
11
11
  shared_examples "has menu link" do |item|
12
+ let(:prefix) { "config/" }
12
13
  it "shows the feature link" do
13
14
  within ".secondary-nav" do
14
- expect(page).to have_link(href: "/admin/decidim_awesome/config/#{item}")
15
+ expect(page).to have_link(href: "/admin/decidim_awesome/#{prefix}#{item}")
15
16
  end
16
17
  end
17
18
  end
18
19
 
19
20
  shared_examples "do not have menu link" do |item|
21
+ let(:prefix) { "config/" }
20
22
  it "do not show the feature link" do
21
23
  within ".secondary-nav" do
22
- expect(page).not_to have_link(href: "/admin/decidim_awesome/config/#{item}")
24
+ expect(page).not_to have_link(href: "/admin/decidim_awesome/#{prefix}#{item}")
23
25
  end
24
26
  end
25
27
  end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples "has no drag and drop" do |rte|
4
+ it "has no help text" do
5
+ expect(page).not_to have_content("Add images by dragging & dropping or pasting them.")
6
+ end
7
+
8
+ if rte
9
+ it "has image button" do
10
+ expect(page).not_to have_xpath("//button[@class='ql-image']")
11
+ end
12
+ else
13
+ it "has no paste event" do
14
+ expect(page.execute_script("return typeof $._data($('#{editor_selector}')[0], 'events').paste")).to eq("undefined")
15
+ end
16
+
17
+ it "has no drop event" do
18
+ expect(page.execute_script("return typeof $._data($('#{editor_selector}')[0], 'events').drop")).to eq("undefined")
19
+ end
20
+ end
21
+ end
22
+
23
+ shared_examples "has drag and drop" do |rte|
24
+ it "has help text" do
25
+ expect(page).to have_content("Add images by dragging & dropping or pasting them.")
26
+ end
27
+
28
+ if rte
29
+ it "has image button" do
30
+ expect(page).to have_xpath("//button[@class='ql-image']")
31
+ end
32
+ else
33
+ it "has paste event" do
34
+ expect(page.execute_script("return typeof $._data($('#{editor_selector}')[0], 'events').paste")).to eq("object")
35
+ end
36
+
37
+ it "has drop event" do
38
+ expect(page.execute_script("return typeof $._data($('#{editor_selector}')[0], 'events').drop")).to eq("object")
39
+ end
40
+ end
41
+ end
42
+
43
+ shared_examples "has markdown editor" do |images|
44
+ it "has CodeMirror class" do
45
+ expect(page).to have_xpath("//div[@class='CodeMirror cm-s-paper CodeMirror-wrap']")
46
+ end
47
+
48
+ it "has toolbar" do
49
+ expect(page).to have_xpath("//div[@class='editor-toolbar']")
50
+ end
51
+
52
+ if images
53
+ it "has help text" do
54
+ expect(page).to have_content("Add images by dragging & dropping or pasting them.")
55
+ end
56
+ else
57
+ it "has no help text" do
58
+ expect(page).not_to have_content("Add images by dragging & dropping or pasting them.")
59
+ end
60
+ end
61
+ end
62
+
63
+ shared_examples "has no markdown editor" do
64
+ it "has CodeMirror class" do
65
+ expect(page).not_to have_xpath("//div[@class='CodeMirror cm-s-paper CodeMirror-wrap']")
66
+ end
67
+
68
+ it "has toolbar" do
69
+ expect(page).not_to have_xpath("//div[@class='editor-toolbar']")
70
+ end
71
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_context "with menu hacks params" do
4
+ let(:organization) { create(:organization) }
5
+ let(:context) do
6
+ {
7
+ current_user: create(:user, organization: organization),
8
+ current_organization: organization
9
+ }
10
+ end
11
+ let(:params) do
12
+ {
13
+ raw_label: label,
14
+ url: url,
15
+ position: position,
16
+ target: target,
17
+ visibility: visibility
18
+ }
19
+ end
20
+ let(:attributes) do
21
+ {
22
+ "label" => label,
23
+ "url" => url,
24
+ "position" => position,
25
+ "target" => target,
26
+ "visibility" => visibility
27
+ }
28
+ end
29
+ let(:label) do
30
+ {
31
+ "en" => "Menu english",
32
+ "ca" => "Menu catalan"
33
+ }
34
+ end
35
+ let(:url) { "/some-path" }
36
+ let(:position) { 2 }
37
+ let(:target) { "_blank" }
38
+ let(:visibility) { "hidden" }
39
+ let(:menu_name) { "menu" }
40
+
41
+ let(:another_params) do
42
+ {
43
+ allow_images_in_full_editor: true,
44
+ allow_images_in_small_editor: true
45
+ }
46
+ end
47
+ let(:form) do
48
+ Decidim::DecidimAwesome::Admin::MenuForm.from_params(params).with_context(context)
49
+ end
50
+ let(:another_form) do
51
+ Decidim::DecidimAwesome::Admin::ConfigForm.from_params(another_params).with_context(context)
52
+ end
53
+ let(:another_config) { Decidim::DecidimAwesome::Admin::UpdateConfig.new(another_form) }
54
+ end
55
+
56
+ shared_examples "forbids disabled feature" do
57
+ let(:feature) { :menu }
58
+ let(:features) { [feature] }
59
+ before do
60
+ features.each do |feat|
61
+ allow(Decidim::DecidimAwesome.config).to receive(feat).and_return(:disabled)
62
+ end
63
+ end
64
+
65
+ it "redirects with error" do
66
+ action
67
+
68
+ expect(flash[:alert]).not_to be_empty
69
+ expect(response).to redirect_to("/admin/")
70
+ end
71
+ end