Module: Decidim::Proposals::ApplicationHelper

Includes:
CheckBoxesTreeHelper, Comments::CommentsHelper, FollowableHelper, LikeableHelper, MapHelper, CollaborativeDraftHelper, ControlVersionHelper, MapHelper, ProposalVotesHelper, RichTextEditorHelper, PaginateHelper
Included in:
CollaborativeDraftCellsHelper, CollaborativeDraftMetadataCell, ProposalCellsHelper, ProposalGCell, ProposalHistoryCell, 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_preview_data_for_map

Methods included from ProposalVotesHelper

#can_accumulate_votes_beyond_threshold?, #current_user_can_vote?, #minimum_votes_per_user_enabled?, #proposal_voted_by_user?, #remaining_minimum_votes_count_for_user, #remaining_votes_count_for_user, #threshold_per_proposal, #threshold_per_proposal_enabled?, #vote_limit_enabled?, #votes_blocked?, #votes_enabled?

Instance Method Details

#activity_filter_valuesObject

Options to filter Proposals by activity.



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

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.



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

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

#component_nameObject



237
238
239
240
# File 'app/helpers/decidim/proposals/application_helper.rb', line 237

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.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
# File '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("meeting", t("meetings", scope:))

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

#filter_proposals_state_valuesObject



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

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



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

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: t("decidim.proposals.proposals.filters.state"), id: "state")
    end
    current_component.available_taxonomy_filters.each do |taxonomy_filter|
      items.append(method: "with_any_taxonomies[#{taxonomy_filter.root_taxonomy_id}]",
                   collection: filter_taxonomy_values_for(taxonomy_filter),
                   label: decidim_sanitize_translated(taxonomy_filter.name),
                   id: "taxonomy-#{taxonomy_filter.root_taxonomy_id}")
    end
    if component_settings.official_proposals_enabled
      items.append(method: :with_any_origin, collection: filter_origin_values, label: t("decidim.proposals.proposals.filters.origin"), id: "origin")
    end
    if current_user
      items.append(method: :activity, collection: activity_filter_values, label: t("decidim.proposals.proposals.filters.activity"), id: "activity", type: :radio_buttons)
    end
    if @proposals.only_emendations.any?
      items.append(method: :type, collection: filter_type_values, label: t("decidim.proposals.proposals.filters.amendment_type"), 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: t("decidim.proposals.proposals.filters.related_to"),
        id: "related_to",
        type: :radio_buttons
      )
    end
  end
  # rubocop:enable Metrics/CyclomaticComplexity
  items.reject { |item| item[:collection].blank? }
end

#filter_type_valuesObject



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

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.



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

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.



25
26
27
# File 'app/helpers/decidim/proposals/application_helper.rb', line 25

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

#layout_item_classesObject



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

def layout_item_classes
  if show_voting_rules?
    "layout-item lg:pt-4"
  else
    "layout-item"
  end
end

#not_from_collaborative_draft(proposal) ⇒ Object



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

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

#not_from_participatory_text(proposal) ⇒ Object



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

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

#proposal_limitObject



128
129
130
131
132
# File '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)


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

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.



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

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



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

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.



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

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)


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

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)


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

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

#show_voting_rules?Boolean

Returns:

  • (Boolean)


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

def show_voting_rules?
  return false if !votes_enabled? || 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

#templates_available?Boolean

Returns:

  • (Boolean)


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

def templates_available?
  Decidim.module_installed?(:templates) && defined?(Decidim::Templates::Template) && Decidim::Templates::Template.exists?(templatable: current_component)
end

#text_editor_for_proposal_body(form) ⇒ Object

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



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

def text_editor_for_proposal_body(form)
  options = {
    value: form_presenter.body(strip_tags: !current_organization.rich_text_editor_in_public_views).strip,
    data: { controller: "character-counter" }
  }

  text_editor_for(form, :body, options)
end