decidim-core 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/app/assets/config/decidim_core_manifest.js +1 -0
  4. data/app/assets/javascripts/decidim.js.es6 +3 -2
  5. data/app/assets/javascripts/decidim/append_elements.js.es6 +8 -0
  6. data/app/assets/javascripts/decidim/filters.js.es6 +22 -0
  7. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +176 -0
  8. data/app/assets/javascripts/decidim/form_filter.component.test.js +151 -0
  9. data/app/assets/javascripts/decidim/inline_svg.js.es6 +12 -0
  10. data/app/assets/javascripts/decidim/user_registrations.js.es6 +22 -0
  11. data/app/assets/stylesheets/decidim/_variables.scss +1 -1
  12. data/app/assets/stylesheets/decidim/modules/_comments.scss +3 -6
  13. data/app/assets/stylesheets/decidim/modules/_cookie-bar.scss +22 -0
  14. data/app/assets/stylesheets/decidim/modules/_layout.scss +9 -1
  15. data/app/assets/stylesheets/decidim/modules/_navbar.scss +8 -5
  16. data/app/assets/stylesheets/decidim/modules/_order-by.scss +0 -1
  17. data/app/assets/stylesheets/decidim/modules/_process-phase.scss +4 -0
  18. data/app/assets/stylesheets/decidim/modules/_timeline.scss +62 -80
  19. data/app/assets/stylesheets/decidim/modules/_typography.scss +20 -31
  20. data/app/assets/stylesheets/decidim/utils/_fontface.scss +4 -16
  21. data/app/assets/stylesheets/decidim/utils/_settings.scss +29 -26
  22. data/app/assets/stylesheets/decidim/utils/_variables.scss +22 -0
  23. data/app/commands/decidim/authorize_user.rb +17 -1
  24. data/app/commands/decidim/create_omniauth_registration.rb +92 -0
  25. data/app/commands/decidim/create_registration.rb +50 -0
  26. data/app/commands/decidim/invite_user.rb +50 -0
  27. data/app/commands/decidim/invite_user_again.rb +25 -0
  28. data/app/commands/decidim/remove_user_role.rb +26 -0
  29. data/app/controllers/concerns/decidim/feature_settings.rb +27 -0
  30. data/app/controllers/concerns/decidim/filter_resource.rb +71 -0
  31. data/app/controllers/concerns/decidim/form_factory.rb +21 -18
  32. data/app/controllers/concerns/decidim/needs_participatory_process.rb +2 -3
  33. data/app/controllers/decidim/devise/confirmations_controller.rb +2 -0
  34. data/app/controllers/decidim/devise/invitations_controller.rb +4 -0
  35. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +96 -0
  36. data/app/controllers/decidim/devise/passwords_controller.rb +2 -0
  37. data/app/controllers/decidim/devise/registrations_controller.rb +34 -0
  38. data/app/controllers/decidim/devise/sessions_controller.rb +1 -0
  39. data/app/controllers/decidim/pages_controller.rb +10 -2
  40. data/app/controllers/decidim/participatory_process_steps_controller.rb +16 -0
  41. data/app/controllers/decidim/participatory_processes_controller.rb +6 -11
  42. data/app/forms/decidim/form.rb +6 -6
  43. data/app/forms/decidim/invite_admin_form.rb +37 -0
  44. data/app/forms/decidim/omniauth_registration_form.rb +24 -0
  45. data/app/forms/decidim/registration_form.rb +41 -0
  46. data/app/helpers/decidim/filters_helper.rb +21 -0
  47. data/app/helpers/decidim/layout_helper.rb +17 -1
  48. data/app/helpers/decidim/omniauth_helper.rb +23 -0
  49. data/app/helpers/decidim/paginate_helper.rb +21 -0
  50. data/app/helpers/decidim/participatory_process_helper.rb +14 -0
  51. data/app/helpers/decidim/participatory_process_steps_helper.rb +17 -0
  52. data/app/mailers/decidim/decidim_devise_mailer.rb +2 -2
  53. data/app/models/decidim/feature.rb +40 -0
  54. data/app/models/decidim/identity.rb +12 -0
  55. data/app/models/decidim/organization.rb +3 -10
  56. data/app/models/decidim/user.rb +3 -1
  57. data/app/models/decidim/user_group.rb +18 -0
  58. data/app/models/decidim/user_group_membership.rb +9 -0
  59. data/app/services/decidim/authorization_handler.rb +13 -13
  60. data/app/services/decidim/resource_search.rb +52 -0
  61. data/app/uploaders/decidim/organization_logo_uploader.rb +1 -1
  62. data/app/views/decidim/authorizations/new.html.erb +3 -1
  63. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +40 -0
  64. data/app/views/decidim/devise/registrations/new.html.erb +21 -1
  65. data/app/views/decidim/devise/sessions/new.html.erb +1 -0
  66. data/app/views/decidim/devise/shared/_links.html.erb +0 -8
  67. data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +21 -0
  68. data/app/views/decidim/participatory_process_steps/_participatory_process_step.html.erb +16 -0
  69. data/app/views/decidim/participatory_process_steps/_timeline.html.erb +7 -0
  70. data/app/views/decidim/participatory_process_steps/index.html.erb +12 -0
  71. data/app/views/decidim/participatory_processes/show.html.erb +5 -5
  72. data/app/views/decidim/shared/_login_modal.html.erb +30 -0
  73. data/app/views/devise/mailer/invite_admin.html.erb +17 -0
  74. data/app/views/devise/mailer/invite_admin.text.erb +15 -0
  75. data/app/views/devise/mailer/organization_admin_invitation_instructions.html.erb +1 -1
  76. data/app/views/devise/mailer/organization_admin_invitation_instructions.text.erb +1 -1
  77. data/app/views/layouts/decidim/_application.html.erb +1 -0
  78. data/app/views/layouts/decidim/_header.html.erb +1 -1
  79. data/app/views/layouts/decidim/_meta.html.erb +1 -0
  80. data/app/views/layouts/decidim/_process_header.html.erb +12 -1
  81. data/app/views/layouts/decidim/_process_header_steps.html.erb +1 -0
  82. data/app/views/layouts/decidim/_social_meta.html.erb +11 -0
  83. data/app/views/layouts/decidim/participatory_process.html.erb +4 -0
  84. data/app/views/pages/home.html.erb +29 -2
  85. data/config/i18n-tasks.yml +1 -0
  86. data/config/initializers/devise.rb +10 -1
  87. data/config/locales/ca.yml +45 -3
  88. data/config/locales/en.yml +45 -3
  89. data/config/locales/es.yml +45 -3
  90. data/config/routes.rb +9 -2
  91. data/config/secrets.yml +36 -0
  92. data/db/migrate/20170110133113_add_configuration_to_features.rb +7 -0
  93. data/db/migrate/20170110153807_add_handler_to_organization.rb +5 -0
  94. data/db/migrate/20170116110851_create_identities.rb +11 -0
  95. data/db/migrate/20170116135237_loosen_step_requirements.rb +6 -0
  96. data/db/migrate/20170117142904_add_uniqueness_field_to_authorizations.rb +7 -0
  97. data/db/migrate/20170119145359_create_user_groups.rb +11 -0
  98. data/db/migrate/20170119150255_create_user_group_memberships.rb +12 -0
  99. data/db/migrate/20170119150649_add_show_statistics_to_organization.rb +5 -0
  100. data/db/migrate/20170120120733_add_user_groups_verified.rb +5 -0
  101. data/db/seeds.rb +45 -79
  102. data/lib/decidim/core.rb +8 -0
  103. data/lib/decidim/core/engine.rb +8 -0
  104. data/lib/decidim/core/test/factories.rb +188 -0
  105. data/lib/decidim/core/version.rb +1 -1
  106. data/lib/decidim/devise_failure_app.rb +1 -0
  107. data/lib/decidim/feature_manifest.rb +27 -0
  108. data/lib/decidim/features/base_controller.rb +8 -3
  109. data/lib/decidim/features/settings_manifest.rb +94 -0
  110. data/lib/decidim/filter_form_builder.rb +56 -0
  111. data/lib/decidim/form_builder.rb +4 -7
  112. data/vendor/assets/javascripts/svg-injector.js +464 -0
  113. metadata +142 -26
  114. data/app/assets/stylesheets/decidim/modules/_owl-carousel.scss +0 -72
  115. data/app/assets/stylesheets/decidim/modules/_phase-nav.scss +0 -177
  116. data/app/assets/stylesheets/decidim/utils/_helpers.sass +0 -21
  117. data/app/assets/stylesheets/decidim/utils/_keyframes.sass +0 -13
  118. data/app/assets/stylesheets/decidim/utils/_mixins.sass +0 -33
@@ -19,14 +19,13 @@ module Decidim
19
19
  #
20
20
  # Returns the current ParticipatoryProcess.
21
21
  def current_participatory_process
22
- @current_participatory_process ||=
23
- current_organization.participatory_processes.find_by(id: params[:participatory_process_id])
22
+ @current_participatory_process ||= current_organization.participatory_processes.find_by(id: params[:participatory_process_id] || params[:id])
24
23
  end
25
24
 
26
25
  private
27
26
 
28
27
  def verify_participatory_process
29
- raise ActionController::RoutingError, "Not Found" unless current_participatory_process
28
+ raise ActionController::RoutingError, "Participatory process not found." unless current_participatory_process
30
29
  end
31
30
  end
32
31
  end
@@ -5,6 +5,8 @@ module Decidim
5
5
  class ConfirmationsController < ::Devise::ConfirmationsController
6
6
  include Decidim::NeedsOrganization
7
7
  include Decidim::LocaleSwitcher
8
+ helper Decidim::TranslationsHelper
9
+
8
10
  layout "layouts/decidim/application"
9
11
  end
10
12
  end
@@ -3,6 +3,10 @@ module Decidim
3
3
  module Devise
4
4
  # This controller customizes the behaviour of Devise::Invitiable.
5
5
  class InvitationsController < ::Devise::InvitationsController
6
+ include Decidim::NeedsOrganization
7
+ include Decidim::LocaleSwitcher
8
+ helper Decidim::TranslationsHelper
9
+
6
10
  # We don't users to create invitations, so we just redirect them to the
7
11
  # homepage.
8
12
  def authenticate_inviter!
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Devise
4
+ # This controller customizes the behaviour of Devise::Omniauthable.
5
+ class OmniauthRegistrationsController < ::Devise::OmniauthCallbacksController
6
+ include FormFactory
7
+
8
+ include Decidim::NeedsOrganization
9
+ include Decidim::LocaleSwitcher
10
+ helper Decidim::TranslationsHelper
11
+
12
+ layout "layouts/decidim/application"
13
+
14
+ def new
15
+ @form = form(OmniauthRegistrationForm).from_params(params[:user])
16
+ end
17
+
18
+ def create
19
+ form_params = user_params_from_oauth_hash || params[:user]
20
+ @form = form(OmniauthRegistrationForm).from_params(form_params)
21
+ @form.email ||= verified_email
22
+
23
+ CreateOmniauthRegistration.call(@form, verified_email) do
24
+ on(:ok) do |user|
25
+ if user.active_for_authentication?
26
+ sign_in_and_redirect user, event: :authentication
27
+ set_flash_message :notice, :success, kind: @form.provider.capitalize
28
+ else
29
+ expire_data_after_sign_in!
30
+ redirect_to root_path
31
+ flash[:notice] = t("devise.registrations.signed_up_but_unconfirmed")
32
+ end
33
+ end
34
+
35
+ on(:invalid) do
36
+ set_flash_message :notice, :success, kind: @form.provider.capitalize
37
+ render :new
38
+ end
39
+
40
+ on(:error) do
41
+ redirect_to decidim.new_user_registration_path
42
+ set_flash_message :alert, :failure, kind: @form.provider, reason: t("decidim.devise.omniauth_registrations.create.email_already_exists")
43
+ end
44
+ end
45
+ end
46
+
47
+ def after_sign_in_path_for(user)
48
+ if !pending_redirect?(user) && first_login_and_not_authorized?(user)
49
+ authorizations_path
50
+ else
51
+ super
52
+ end
53
+ end
54
+
55
+ # Calling the `stored_location_for` method removes the key, so in order
56
+ # to check if there's any pending redirect after login I need to call
57
+ # this method and use the value to set a pending redirect. This is the
58
+ # only way to do this without checking the session directly.
59
+ def pending_redirect?(user)
60
+ store_location_for(user, stored_location_for(user))
61
+ end
62
+
63
+ def first_login_and_not_authorized?(user)
64
+ user.is_a?(User) && user.sign_in_count == 1 && Decidim.authorization_handlers.any?
65
+ end
66
+
67
+ def action_missing(action_name)
68
+ return send(:create) if devise_mapping.omniauthable? && User.omniauth_providers.include?(action_name.to_sym)
69
+ raise AbstractController::ActionNotFound, "The action '#{action_name}' could not be found for Decidim::Devise::OmniauthCallbacksController"
70
+ end
71
+
72
+ private
73
+
74
+ def oauth_data
75
+ return {} unless request.env["omniauth.auth"]
76
+ @oauth_data ||= request.env["omniauth.auth"].slice(:provider, :uid, :info)
77
+ end
78
+
79
+ # Private: Create form params from omniauth hash
80
+ # Since we are using trusted omniauth data we are generating a valid signature.
81
+ def user_params_from_oauth_hash
82
+ return nil unless request.env["omniauth.auth"]
83
+ {
84
+ provider: oauth_data[:provider],
85
+ uid: oauth_data[:uid],
86
+ name: oauth_data[:info][:name],
87
+ oauth_signature: OmniauthRegistrationForm.create_signature(oauth_data[:provider], oauth_data[:uid])
88
+ }
89
+ end
90
+
91
+ def verified_email
92
+ @verified_email ||= oauth_data.dig(:info, :email)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -5,6 +5,8 @@ module Decidim
5
5
  class PasswordsController < ::Devise::PasswordsController
6
6
  include Decidim::NeedsOrganization
7
7
  include Decidim::LocaleSwitcher
8
+ helper Decidim::TranslationsHelper
9
+
8
10
  layout "layouts/decidim/application"
9
11
  end
10
12
  end
@@ -6,9 +6,43 @@ module Decidim
6
6
  class RegistrationsController < ::Devise::RegistrationsController
7
7
  include Decidim::NeedsOrganization
8
8
  include Decidim::LocaleSwitcher
9
+ include FormFactory
10
+ helper Decidim::TranslationsHelper
11
+ helper Decidim::OmniauthHelper
12
+
9
13
  layout "layouts/decidim/application"
10
14
  before_action :configure_permitted_parameters
11
15
 
16
+ def new
17
+ @form = form(RegistrationForm).from_params(
18
+ user: {
19
+ sign_up_as: "user"
20
+ }
21
+ )
22
+ end
23
+
24
+ def create
25
+ @form = form(RegistrationForm).from_params(params[:user])
26
+
27
+ CreateRegistration.call(@form) do
28
+ on(:ok) do |user|
29
+ if user.active_for_authentication?
30
+ set_flash_message! :notice, :signed_up
31
+ sign_up(:user, user)
32
+ respond_with user, location: after_sign_up_path_for(user)
33
+ else
34
+ set_flash_message! :notice, :"signed_up_but_#{user.inactive_message}"
35
+ expire_data_after_sign_in!
36
+ respond_with user, location: after_inactive_sign_up_path_for(user)
37
+ end
38
+ end
39
+
40
+ on(:invalid) do
41
+ render :new
42
+ end
43
+ end
44
+ end
45
+
12
46
  protected
13
47
 
14
48
  def configure_permitted_parameters
@@ -6,6 +6,7 @@ module Decidim
6
6
  include Decidim::NeedsOrganization
7
7
  include Decidim::LocaleSwitcher
8
8
  helper Decidim::TranslationsHelper
9
+ helper Decidim::OmniauthHelper
9
10
 
10
11
  layout "layouts/decidim/application"
11
12
 
@@ -11,14 +11,22 @@ module Decidim
11
11
 
12
12
  authorize_resource :public_pages, class: false
13
13
  delegate :page, to: :page_finder
14
- helper_method :page, :participatory_processes
14
+ helper_method :page, :participatory_processes, :promoted_participatory_processes, :users
15
15
 
16
16
  def page_finder
17
17
  @page_finder ||= Decidim::PageFinder.new(params[:id], current_organization)
18
18
  end
19
19
 
20
+ def promoted_participatory_processes
21
+ @promoted_participatory_processes ||= participatory_processes.promoted
22
+ end
23
+
20
24
  def participatory_processes
21
- @participatory_processes ||= current_organization.participatory_processes.includes(:active_step).published.promoted
25
+ @participatory_processes ||= current_organization.participatory_processes.includes(:active_step).published
26
+ end
27
+
28
+ def users
29
+ @users ||= Decidim::User.where(organization: current_organization)
22
30
  end
23
31
  end
24
32
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ require_dependency "decidim/application_controller"
3
+
4
+ module Decidim
5
+ # A controller that holds the logic to show ParticipatoryProcessSteps in a
6
+ # public layout.
7
+ class ParticipatoryProcessStepsController < ApplicationController
8
+ helper_method :participatory_process, :current_participatory_process
9
+ layout "layouts/decidim/participatory_process", only: [:index]
10
+ include NeedsParticipatoryProcess
11
+
12
+ def index
13
+ authorize! :read, ParticipatoryProcess
14
+ end
15
+ end
16
+ end
@@ -5,29 +5,24 @@ module Decidim
5
5
  # A controller that holds the logic to show ParticipatoryProcesses in a
6
6
  # public layout.
7
7
  class ParticipatoryProcessesController < ApplicationController
8
- helper_method :participatory_processes, :participatory_process, :promoted_processes
9
- helper_method :current_participatory_process
8
+ include NeedsParticipatoryProcess
10
9
 
11
10
  layout "layouts/decidim/participatory_process", only: [:show]
12
11
 
12
+ helper_method :participatory_processes, :promoted_processes
13
+
14
+ skip_after_action :verify_participatory_process , only: [:index]
15
+
13
16
  def index
14
17
  authorize! :read, ParticipatoryProcess
15
18
  end
16
19
 
17
20
  def show
18
- authorize! :read, participatory_process
21
+ authorize! :read, current_participatory_process
19
22
  end
20
23
 
21
24
  private
22
25
 
23
- def current_participatory_process
24
- participatory_process
25
- end
26
-
27
- def participatory_process
28
- @participatory_process ||= ParticipatoryProcess.find(params[:id])
29
- end
30
-
31
26
  def participatory_processes
32
27
  @participatory_processes ||= current_organization.participatory_processes.includes(:active_step).published
33
28
  end
@@ -3,13 +3,13 @@ module Decidim
3
3
  # A base form object to hold common logic, like automatically adding as
4
4
  # public method the params sent as context by the `FormFactory` concern.
5
5
  class Form < Rectify::Form
6
- attr_reader :current_organization, :current_user, :current_feature
6
+ delegate :current_organization,
7
+ :current_user,
8
+ :current_feature,
9
+ to: :context, prefix: false, allow_nil: true
7
10
 
8
- def initialize(attributes = {})
9
- @current_organization = attributes.delete("current_organization") || attributes.delete(:current_organization)
10
- @current_user = attributes.delete("current_user") || attributes.delete(:current_user)
11
- @current_feature = attributes.delete("current_feature") || attributes.delete(:current_feature)
12
- super
11
+ def available_locales
12
+ current_organization&.available_locales
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # A form object used to invite admins to an organization.
5
+ #
6
+ class InviteAdminForm < Form
7
+ mimic :user
8
+
9
+ attribute :email, String
10
+ attribute :name, String
11
+ attribute :invitation_instructions, String
12
+ attribute :roles, Array[String]
13
+ attribute :organization, Decidim::Organization
14
+ attribute :invited_by, Decidim::User
15
+
16
+ validates :email, :name, :organization, :invitation_instructions, :roles, presence: true
17
+ validate :admin_uniqueness
18
+
19
+ def email
20
+ super&.downcase
21
+ end
22
+
23
+ def organization
24
+ super || current_organization
25
+ end
26
+
27
+ def invited_by
28
+ super || current_user
29
+ end
30
+
31
+ private
32
+
33
+ def admin_uniqueness
34
+ errors.add(:email, :taken) if organization.admins.where(email: email).exists?
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # A form object used to fisnish signup from omniauth data
5
+ class OmniauthRegistrationForm < Form
6
+ mimic :user
7
+
8
+ attribute :email, String
9
+ attribute :name, String
10
+ attribute :provider, String
11
+ attribute :uid, String
12
+ attribute :tos_agreement, Boolean
13
+ attribute :oauth_signature, String
14
+
15
+ validates :email, presence: true
16
+ validates :name, presence: true
17
+ validates :provider, presence: true
18
+ validates :uid, presence: true
19
+
20
+ def self.create_signature(provider, uid)
21
+ Digest::MD5.hexdigest("#{provider}-#{uid}-#{Rails.application.secrets.secret_key_base}")
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # A form object used to handle user registrations
5
+ class RegistrationForm < Form
6
+ mimic :user
7
+
8
+ attribute :sign_up_as, String
9
+ attribute :name, String
10
+ attribute :email, String
11
+ attribute :password, String
12
+ attribute :password_confirmation, String
13
+ attribute :tos_agreement, Boolean
14
+
15
+ attribute :user_group_name, String
16
+ attribute :user_group_document_number, String
17
+ attribute :user_group_phone, String
18
+
19
+ validates :sign_up_as, inclusion: { in: %w(user user_group) }
20
+ validates :name, presence: true
21
+ validates :email, presence: true
22
+ validates :password, presence: true, confirmation: true
23
+ validates :tos_agreement, allow_nil: false, acceptance: true
24
+
25
+ validates :user_group_name, presence: true, if: :is_user_group?
26
+ validates :user_group_document_number, presence: true, if: :is_user_group?
27
+ validates :user_group_phone, presence: true, if: :is_user_group?
28
+
29
+ validate :email_unique_in_organization
30
+
31
+ def is_user_group?
32
+ sign_up_as == "user_group"
33
+ end
34
+
35
+ private
36
+
37
+ def email_unique_in_organization
38
+ errors.add :email, :taken if User.where(email: email, organization: current_organization).first.present?
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ # Helper that provides a single method to create filter resource forms
4
+ module FiltersHelper
5
+ # This method wraps everything in a div with class filters and calls
6
+ # the form_for helper with a custom builder
7
+ #
8
+ # filter - A filter object
9
+ # block - A block to be called with the form builder
10
+ #
11
+ # Returns the filter resource form wrapped in a div
12
+ def filter_form_for(filter)
13
+ filters_container = content_tag :div, class: "filters" do
14
+ form_for filter, builder: FilterFormBuilder, url: url_for, as: :filter, method: :get, remote: true do |form|
15
+ yield form
16
+ end
17
+ end
18
+ filters_container + javascript_include_tag("decidim/filters")
19
+ end
20
+ end
21
+ end
@@ -33,11 +33,27 @@ module Decidim
33
33
  html_properties["aria-label"] = options[:aria_label]
34
34
  html_properties["role"] = options[:role]
35
35
  html_properties["aria-hidden"] = options[:aria_hidden]
36
- html_properties["class"] = "icon icon--#{name} #{options[:class]}"
36
+
37
+ icon_class = (options[:remove_icon_class] ? "" : "icon")
38
+ html_properties["class"] = "icon--#{name} #{icon_class} #{options[:class]}"
37
39
 
38
40
  content_tag :svg, html_properties do
39
41
  content_tag :use, nil, "xlink:href" => "#{asset_url("decidim/icons.svg")}#icon-#{name}"
40
42
  end
41
43
  end
44
+
45
+ # Outputs a SVG icon from an external file. It apparently renders an image
46
+ # tag, but then a JS script kicks in and replaces it with an inlined SVG
47
+ # version.
48
+ #
49
+ # path - The asset's path
50
+ #
51
+ # Returns an <img /> tag with the SVG icon.
52
+ def external_icon(path)
53
+ # Ugly hack to prevent PhantomJS from freaking out with SVGs.
54
+ return content_tag(:span, "?", class: "external-svg", "data-src" => path) if Rails.env.test?
55
+
56
+ image_tag(path, class: "external-svg", style: "display: none")
57
+ end
42
58
  end
43
59
  end