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.



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

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.



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

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

#component_nameObject



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

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



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

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



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

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



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

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



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

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.



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

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)


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

def minimum_votes_per_user_enabled?
  minimum_votes_per_user.positive?
end

#not_from_collaborative_draft(proposal) ⇒ Object



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

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

#not_from_participatory_text(proposal) ⇒ Object



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

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

#proposal_limitObject



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

def proposal_limit
  return if component_settings.proposal_limit.zero?

  component_settings.proposal_limit
end

#proposal_limit_enabled?Boolean

Returns:

  • (Boolean)


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

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.



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

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
# File 'app/helpers/decidim/proposals/application_helper.rb', line 31

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

  proposal.proposal_state&.css_style
end

#render_proposal_body(proposal) ⇒ Object

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



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

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)


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

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)


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

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

#show_voting_rules?Boolean

Returns:

  • (Boolean)


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

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.



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

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



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

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