Module: Decidim::Proposals::ApplicationHelper

Overview

Custom helpers, scoped to the proposals engine.

Constant Summary

Constants included from AmendmentsHelper

AmendmentsHelper::TOTAL_STEPS

Instance Method Summary collapse

Methods included from CheckBoxesTreeHelper

#check_boxes_tree_options, #filter_areas_values, #filter_categories_values, #filter_global_scopes_values, #filter_scopes_values, #filter_text_for, #filter_tree_from_array, #flat_filter_values, #resource_filter_scope_values

Methods included from RichTextEditorHelper

included, #text_editor_for

Methods included from ControlVersionHelper

#item_name

Methods included from CollaborativeDraftHelper

#accept_request_button_label, #collaborative_drafts_filter_sections, #collaborative_drafts_state_class, #filter_collaborative_drafts_state_values, #reject_request_button_label

Methods included from MapHelper

#has_position?, #proposal_data_for_map, #proposal_preview_data_for_map, #proposals_data_for_map

Methods included from ApplicationHelper

#cell, #edit_link, #extra_admin_link, #html_truncate, #present, #prevent_timeout_seconds, #resolve_presenter_class, #step_cta_url

Methods included from CacheHelper

#cache

Methods included from AmendmentsHelper

#accept_and_reject_buttons_for, #action_button_card_for, #allowed_to_accept_and_reject?, #allowed_to_promote?, #amend_button_for, #amendments_enabled?, #amendments_form_field_for, #amendments_form_fields_label, #amendments_form_fields_value, #can_participate_in_private_space?, #can_react_to_emendation?, #current_step, #emendation_actions_for, #emendation_announcement_for, #promote_button_for, #render_emendation_body, #total_steps, #wizard_aside_back_url, #wizard_header_title

Methods included from ContextualHelpHelper

#floating_help

Methods included from ScopesHelper

#has_visible_scopes?, #scope_name_for_picker, #scopes_picker_field, #scopes_picker_filter, #scopes_select_field, #scopes_select_tag

Methods included from TranslatableAttributes

#default_locale?

Methods included from DecidimFormHelper

#areas_for_select, #base_error_messages, #decidim_form_for, #decidim_form_slug_url, #editor_field_tag, #form_field_has_error?, #form_required_explanation, #name_with_locale, #ordered_scopes_descendants, #ordered_scopes_descendants_for_select, #scopes_picker_field_tag, #tab_element_class_for, #translated_field_tag

Methods included from OmniauthHelper

#normalize_provider_name, #oauth_icon, #provider_name

Methods included from MapHelper

#dynamic_map_for, #static_map_link

Methods included from FollowableHelper

#follow_button_for

Methods included from EndorsableHelper

#current_user_can_endorse?, #endorsement_buttons_cell, #endorsements_blocked?, #endorsements_enabled?, #endorsers_list_cell, #fully_endorsed?, #path_to_create_endorsement, #path_to_destroy_endorsement, #render_endorsement_identity, #show_endorsements_card?

Methods included from ProposalVotesHelper

#can_accumulate_supports_beyond_threshold?, #current_user_can_vote?, #remaining_votes_count_for, #threshold_per_proposal, #threshold_per_proposal_enabled?, #vote_limit, #vote_limit_enabled?, #votes_blocked?, #votes_enabled?

Methods included from Decidim::PaginateHelper

#decidim_paginate, #per_page

Methods included from Comments::CommentsHelper

#comments_for, #inline_comments_for

Instance Method Details

#activity_filter_valuesObject

Options to filter Proposals by activity.



160
161
162
163
164
165
166
167
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 160

def activity_filter_values
  base = [
    ["all", t("decidim.proposals.proposals.filters.all")],
    ["my_proposals", t("decidim.proposals.proposals.filters.my_proposals")]
  ]
  base += [["voted", t("decidim.proposals.proposals.filters.voted")]] if current_settings.votes_enabled?
  base
end

#collaborative_draft_state_badge_css_class(state) ⇒ Object

Public: The css class applied based on the collaborative draft state.

state - The String state of the collaborative draft.

Returns a String.



66
67
68
69
70
71
72
73
74
75
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 66

def collaborative_draft_state_badge_css_class(state)
  case state
  when "open"
    "success"
  when "withdrawn"
    "alert"
  when "published"
    "secondary"
  end
end

#component_nameObject



241
242
243
244
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 241

def component_name
  i18n_key = controller_name == "collaborative_drafts" ? "decidim.proposals.collaborative_drafts.name" : "decidim.components.proposals.name"
  (defined?(current_component) && translated_attribute(current_component&.name).presence) || t(i18n_key)
end

#filter_origin_valuesObject

Explicitely commenting the used I18n keys so their are not flagged as unused i18n-tasks-use t(‘decidim.proposals.application_helper.filter_origin_values.official’) i18n-tasks-use t(‘decidim.proposals.application_helper.filter_origin_values.participants’) i18n-tasks-use t(‘decidim.proposals.application_helper.filter_origin_values.user_groups’) i18n-tasks-use t(‘decidim.proposals.application_helper.filter_origin_values.official’) i18n-tasks-use t(‘decidim.proposals.application_helper.filter_origin_values.meetings’) i18n-tasks-use t(‘decidim.proposals.application_helper.filter_origin_values.all’)



176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 176

def filter_origin_values
  scope = "decidim.proposals.application_helper.filter_origin_values"
  origin_values = []
  origin_values << TreePoint.new("official", t("official", scope:)) if component_settings.official_proposals_enabled
  origin_values << TreePoint.new("participants", t("participants", scope:))
  origin_values << TreePoint.new("user_group", t("user_groups", scope:)) if current_organization.user_groups_enabled?
  origin_values << TreePoint.new("meeting", t("meetings", scope:))

  TreeNode.new(
    TreePoint.new("", t("all", scope:)),
    origin_values
  )
end

#filter_proposals_state_valuesObject



190
191
192
193
194
195
196
197
198
199
200
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 190

def filter_proposals_state_values
  Decidim::CheckBoxesTreeHelper::TreeNode.new(
    Decidim::CheckBoxesTreeHelper::TreePoint.new("", t("decidim.proposals.application_helper.filter_state_values.all")),
    [
      Decidim::CheckBoxesTreeHelper::TreePoint.new("accepted", t("decidim.proposals.application_helper.filter_state_values.accepted")),
      Decidim::CheckBoxesTreeHelper::TreePoint.new("evaluating", t("decidim.proposals.application_helper.filter_state_values.evaluating")),
      Decidim::CheckBoxesTreeHelper::TreePoint.new("state_not_published", t("decidim.proposals.application_helper.filter_state_values.not_answered")),
      Decidim::CheckBoxesTreeHelper::TreePoint.new("rejected", t("decidim.proposals.application_helper.filter_state_values.rejected"))
    ]
  )
end

#filter_sectionsObject

rubocop:disable Metrics/CyclomaticComplexity rubocop:disable Metrics/PerceivedComplexity



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 204

def filter_sections
  @filter_sections ||= begin
    items = []
    if component_settings.proposal_answering_enabled && current_settings.proposal_answering_enabled
      items.append(method: :with_any_state, collection: filter_proposals_state_values, label_scope: "decidim.proposals.proposals.filters", id: "state")
    end
    if current_component.has_subscopes?
      items.append(method: :with_any_scope, collection: filter_scopes_values, label_scope: "decidim.proposals.proposals.filters", id: "scope")
    end
    if current_component.categories.any?
      items.append(method: :with_any_category, collection: filter_categories_values, label_scope: "decidim.proposals.proposals.filters", id: "category")
    end
    if component_settings.official_proposals_enabled
      items.append(method: :with_any_origin, collection: filter_origin_values, label_scope: "decidim.proposals.proposals.filters", id: "origin")
    end
    if current_user
      items.append(method: :activity, collection: activity_filter_values, label_scope: "decidim.proposals.proposals.filters", id: "activity", type: :radio_buttons)
    end
    if @proposals.only_emendations.any?
      items.append(method: :type, collection: filter_type_values, label_scope: "decidim.proposals.proposals.filters", id: "amendment_type", type: :radio_buttons)
    end
    if linked_classes_for(Decidim::Proposals::Proposal).any?
      items.append(
        method: :related_to,
        collection: linked_classes_filter_values_for(Decidim::Proposals::Proposal),
        label_scope: "decidim.proposals.proposals.filters",
        id: "related_to",
        type: :radio_buttons
      )
    end
  end
  # rubocop:enable Metrics/PerceivedComplexity
  # rubocop:enable Metrics/CyclomaticComplexity

  items.reject { |item| item[:collection].blank? }
end

#filter_type_valuesObject



151
152
153
154
155
156
157
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 151

def filter_type_values
  [
    ["all", t("decidim.proposals.application_helper.filter_type_values.all")],
    ["proposals", t("decidim.proposals.application_helper.filter_type_values.proposals")],
    ["amendments", t("decidim.proposals.application_helper.filter_type_values.amendments")]
  ]
end

#humanize_collaborative_draft_state(state) ⇒ Object

Public: The state of a proposal in a way a human can understand.

state - The String state of the proposal.

Returns a String.



57
58
59
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 57

def humanize_collaborative_draft_state(state)
  I18n.t("decidim.proposals.collaborative_drafts.states.#{state}", default: :open)
end

#humanize_proposal_state(state) ⇒ Object

Public: The state of a proposal in a way a human can understand.

state - The String state of the proposal.

Returns a String.



27
28
29
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 27

def humanize_proposal_state(state)
  I18n.t(state, scope: "decidim.proposals.answers", default: :not_answered)
end

#minimum_votes_per_user_enabled?Boolean

Returns:

  • (Boolean)


81
82
83
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 81

def minimum_votes_per_user_enabled?
  minimum_votes_per_user.positive?
end

#not_from_collaborative_draft(proposal) ⇒ Object



85
86
87
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 85

def not_from_collaborative_draft(proposal)
  proposal.linked_resources(:proposals, "created_from_collaborative_draft").empty?
end

#not_from_participatory_text(proposal) ⇒ Object



89
90
91
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 89

def not_from_participatory_text(proposal)
  proposal.participatory_text_level.nil?
end

#proposal_limitObject



128
129
130
131
132
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 128

def proposal_limit
  return if component_settings.proposal_limit.zero?

  component_settings.proposal_limit
end

#proposal_limit_enabled?Boolean

Returns:

  • (Boolean)


77
78
79
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 77

def proposal_limit_enabled?
  proposal_limit.present?
end

#proposal_state_css_class(proposal) ⇒ Object

Public: The css class applied based on the proposal state.

proposal - The proposal to evaluate.

Returns a String.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 36

def proposal_state_css_class(proposal)
  state = proposal.state
  state = proposal.internal_state if proposal.answered? && !proposal.published_state?

  case state
  when "accepted"
    "success"
  when "rejected", "withdrawn"
    "alert"
  when "evaluating"
    "warning"
  else
    "info"
  end
end

#render_proposal_body(proposal) ⇒ Object

If the content is safe, HTML tags are sanitized, otherwise, they are stripped.



108
109
110
111
112
113
114
115
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 108

def render_proposal_body(proposal)
  sanitized = render_sanitized_content(proposal, :body)
  if safe_content?
    Decidim::ContentProcessor.render_without_format(sanitized).html_safe
  else
    Decidim::ContentProcessor.render(sanitized)
  end
end

#safe_content?Boolean

If the proposal is official or the rich text editor is enabled on the frontend, the proposal body is considered as safe content; that is unless the proposal comes from a collaborative_draft or a participatory_text.

Returns:

  • (Boolean)


96
97
98
99
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 96

def safe_content?
  (rich_text_editor_in_public_views? && not_from_collaborative_draft(@proposal)) ||
    safe_content_admin?
end

#safe_content_admin?Boolean

For admin entered content, the proposal body can contain certain extra tags, such as iframes.

Returns:

  • (Boolean)


103
104
105
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 103

def safe_content_admin?
  (@proposal.official? || @proposal.official_meeting?) && not_from_participatory_text(@proposal)
end

#show_voting_rules?Boolean

Returns:

  • (Boolean)


141
142
143
144
145
146
147
148
149
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 141

def show_voting_rules?
  return false unless votes_enabled?

  return true if vote_limit_enabled?
  return true if threshold_per_proposal_enabled?
  return true if proposal_limit_enabled?
  return true if can_accumulate_supports_beyond_threshold?
  return true if minimum_votes_per_user_enabled?
end

#text_editor_for_proposal_body(form) ⇒ Object

Returns :text_area or :editor based on the organization’ settings.



118
119
120
121
122
123
124
125
126
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 118

def text_editor_for_proposal_body(form)
  options = {
    class: "js-hashtags",
    hashtaggable: true,
    value: form_presenter.body(extras: false, strip_tags: !current_organization.rich_text_editor_in_public_views).strip
  }

  text_editor_for(form, :body, options)
end

#votes_givenObject



134
135
136
137
138
139
# File 'decidim-proposals/app/helpers/decidim/proposals/application_helper.rb', line 134

def votes_given
  @votes_given ||= ProposalVote.where(
    proposal: Proposal.where(component: current_component),
    author: current_user
  ).count
end