Merge pull request #6061 from consuldemocracy/poll_text_answers
Add support for essay poll questions
This commit is contained in:
@@ -2,16 +2,18 @@
|
||||
"use strict";
|
||||
App.AdminVotationTypesFields = {
|
||||
adjustForm: function() {
|
||||
if ($(this).val() === "unique") {
|
||||
$(".max-votes").hide();
|
||||
$(".description-unique").show();
|
||||
$(".description-multiple").hide();
|
||||
$(".votation-type-max-votes").prop("disabled", true);
|
||||
} else {
|
||||
var select_field = $(this);
|
||||
|
||||
$("[data-vote-type]").hide(0, function() {
|
||||
$("[data-vote-type=" + select_field.val() + "]").show();
|
||||
});
|
||||
|
||||
if (select_field.val() === "multiple") {
|
||||
$(".max-votes").show();
|
||||
$(".description-unique").hide();
|
||||
$(".description-multiple").show();
|
||||
$(".votation-type-max-votes").prop("disabled", false);
|
||||
} else {
|
||||
$(".max-votes").hide();
|
||||
$(".votation-type-max-votes").prop("disabled", true);
|
||||
}
|
||||
},
|
||||
initialize: function() {
|
||||
|
||||
@@ -1,33 +1,42 @@
|
||||
.poll-form {
|
||||
fieldset {
|
||||
fieldset,
|
||||
.poll-question-open-ended {
|
||||
border: 1px solid $border;
|
||||
border-radius: $global-radius;
|
||||
padding: $line-height;
|
||||
}
|
||||
|
||||
fieldset + fieldset {
|
||||
margin-top: calc($line-height / 2);
|
||||
}
|
||||
|
||||
legend {
|
||||
@include header-font-size(h3);
|
||||
float: $global-left;
|
||||
margin-bottom: 0;
|
||||
|
||||
+ * {
|
||||
clear: $global-left;
|
||||
margin-top: calc($line-height / 2);
|
||||
}
|
||||
}
|
||||
|
||||
fieldset {
|
||||
legend {
|
||||
@include header-font-size(h3);
|
||||
float: $global-left;
|
||||
margin-bottom: 0;
|
||||
|
||||
label {
|
||||
@include radio-or-checkbox-and-label-alignment;
|
||||
font-weight: normal;
|
||||
+ * {
|
||||
clear: $global-left;
|
||||
}
|
||||
}
|
||||
|
||||
&:first-of-type::before {
|
||||
content: "\A";
|
||||
margin-top: calc($line-height / 2);
|
||||
white-space: pre;
|
||||
label {
|
||||
@include radio-or-checkbox-and-label-alignment;
|
||||
font-weight: normal;
|
||||
|
||||
&:first-of-type::before {
|
||||
content: "\A";
|
||||
margin-top: calc($line-height / 2);
|
||||
white-space: pre;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.poll-question-open-ended {
|
||||
label {
|
||||
@include header-font-size(h3);
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,9 @@
|
||||
|
||||
<div class="small-12 column">
|
||||
<div class="callout primary">
|
||||
<span class="description-unique">
|
||||
<%= t("admin.polls.votation_type.unique_description") %>
|
||||
</span>
|
||||
<span class="description-multiple hidden">
|
||||
<%= t("admin.polls.votation_type.multiple_description") %>
|
||||
</span>
|
||||
<% descriptions.each do |vote_type, text| %>
|
||||
<%= description_tag(vote_type, text) %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -4,4 +4,18 @@ class Admin::VotationTypes::FieldsComponent < ApplicationComponent
|
||||
def initialize(form:)
|
||||
@form = form
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def descriptions
|
||||
{
|
||||
unique: t("admin.polls.votation_type.unique_description"),
|
||||
multiple: t("admin.polls.votation_type.multiple_description"),
|
||||
open: t("admin.polls.votation_type.open_description")
|
||||
}
|
||||
end
|
||||
|
||||
def description_tag(vote_type, text)
|
||||
tag.span(text, data: { vote_type: vote_type })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% poll.questions.each do |question| %>
|
||||
<% poll.questions.for_physical_votes.each do |question| %>
|
||||
<fieldset class="row">
|
||||
<legend class="column"><%= question.title %></legend>
|
||||
<% question.question_options.each_with_index do |option, i| %>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<% @poll.questions.each do |question| %>
|
||||
<% @poll.questions.for_physical_votes.each do |question| %>
|
||||
<%= render Admin::Poll::Results::QuestionComponent.new(question, @partial_results) %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -8,13 +8,9 @@
|
||||
</div>
|
||||
|
||||
<div class="poll-info">
|
||||
<% if poll.questions.one? %>
|
||||
<h4><%= link_to_poll poll.questions.first.title, poll %></h4>
|
||||
<div class="dates"><%= dates %></div>
|
||||
<% else %>
|
||||
<h4><%= link_to_poll poll.name, poll %></h4>
|
||||
<div class="dates"><%= dates %></div>
|
||||
|
||||
<h4><%= link_to header_text, path %></h4>
|
||||
<div class="dates"><%= dates %></div>
|
||||
<% if poll.questions.many? %>
|
||||
<ul class="margin-top">
|
||||
<% poll.questions.sort_for_list.each do |question| %>
|
||||
<li><%= question.title %></li>
|
||||
@@ -25,9 +21,5 @@
|
||||
<%= render SDG::TagListComponent.new(poll, limit: 5, linkable: false) %>
|
||||
</div>
|
||||
|
||||
<% if poll.expired? %>
|
||||
<%= link_to_poll t("polls.index.participate_button_expired"), poll, class: "button hollow expanded" %>
|
||||
<% else %>
|
||||
<%= link_to_poll t("polls.index.participate_button"), poll, class: "button hollow expanded" %>
|
||||
<% end %>
|
||||
<%= link_to link_text, path, class: "button hollow expanded" %>
|
||||
</div>
|
||||
|
||||
@@ -12,13 +12,29 @@ class Polls::PollComponent < ApplicationComponent
|
||||
t("polls.dates", open_at: l(poll.starts_at.to_date), closed_at: l(poll.ends_at.to_date))
|
||||
end
|
||||
|
||||
def link_to_poll(text, poll, options = {})
|
||||
if can?(:results, poll)
|
||||
link_to text, results_poll_path(id: poll.slug || poll.id), options
|
||||
elsif can?(:stats, poll)
|
||||
link_to text, stats_poll_path(id: poll.slug || poll.id), options
|
||||
def header_text
|
||||
if poll.questions.one?
|
||||
poll.questions.first.title
|
||||
else
|
||||
link_to text, poll_path(id: poll.slug || poll.id), options
|
||||
poll.name
|
||||
end
|
||||
end
|
||||
|
||||
def link_text
|
||||
if poll.expired?
|
||||
t("polls.index.participate_button_expired")
|
||||
else
|
||||
t("polls.index.participate_button")
|
||||
end
|
||||
end
|
||||
|
||||
def path
|
||||
if can?(:results, poll)
|
||||
results_poll_path(id: poll.slug || poll.id)
|
||||
elsif can?(:stats, poll)
|
||||
stats_poll_path(id: poll.slug || poll.id)
|
||||
else
|
||||
poll_path(id: poll.slug || poll.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,23 +1,31 @@
|
||||
<fieldset <%= fieldset_attributes %>>
|
||||
<legend><%= question.title %></legend>
|
||||
|
||||
<% if multiple_choice? %>
|
||||
<%= multiple_choice_help_text %>
|
||||
|
||||
<% question.question_options.each do |option| %>
|
||||
<%= multiple_choice_field(option) %>
|
||||
<% if question.open? %>
|
||||
<div class="poll-question-open-ended">
|
||||
<%= fields_for "web_vote[#{question.id}]" do |f| %>
|
||||
<%= f.text_area :answer, label: question.title, value: existing_answer, rows: 3 %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% question.question_options.each do |option| %>
|
||||
<%= single_choice_field(option) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<fieldset <%= fieldset_attributes %>>
|
||||
<legend><%= question.title %></legend>
|
||||
|
||||
<% if question.options_with_read_more? %>
|
||||
<div class="read-more-links">
|
||||
<p><%= t("poll_questions.read_more_about") %></p>
|
||||
<p><%= options_read_more_links %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= form.error_for(:"question_#{question.id}") %>
|
||||
</fieldset>
|
||||
<% if multiple_choice? %>
|
||||
<%= multiple_choice_help_text %>
|
||||
|
||||
<% question.question_options.each do |option| %>
|
||||
<%= multiple_choice_field(option) %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% question.question_options.each do |option| %>
|
||||
<%= single_choice_field(option) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if question.options_with_read_more? %>
|
||||
<div class="read-more-links">
|
||||
<p><%= t("poll_questions.read_more_about") %></p>
|
||||
<p><%= options_read_more_links %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= form.error_for(:"question_#{question.id}") %>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
|
||||
@@ -33,6 +33,10 @@ class Polls::Questions::QuestionComponent < ApplicationComponent
|
||||
end, ", ")
|
||||
end
|
||||
|
||||
def existing_answer
|
||||
form.object.answers[question.id]&.first&.answer
|
||||
end
|
||||
|
||||
def multiple_choice?
|
||||
question.multiple?
|
||||
end
|
||||
|
||||
@@ -1,25 +1,46 @@
|
||||
<h3 id="<%= question.title.parameterize %>"><%= question.title %></h3>
|
||||
<table id="question_<%= question.id %>_results_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<%- question.question_options.each do |option| %>
|
||||
<th scope="col" class="<%= option_styles(option) %>">
|
||||
<% if most_voted_option?(option) %>
|
||||
<span class="show-for-sr"><%= t("polls.show.results.most_voted_answer") %></span>
|
||||
<% end %>
|
||||
<%= option.title %>
|
||||
</th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<%- question.question_options.each do |option| %>
|
||||
<td id="option_<%= option.id %>_result" class="<%= option_styles(option) %>">
|
||||
<%= option.total_votes %>
|
||||
(<%= option.total_votes_percentage.round(2) %>%)
|
||||
<% if question.accepts_options? %>
|
||||
<thead>
|
||||
<tr>
|
||||
<%- question.question_options.each do |option| %>
|
||||
<th scope="col" class="<%= option_styles(option) %>">
|
||||
<% if most_voted_option?(option) %>
|
||||
<span class="show-for-sr"><%= t("polls.show.results.most_voted_answer") %></span>
|
||||
<% end %>
|
||||
<%= option.title %>
|
||||
</th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<%- question.question_options.each do |option| %>
|
||||
<td class="<%= option_styles(option) %>">
|
||||
<%= option.total_votes %>
|
||||
(<%= option.total_votes_percentage.round(2) %>%)
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
</tbody>
|
||||
<% else %>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"><%= t("polls.show.results.open_ended.valid") %></th>
|
||||
<th scope="col"><%= t("polls.show.results.open_ended.blank") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<%= question.open_ended_valid_answers_count %>
|
||||
(<%= question.open_ended_valid_percentage.round(2) %>%)
|
||||
</td>
|
||||
<% end %>
|
||||
</tr>
|
||||
</tbody>
|
||||
<td>
|
||||
<%= question.open_ended_blank_answers_count %>
|
||||
(<%= question.open_ended_blank_percentage.round(2) %>%)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Polls::Results::QuestionComponent < ApplicationComponent
|
||||
attr_reader :question
|
||||
|
||||
def initialize(question:)
|
||||
def initialize(question)
|
||||
@question = question
|
||||
end
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="polls-results">
|
||||
<%= render Polls::PollHeaderComponent.new(poll) %>
|
||||
|
||||
<%= render "poll_subnav" %>
|
||||
<%= render "polls/poll_subnav" %>
|
||||
|
||||
<div class="polls-results-content">
|
||||
<div>
|
||||
@@ -16,7 +16,9 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<%= render Polls::Results::QuestionComponent.with_collection(poll.questions) %>
|
||||
<% poll.questions.each do |question| %>
|
||||
<%= render Polls::Results::QuestionComponent.new(question) %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -101,7 +101,7 @@ module Abilities
|
||||
end
|
||||
can [:read, :order_options], Poll::Question::Option
|
||||
can [:create, :update, :destroy], Poll::Question::Option do |option|
|
||||
can?(:update, option.question)
|
||||
can?(:update, option.question) && option.question.accepts_options?
|
||||
end
|
||||
can :read, Poll::Question::Option::Video
|
||||
can [:create, :update, :destroy], Poll::Question::Option::Video do |video|
|
||||
|
||||
@@ -9,21 +9,9 @@ class Poll::Answer < ApplicationRecord
|
||||
validates :author, presence: true
|
||||
validates :answer, presence: true
|
||||
validates :option, uniqueness: { scope: :author_id }, allow_nil: true
|
||||
validate :max_votes
|
||||
|
||||
validates :answer, inclusion: { in: ->(poll_answer) { poll_answer.option.possible_answers }},
|
||||
if: ->(poll_answer) { poll_answer.option.present? }
|
||||
|
||||
scope :by_author, ->(author_id) { where(author_id: author_id) }
|
||||
scope :by_question, ->(question_id) { where(question_id: question_id) }
|
||||
|
||||
private
|
||||
|
||||
def max_votes
|
||||
return if !question || !author || persisted?
|
||||
|
||||
if question.answers.by_author(author).count >= question.max_votes
|
||||
errors.add(:answer, "Maximum number of votes per user exceeded")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,10 +27,11 @@ class Poll::Question < ApplicationRecord
|
||||
accepts_nested_attributes_for :question_options, reject_if: :all_blank, allow_destroy: true
|
||||
accepts_nested_attributes_for :votation_type
|
||||
|
||||
delegate :multiple?, :vote_type, to: :votation_type, allow_nil: true
|
||||
delegate :multiple?, :open?, :vote_type, to: :votation_type, allow_nil: true
|
||||
|
||||
scope :sort_for_list, -> { order(Arel.sql("poll_questions.proposal_id IS NULL"), :created_at) }
|
||||
scope :for_render, -> { includes(:author, :proposal) }
|
||||
scope :for_physical_votes, -> { left_joins(:votation_type).merge(VotationType.accepts_options) }
|
||||
|
||||
def copy_attributes_from_proposal(proposal)
|
||||
if proposal.present?
|
||||
@@ -61,6 +62,10 @@ class Poll::Question < ApplicationRecord
|
||||
votation_type.nil? || votation_type.unique?
|
||||
end
|
||||
|
||||
def accepts_options?
|
||||
votation_type.nil? || votation_type.accepts_options?
|
||||
end
|
||||
|
||||
def max_votes
|
||||
if multiple?
|
||||
votation_type.max_votes
|
||||
@@ -69,23 +74,51 @@ class Poll::Question < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def find_or_initialize_user_answer(user, option_id)
|
||||
option = question_options.find(option_id)
|
||||
def find_or_initialize_user_answer(user, option_id: nil, answer_text: nil)
|
||||
answer = answers.find_or_initialize_by(find_by_attributes(user, option_id))
|
||||
|
||||
if accepts_options?
|
||||
option = question_options.find(option_id)
|
||||
answer.option = option
|
||||
answer.answer = option.title
|
||||
else
|
||||
answer.answer = answer_text
|
||||
end
|
||||
|
||||
answer = answers.find_or_initialize_by(find_by_attributes(user, option))
|
||||
answer.option = option
|
||||
answer.answer = option.title
|
||||
answer
|
||||
end
|
||||
|
||||
def open_ended_valid_answers_count
|
||||
answers.count
|
||||
end
|
||||
|
||||
def open_ended_blank_answers_count
|
||||
poll.voters.count - open_ended_valid_answers_count
|
||||
end
|
||||
|
||||
def open_ended_valid_percentage
|
||||
return 0.0 if open_ended_total_answers.zero?
|
||||
|
||||
(open_ended_valid_answers_count * 100.0) / open_ended_total_answers
|
||||
end
|
||||
|
||||
def open_ended_blank_percentage
|
||||
return 0.0 if open_ended_total_answers.zero?
|
||||
|
||||
(open_ended_blank_answers_count * 100.0) / open_ended_total_answers
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_by_attributes(user, option)
|
||||
case vote_type
|
||||
when "unique", nil
|
||||
def find_by_attributes(user, option_id)
|
||||
if multiple?
|
||||
{ author: user, option_id: option_id }
|
||||
else
|
||||
{ author: user }
|
||||
when "multiple"
|
||||
{ author: user, answer: option.title }
|
||||
end
|
||||
end
|
||||
|
||||
def open_ended_total_answers
|
||||
open_ended_valid_answers_count + open_ended_blank_answers_count
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,8 +63,17 @@ class Poll::WebVote
|
||||
def answers_for_question(question, question_params)
|
||||
return [] unless question_params
|
||||
|
||||
Array(question_params[:option_id]).map do |option_id|
|
||||
question.find_or_initialize_user_answer(user, option_id)
|
||||
if question.open?
|
||||
answer_text = question_params[:answer].to_s.strip
|
||||
if answer_text.present?
|
||||
[question.find_or_initialize_user_answer(user, answer_text: answer_text)]
|
||||
else
|
||||
[]
|
||||
end
|
||||
else
|
||||
Array(question_params[:option_id]).map do |option_id|
|
||||
question.find_or_initialize_user_answer(user, option_id: option_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,17 +1,31 @@
|
||||
class VotationType < ApplicationRecord
|
||||
belongs_to :questionable, polymorphic: true
|
||||
|
||||
validate :cannot_be_open_ended_if_question_has_options
|
||||
|
||||
QUESTIONABLE_TYPES = %w[Poll::Question].freeze
|
||||
|
||||
enum :vote_type, { unique: 0, multiple: 1 }
|
||||
enum :vote_type, { unique: 0, multiple: 1, open: 2 }
|
||||
|
||||
validates :questionable, presence: true
|
||||
validates :questionable_type, inclusion: { in: ->(*) { QUESTIONABLE_TYPES }}
|
||||
validates :max_votes, presence: true, if: :max_votes_required?
|
||||
|
||||
scope :accepts_options, -> { where.not(vote_type: "open") }
|
||||
|
||||
def accepts_options?
|
||||
!open?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def max_votes_required?
|
||||
multiple?
|
||||
end
|
||||
|
||||
def cannot_be_open_ended_if_question_has_options
|
||||
if questionable&.question_options&.any? && !accepts_options?
|
||||
errors.add(:vote_type, :cannot_change_to_open_ended)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<br>
|
||||
<%= VotationType.human_attribute_name("vote_type.#{@question.vote_type}") %>
|
||||
</p>
|
||||
<% if @question.max_votes.present? %>
|
||||
<% if @question.multiple? %>
|
||||
<p>
|
||||
<strong><%= VotationType.human_attribute_name("max_votes") %></strong>
|
||||
<br>
|
||||
@@ -46,57 +46,59 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clear">
|
||||
<% if can?(:create, Poll::Question::Option.new(question: @question)) %>
|
||||
<%= link_to t("admin.questions.show.add_answer"), new_admin_question_option_path(@question),
|
||||
class: "button float-right" %>
|
||||
<% else %>
|
||||
<div class="callout warning">
|
||||
<strong><%= t("admin.questions.no_edit") %></strong>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<table class="margin-top">
|
||||
<caption><%= t("admin.questions.show.valid_answers") %></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.questions.show.answers.title") %></th>
|
||||
<th scope="col" class="medium-7"><%= t("admin.questions.show.answers.description") %></th>
|
||||
<th scope="col" class="text-center"><%= t("admin.questions.show.answers.images") %></th>
|
||||
<th scope="col" class="text-center"><%= t("admin.questions.show.answers.documents") %></th>
|
||||
<th scope="col" class="text-center"><%= t("admin.questions.show.answers.videos") %></th>
|
||||
<th><%= t("admin.actions.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="sortable" data-js-url="<%= admin_question_options_order_options_path(@question.id) %>">
|
||||
<% @question.question_options.each do |option| %>
|
||||
<tr id="<%= dom_id(option) %>" class="poll_question_option" data-option-id="<%= option.id %>">
|
||||
<td class="align-top"><%= option.title %></td>
|
||||
<td class="align-top break"><%= wysiwyg(option.description) %></td>
|
||||
<td class="align-top text-center">
|
||||
(<%= option.images.count %>)
|
||||
<br>
|
||||
<%= link_to t("admin.questions.show.answers.images_list"),
|
||||
admin_option_images_path(option) %>
|
||||
</td>
|
||||
<td class="align-top text-center">
|
||||
(<%= option.documents.count rescue 0 %>)
|
||||
<br>
|
||||
<%= link_to t("admin.questions.show.answers.documents_list"),
|
||||
admin_option_documents_path(option) %>
|
||||
</td>
|
||||
<td class="align-top text-center">
|
||||
(<%= option.videos.count %>)
|
||||
<br>
|
||||
<%= link_to t("admin.questions.show.answers.video_list"),
|
||||
admin_option_videos_path(option) %>
|
||||
</td>
|
||||
<td>
|
||||
<%= render Admin::Poll::Questions::Options::TableActionsComponent.new(option) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% if @question.accepts_options? %>
|
||||
<div class="clear">
|
||||
<% if can?(:create, Poll::Question::Option.new(question: @question)) %>
|
||||
<%= link_to t("admin.questions.show.add_answer"), new_admin_question_option_path(@question),
|
||||
class: "button float-right" %>
|
||||
<% else %>
|
||||
<div class="callout warning">
|
||||
<strong><%= t("admin.questions.no_edit") %></strong>
|
||||
</div>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<table class="margin-top">
|
||||
<caption><%= t("admin.questions.show.valid_answers") %></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.questions.show.answers.title") %></th>
|
||||
<th scope="col" class="medium-7"><%= t("admin.questions.show.answers.description") %></th>
|
||||
<th scope="col" class="text-center"><%= t("admin.questions.show.answers.images") %></th>
|
||||
<th scope="col" class="text-center"><%= t("admin.questions.show.answers.documents") %></th>
|
||||
<th scope="col" class="text-center"><%= t("admin.questions.show.answers.videos") %></th>
|
||||
<th><%= t("admin.actions.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="sortable" data-js-url="<%= admin_question_options_order_options_path(@question.id) %>">
|
||||
<% @question.question_options.each do |option| %>
|
||||
<tr id="<%= dom_id(option) %>" class="poll_question_option" data-option-id="<%= option.id %>">
|
||||
<td class="align-top"><%= option.title %></td>
|
||||
<td class="align-top break"><%= wysiwyg(option.description) %></td>
|
||||
<td class="align-top text-center">
|
||||
(<%= option.images.count %>)
|
||||
<br>
|
||||
<%= link_to t("admin.questions.show.answers.images_list"),
|
||||
admin_option_images_path(option) %>
|
||||
</td>
|
||||
<td class="align-top text-center">
|
||||
(<%= option.documents.count rescue 0 %>)
|
||||
<br>
|
||||
<%= link_to t("admin.questions.show.answers.documents_list"),
|
||||
admin_option_documents_path(option) %>
|
||||
</td>
|
||||
<td class="align-top text-center">
|
||||
(<%= option.videos.count %>)
|
||||
<br>
|
||||
<%= link_to t("admin.questions.show.answers.video_list"),
|
||||
admin_option_videos_path(option) %>
|
||||
</td>
|
||||
<td>
|
||||
<%= render Admin::Poll::Questions::Options::TableActionsComponent.new(option) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
Reference in New Issue
Block a user