Module: Decidim::Proposals::ApplicationHelper

Includes:
CheckBoxesTreeHelper, Comments::CommentsHelper, EndorsableHelper, FollowableHelper, MapHelper, CollaborativeDraftHelper, ControlVersionHelper, MapHelper, ProposalVotesHelper, RichTextEditorHelper, PaginateHelper
Included in:
CollaborativeDraftCellsHelper, CollaborativeDraftMetadataCell, ProposalCellsHelper, ProposalGCell, ProposalMetadataCell
Defined in:
app/helpers/decidim/proposals/application_helper.rb

Overview

Custom helpers, scoped to the proposals engine.

Instance Method Summary collapse

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 ProposalVotesHelper

#can_accumulate_votes_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?

Instance Method Details

#activity_filter_valuesObject

Options to filter Proposals by activity.



167
168
169
170
171
172
173
174
# File 'app/helpers/decidim/proposals/application_helper.rb', line 167

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.



73
74
75
76
77
78
79
80
81
82
# File 'app/helpers/decidim/proposals/application_helper.rb', line 73

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

#component_nameObject



248
249
250
251
# File 'app/helpers/decidim/proposals/application_helper.rb', line 248

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

Explicitly 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’)



183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'app/helpers/decidim/proposals/application_helper.rb', line 183

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



197
198
199
200
201
202
203
204
205
206
207
# File 'app/helpers/decidim/proposals/application_helper.rb', line 197

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("state_not_published", t("decidim.proposals.application_helper.filter_state_values.not_answered"))
    ] +
      Decidim::Proposals::ProposalState.where(component: current_component).where.not(token: "not_answered").map do |state|
        Decidim::CheckBoxesTreeHelper::TreePoint.new(state.token, translated_attribute(state.title))
      end
  )
end

#filter_sectionsObject

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



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
240
241
242
243
244
245
246
# File 'app/helpers/decidim/proposals/application_helper.rb', line 211

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



158
159
160
161
162
163
164
# File 'app/helpers/decidim/proposals/application_helper.rb', line 158

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.



64
65
66
# File 'app/helpers/decidim/proposals/application_helper.rb', line 64

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 '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)


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

def minimum_votes_per_user_enabled?
  minimum_votes_per_user.positive?
end

#not_from_collaborative_draft(proposal) ⇒ Object



92
93
94
# File 'app/helpers/decidim/proposals/application_helper.rb', line 92

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

#not_from_participatory_text(proposal) ⇒ Object



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

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

#proposal_limitObject



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

def proposal_limit
  return if component_settings.proposal_limit.zero?

  component_settings.proposal_limit
end

#proposal_limit_enabled?Boolean

Returns:

  • (Boolean)


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

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.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'app/helpers/decidim/proposals/application_helper.rb', line 43

def proposal_state_css_class(proposal)
  return "alert" if proposal.withdrawn?
  return if proposal.state.blank?

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

#proposal_state_css_style(proposal) ⇒ Object



31
32
33
34
35
36
# File 'app/helpers/decidim/proposals/application_helper.rb', line 31

def proposal_state_css_style(proposal)
  return "" if proposal.emendation?
  return "" if proposal.withdrawn?

  proposal.proposal_state&.css_style
end

#render_proposal_body(proposal) ⇒ Object

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



115
116
117
118
119
120
121
122
# File 'app/helpers/decidim/proposals/application_helper.rb', line 115

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)


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

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)


110
111
112
# File 'app/helpers/decidim/proposals/application_helper.rb', line 110

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

#show_voting_rules?Boolean

Returns:

  • (Boolean)


148
149
150
151
152
153
154
155
156
# File 'app/helpers/decidim/proposals/application_helper.rb', line 148

def show_voting_rules?
  return false if !votes_enabled? || current_settings.votes_blocked?

  return true if vote_limit_enabled?
  return true if threshold_per_proposal_enabled?
  return true if proposal_limit_enabled?
  return true if can_accumulate_votes_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.



125
126
127
128
129
130
131
132
133
# File 'app/helpers/decidim/proposals/application_helper.rb', line 125

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



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

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