diff --git a/app/controllers/answers_controller.rb b/app/controllers/answers_controller.rb index 7d48ddf..e66bd66 100644 --- a/app/controllers/answers_controller.rb +++ b/app/controllers/answers_controller.rb @@ -36,9 +36,24 @@ @question = @answer.question @section = @plan.get_section(@question.section_id) - respond_to do |format| - format.js {} - end + render json: { + "question" => { + "id" => @question.id, + "answer_lock_version" => @answer.lock_version, + "locking" => @stale_answer ? + render_to_string(partial: 'answers/locking', locals: { question: @question, answer: @stale_answer, user: @answer.user }, formats: [:html]) : + nil, + "answer_status" => render_to_string(partial: 'answers/status', locals: { answer: @answer}, formats: [:html]) + }, + "section" => { + "id" => @section.id, + "progress" => render_to_string(partial: '/sections/progress', locals: { section: @section, plan: @plan }, formats: [:html]) + }, + "plan" => { + "id" => @plan.id, + "progress" => render_to_string(:partial => 'plans/progress', locals: { plan: @plan }, formats: [:html]) + } + }.to_json end # End update private diff --git a/app/views/answers/_new_edit.html.erb b/app/views/answers/_new_edit.html.erb index 5706833..0aa8384 100644 --- a/app/views/answers/_new_edit.html.erb +++ b/app/views/answers/_new_edit.html.erb @@ -1,86 +1,22 @@ -<% q_format = question.question_format %> -<%= form_for answer, url: {controller: :answers, action: :update}, html: {method: :put, class: "roadmap-form answer", 'data-autosave': question.id}, remote: true do |f| %> -
- <% if !readonly %> - <%= f.hidden_field :id %> - <%= f.hidden_field :plan_id %> - <%= f.hidden_field :user_id %> - <%= f.hidden_field :question_id %> - <%= f.hidden_field :lock_version %> - <% end %> - -
- +<%= form_for answer, url: {controller: :answers, action: :update}, html: {method: :put, 'data-autosave': question.id, class: 'form-answer' } do |f| %> + <% if !readonly %> + <%= f.hidden_field :id %> + <%= f.hidden_field :plan_id %> + <%= f.hidden_field :user_id %> + <%= f.hidden_field :question_id %> + <%= f.hidden_field :lock_version %> + <% end %> +
<% if question.option_based? %> - <%= f.label raw(question.text), for: :question_option_ids %> - <% else %> - <%= f.label raw(question.text), for: :text %> + <%= render(partial: 'questions/new_edit_question_option_based', locals: { f: f, question: question, answer: answer, readonly: @readonly }) %> + <% elsif question.question_format.textfield?%> + <%= render(partial: 'questions/new_edit_question_textfield', locals: { f: f, question: question, answer: answer, readonly: @readonly }) %> + <% elsif question.question_format.textarea? %> + <%= render(partial: 'questions/new_edit_question_textarea', locals: { f: f, question: question, answer: answer, readonly: @readonly }) %> <% end %> - - <% if question.option_based? %> - <% options = question.question_options.by_number %> - <% if q_format.checkbox? %> -
    - <% options.each do |op| %> -
  1. - <%= f.check_box(:question_option_ids, { multiple: true, checked: answer.has_question_option(op.id), disabled: readonly }, op.id, nil) %> - <%= raw op.text %> -
  2. - <% end %> -
- <% elsif q_format.radiobuttons? %> -
    - <% options.each do |op| %> -
  1. - <%= f.radio_button :question_option_ids, op.id, { checked: answer.has_question_option(op.id), id: "answer_option_ids_#{op.id}", disabled: readonly } %> - <%= raw op.text %> -
  2. - <% end %> -
- <% elsif q_format.dropdown? || q_format.multiselectbox? %> - <% - options_html = "" - options.each do |op| - options_html += answer.has_question_option(op.id) ? - "" : - "" - end - %> - <%= select_tag('answer[question_option_ids]', raw(options_html), - {multiple: q_format.multiselectbox?, include_blank: q_format.dropdown?, disabled: readonly }) %> - <% end %> - - <% if question.option_comment_display == true %> - <%= label_tag('answer[text]', _('Comment')) %> - <% if readonly %> -

<%= raw(answer.text) %>

- <% else %> - <%= text_area_tag('answer[text]', answer.text, id: "answer-text-#{question.id}", class: "tinymce_answer") %> - <% end %> - <%end%> - - - <% elsif q_format.textfield? %> - <% if readonly %> -

<%= strip_tags(answer.text) %>

- <% else %> - <%= text_field_tag('answer[text]', strip_tags(answer.text)) %> - <% end %> - - <% elsif q_format.textarea? %> - <% if readonly %> -

<%= raw(answer.text) %>

- <% else %> - <%= text_area_tag('answer[text]', answer.text, id: "answer-text-#{question.id}", class: "tinymce_answer") %> - <% end %> - <% end %> - - <%= - raw("") - %> <% if !readonly && question.annotations.where(type: Annotation.types[:example_answer]).any? %> <% annotation = question.annotations.where(type: Annotation.types[:example_answer]).order(:created_at).first %> @@ -96,16 +32,8 @@
<% end %> <% end %> - -
- -
- <% if !readonly %> - - <% end %> -
" class="answer-status inline left-indent"> - <%= render(partial: 'answers/status', locals: { answer: answer }) %> -
-
+ <% if !readonly %> + <%= f.button(_('Save'), class: "btn btn-default", type: "submit") %> + <% end %> <% end %> \ No newline at end of file diff --git a/app/views/answers/_status.html.erb b/app/views/answers/_status.html.erb index c0fdfcc..4405d65 100644 --- a/app/views/answers/_status.html.erb +++ b/app/views/answers/_status.html.erb @@ -1,8 +1,13 @@ - -
+ <% if answer.updated_at.blank? %> - <%= _('Not answered yet') %> +

+ <%= _('Not answered yet') %> +

<% else %> - <%= _('Answered')%> <%= answer.updated_at.iso8601 %><%= _(' by')%> <%= answer.user.name %> +

+ <%= _('Answered')%> <%= answer.updated_at.iso8601 %><%= _(' by')%> <%= answer.user.name %> +

<% end %> \ No newline at end of file diff --git a/app/views/answers/update.js.erb b/app/views/answers/update.js.erb deleted file mode 100644 index d1dd1fe..0000000 --- a/app/views/answers/update.js.erb +++ /dev/null @@ -1,24 +0,0 @@ -// partial /answers/locking -<% if @stale_answer %> - $("#answer-locking-<%= @question.id%>") - .html("<%= escape_javascript(render partial: '/answers/locking', locals: { question: @question, answer: @stale_answer, user: @answer.user }) %>"); -<% else %> - $("#answer-locking-<%= @question.id%>").html(""); -<% end %> -// Destroys a tinymce editor whose id is defined below -dmproadmap.utils.tinymce.destroyEditorById('<%= "answer-text-#{@question.id}" %>'); -// partial /answer/new_edit -$("#answer-form-<%= @question.id%>") - .html("<%= escape_javascript(render partial: '/answers/new_edit', locals: { question: @question, answer: @answer, readonly: false }) %>"); -// Adds listeners for a tinyMCE editor with target element id passed -dmproadmap.answers.status.reloadEditorListeners('<%= "answer-text-#{@question.id}" %>'); -// partial /answer/status -$("#answer-status-<%= @question.id %>") - .html("<%= escape_javascript(render partial: '/answers/status', locals: { answer: @answer}) %>"); - -// partial /plans/progress -$(".progress").html("<%= escape_javascript(render :partial => '/plans/progress', locals: { plan: @plan }) %>"); - -// partial /sections/progress -$(".progress-bar-<%= @section.id %>") - .html("<%= escape_javascript(render partial: '/sections/progress', locals: { section: @section, plan: @plan }) %>"); \ No newline at end of file diff --git a/app/views/layouts/_es5_scripts.html.erb b/app/views/layouts/_es5_scripts.html.erb index b00fd5d..f473d97 100644 --- a/app/views/layouts/_es5_scripts.html.erb +++ b/app/views/layouts/_es5_scripts.html.erb @@ -9,7 +9,7 @@ <%= javascript_include_tag 'jquery.tablesorter.min.js' %> <%= javascript_include_tag 'jquery.tablesorter.widgets.min.js' %> <%= javascript_include_tag 'jquery.timeago.js' %> - <%= javascript_include_tag 'bootstrap.min.js' %> + <%#= javascript_include_tag 'bootstrap.min.js' %> @@ -30,7 +30,6 @@ - <%= javascript_include_tag 'views/answers/status.js' %> <%= javascript_include_tag 'views/guidances/admin_edit.js' %> <%= javascript_include_tag 'views/home/index.js' %> <%= javascript_include_tag 'views/notes/add.js' %> diff --git a/app/views/phases/_edit_plan_answers.html.erb b/app/views/phases/_edit_plan_answers.html.erb new file mode 100644 index 0000000..1a9d52e --- /dev/null +++ b/app/views/phases/_edit_plan_answers.html.erb @@ -0,0 +1,90 @@ +
+
+
+ +
+
+ <%= render :partial => "/plans/progress", locals: { plan: @plan } %> +
+
+
+
+ <% @phase.sections.order(:number).each do |section| %> + <% sectionid = section.id %> +
+ +
+
+
+
<%= raw section.description %>
+ + + + <% section.questions.each do |question| %> + <% # Load the answer or create a new one + answers = question.plan_answers(@plan.id) + if answers.present? + answer = answers.first + else + answer = Answer.new({plan_id: @plan.id, question_id: question.id, user_id: current_user.id }) + if question.default_value.present? + answer.text = question.default_value + end + end + %> +
+
+ +
+
" class="answer-locking">
+ <%= render(partial: 'answers/new_edit', locals: { question: question, answer: answer, readonly: @readonly }) %> +
"> + <%= render(partial: 'answers/status', locals: { answer: answer }) %> +
+
+
+
+ + <%= render partial: 'guidance_section', locals: {plan: @plan, question: question, answer: answer, question_guidances: @question_guidances} %> +
+
+ <% end %> +
+
+ <% end %> +
+ +
+
\ No newline at end of file diff --git a/app/views/phases/edit.html.erb b/app/views/phases/edit.html.erb index c0c5859..92b5bb6 100644 --- a/app/views/phases/edit.html.erb +++ b/app/views/phases/edit.html.erb @@ -1,149 +1,11 @@ - -
-

<%= @plan.title %>

-
- - - - -
-
- -
- - -
- <%= render :partial => "/plans/progress", locals: { plan: @plan } %> -
-
- -
- <% @phase.sections.order(:number).each do |section| %> - <% sectionid = section.id %> - -
- -
- -
-
- -
<%= raw section.description %>
- - - - - -
- <% section.questions.each do |question| %> - <% if question.id == session[:question_id_comments].to_i then id_css = "current_question" end %> -
- - <% - # Load the answer or create a new one - answers = question.plan_answers(@plan.id) - if answers.present? - answer = answers.first - else - answer = Answer.new({plan_id: @plan.id, - question_id: question.id, - user_id: current_user.id }) - if question.default_value.present? - answer.text = question.default_value - end - end - %> - - -
-
-
" class="answer-locking">
-
"> - <%= render(partial: 'answers/new_edit', - locals: { question: question, answer: answer, readonly: @readonly }) %> -
-
-
- - - -
- <%= render partial: 'guidance_section', - locals: {plan: @plan, question: question, answer: answer, - question_guidances: @question_guidances} %> -
-
- <% end %> - -
- -
-
- - <% end %> -
- - -
-
-
+ <%= render partial: 'edit_plan_answers', layout: 'shared/plan_navigation', locals: {} %>
-
\ No newline at end of file + \ No newline at end of file diff --git a/app/views/plans/_progress.html.erb b/app/views/plans/_progress.html.erb index db2542a..e95f0b9 100644 --- a/app/views/plans/_progress.html.erb +++ b/app/views/plans/_progress.html.erb @@ -1,9 +1,11 @@ <% nanswers = plan.num_answered_questions() nquestions = plan.num_questions() + value=(nanswers.to_f/nquestions*100).round(2) %> -<% answered = %(#{nanswers}/#{nquestions})%> -
-
 
- <%= answered -%> <%= _(' answered')%> +
;"> + <%= "#{value} % #{_('answered')}" %>
diff --git a/app/views/questions/_new_edit_question_option_based.html.erb b/app/views/questions/_new_edit_question_option_based.html.erb new file mode 100644 index 0000000..7a5a0c1 --- /dev/null +++ b/app/views/questions/_new_edit_question_option_based.html.erb @@ -0,0 +1,48 @@ +<% options = question.question_options.by_number %> +<% if question.question_format.checkbox? %> + <%= f.label(:question_option_ids, raw(question.text), class: 'control-label') %> + <% options.each do |op| %> +
+ +
+ <% end %> +<% elsif question.question_format.radiobuttons? %> + <%= f.label(:question_option_ids, raw(question.text), class: 'control-label') %> + <% options.each do |op| %> +
+ +
+ <% end %> +<% elsif question.question_format.dropdown? || question.question_format.multiselectbox? %> + <% + options_html = "" + options.each do |op| + options_html += answer.has_question_option(op.id) ? + "" : + "" + end + %> + <%= f.label(:question_option_ids, raw(question.text), class: 'control-label') %> + <%= select_tag('answer[question_option_ids]', + raw(options_html), + { multiple: question.question_format.multiselectbox?, + include_blank: question.question_format.dropdown?, + disabled: readonly, + class: 'form-control' }) %> +<% end %> +
+<% if question.option_comment_display %> + <%= label_tag('answer[text]', _('Comment'), class: 'control-label') %> + <% if readonly %> +

<%= raw(answer.text) %>

+ <% else %> + <%= text_area_tag('answer[text]', answer.text, id: "answer-text-#{question.id}", class: "form-control tinymce_answer") %> + <% end %> +<% end %> +
diff --git a/app/views/questions/_new_edit_question_textarea.html.erb b/app/views/questions/_new_edit_question_textarea.html.erb new file mode 100644 index 0000000..c390574 --- /dev/null +++ b/app/views/questions/_new_edit_question_textarea.html.erb @@ -0,0 +1,8 @@ +
+ <%= f.label(:text, raw(question.text), class: 'control-label') %> + <% if readonly %> +

<%= raw(answer.text) %>

+ <% else %> + <%= text_area_tag('answer[text]', answer.text, id: "answer-text-#{question.id}", class: "form-control tinymce_answer") %> + <% end %> +
\ No newline at end of file diff --git a/app/views/questions/_new_edit_question_textfield.html.erb b/app/views/questions/_new_edit_question_textfield.html.erb new file mode 100644 index 0000000..b1dbd95 --- /dev/null +++ b/app/views/questions/_new_edit_question_textfield.html.erb @@ -0,0 +1,8 @@ +
+ <%= f.label(:text, raw(question.text), class: 'control-label') %> + <% if readonly %> +

<%= strip_tags(answer.text) %>

+ <% else %> + <%= text_field_tag('answer[text]', strip_tags(answer.text), class: 'form-control') %> + <% end %> +
\ No newline at end of file diff --git a/app/views/sections/_progress.html.erb b/app/views/sections/_progress.html.erb index 02c8d69..7eae314 100644 --- a/app/views/sections/_progress.html.erb +++ b/app/views/sections/_progress.html.erb @@ -3,6 +3,6 @@ <% num_section_answers = section.num_answered_questions(plan.id) %> - <%= num_section_answers %> / <%= num_section_questions %> + (<%= num_section_answers %> / <%= num_section_questions %>) \ No newline at end of file diff --git a/lib/assets/javascripts/application.js b/lib/assets/javascripts/application.js index a974141..0a2fc35 100644 --- a/lib/assets/javascripts/application.js +++ b/lib/assets/javascripts/application.js @@ -1,3 +1,4 @@ +import './views/answers/status'; import './views/contacts/new'; import './views/devise/invitations/edit'; import './views/devise/passwords/edit'; diff --git a/lib/assets/javascripts/views/answers/status.js b/lib/assets/javascripts/views/answers/status.js index ae9b12d..55e3aa0 100644 --- a/lib/assets/javascripts/views/answers/status.js +++ b/lib/assets/javascripts/views/answers/status.js @@ -1,92 +1,130 @@ -$(document).ready(function(){ - /*-------------- - START Autosaving - ----------------*/ - // debounced object holds a set of debounced functions, one for each form present in the page. Note, - // each debounced function stored at funcs is created on demand, i.e. once the user changes any element of a form - var debounced = (function(){ - var funcs = {}; - return { - has: function(id){ - return funcs[id] !== undefined; - }, - get: function(id){ +import { + isObject, + isNumber, + isString } from '../../utils/isType'; +import { Tinymce } from '../../utils/tinymce'; +import debounce from '../../utils/debounce'; - return funcs[id]; - }, - set: function(id, func){ - funcs[id] = dmproadmap.utils.debounce(func); - } - } - })(); - // This function triggers a form submit, if and only if the answer has not been optimistically locked - var autoSaving=function(){ - if($(this).closest('.question-form').find('.answer-locking').children().length === 0){ - $(this).closest('form.answer').submit(); - } - }; - var listenersForEditor=function(editor){ - editor.on('change', function(){ - var notAnswered = $('#'+editor.id).closest('.question-form').find('.not-answered'); - notAnswered.hide(); - }); - editor.on('blur', function(){ - var id = $('#'+editor.id).closest('form.answer').attr('data-autosave'); - $('#'+editor.id).val(editor.getContent()); //Updates target element of tinyMCE.editor with its content - if(!debounced.has(id)){ - debounced.set(id, autoSaving); - } - debounced.get(id).apply($('#'+editor.id),[id]); - }); - editor.on('focus', function(){ - var id = $('#'+editor.id).closest('form.answer').attr('data-autosave'); - if(debounced.has(id)){ - debounced.get(id).cancel(); //Cancels the execution of its debounced function either because user transitioned from question with options - // to the comments or because textarea lost focus and gained again before the delay being met - } - }); +$(() => { + /* + * Shows the closest saving-message HTML element within a question-form + * @param { Strin } selector - A valid CSS selector to look for + * @return { jQuery } + */ + const showSavingMessage = selector => $(selector).closest('.question-form').find('.saving-message').show(); + /* + * Hides the closest not-answered HTML element within a question-form + * @param { String } selector - A valid CSS selector to look for + * @return { jQuery } + */ + const hideNotAnswered = selector => $(selector).closest('.question-form').find('.not-answered').hide(); + /* + * Retrieves the question id for the closest form-answer + * @param { String } selector - A valid CSS selector to look for + * @return { String } representing the question id for a given answer, otherwise undefined + */ + const questionId = selector => $(selector).closest('.form-answer').attr('data-autosave'); + /* + * A map of debounced functions, one for each input, textarea or select change at any + * form with class form-answer. The key represents a question id and the value holds + * the debounced function for a given input, textarea or select. Note, this map is + * populated on demand, i.e. the first time a change is made at a given input, textarea + * or select within the form, a new key-value should be created. Succesive times, the + * debounced function should be retrieved instead. + */ + const debounceMap = {}; + const autoSaving = (selector) => { + if ($(selector).closest('.question-form').find('.answer-locking').html().length === 0) { + $(selector).closest('.form-answer').trigger('submit'); } - /*-------------- - END Autosaving - ----------------*/ - // Listener for submit event triggered - $('.question-form').on('submit', 'form.answer', function(){ - var id = $(this).attr('data-autosave'); - if(debounced.has(id)){ - debounced.get(id).cancel(); //Cancels the execution of its debounced function, if not already, since submit() could have been trigerred through Save button - } - var container = $(this).closest('.question-form'); - var saving = container.find('.saving-message'); - saving.show(); + }; + // Initialises tinymce for any target element with class tinymce_answer + Tinymce.init({ selector: '.tinymce_answer' }); + // Listeners for change, blur and focus at any target element with class tinymce_answer + Tinymce.findEditorsByClassName('tinymce_answer').forEach((editor) => { + editor.on('Change', () => { + hideNotAnswered(`#${editor.id}`); }); - // Listener for changes at any element value from question-form - $('.question-form').on('change', 'form.answer fieldset input, form.answer fieldset select', function(){ - var notAnswered = $(this).closest('.question-form').find('.not-answered'); - notAnswered.hide(); + editor.on('Blur', () => { + const id = questionId(`#${editor.id}`); + $(`#${editor.id}`).val(editor.getContent()); // Updates target element of editor with its content + if (!debounceMap[id]) { + debounceMap[id] = debounce(autoSaving); + } + debounceMap[id]($(`#${editor.id}`)); }); - // Listener for changes at any element value from question-form. This triggers the debounced function - $('.question-form').on('change', 'form.answer fieldset input, form.answer fieldset select', function(){ - var id = $(this).closest('form.answer').attr('data-autosave'); - if(!debounced.has(id)){ - debounced.set(id, autoSaving); - } - debounced.get(id).apply($(this),[id]); + editor.on('Focus', () => { + const id = questionId(`#${editor.id}`); + if (debounceMap[id]) { + /* Cancels the delayed execution of autoSaving, either because user + * transitioned from an option_based question to the comment or + * because the target element triggered blur and focus before + * the delayed execution of autoSaving. + */ + debounceMap[id].cancel(); + } }); - // Init function to add listeners for every tinyMCE editor whose target element class is tinymce_answer - (function(){ - var editors = dmproadmap.utils.tinymce.findEditorsByClassName('tinymce_answer'); - editors.forEach(listenersForEditor); - // Initialises timeago for each element abbr with class timeago - $('abbr.timeago').timeago(); - })(); - (function(ctx){ - // function to add listeners for a tinyMCE editor with target element id passed - ctx.reloadEditorListeners = ctx.reloadEditorListeners || (function(id){ - var editor = dmproadmap.utils.tinymce.findEditorById(id); - if(editor){ - listenersForEditor(editor); - $('abbr.timeago').timeago(); + }); + // Listener for input or select field + $('.question-form').on('change', 'form.answer fieldset input, form.answer fieldset select', (e) => { + hideNotAnswered(e.target); + const id = questionId(e.target); + if (!debounceMap[id]) { + debounceMap[id] = debounce(autoSaving); + } + debounceMap[id]($(e.target)); + }); + // Listener for submit button + $('.form-answer').on('submit', (e) => { + e.preventDefault(); + const id = questionId(e.target); + if (debounceMap[id]) { + // Cancels the delated execution of autoSaving + // (e.g. user clicks the button before the delay is met) + debounceMap[id].cancel(); + } + showSavingMessage(e.target); + const formElements = $(e.target).closest('.form-answer').serializeArray(); + const answerId = formElements.find(el => el.name === 'answer[id]'); + if (answerId) { + // TODO centralise AJAX calls + $.ajax({ + method: 'PUT', + url: `/answers/${answerId}`, + data: formElements, + }).done((data) => { + // Validation for the data object received + if (isObject(data)) { + if (isObject(data.question)) { // Object related to question within data received + if (isNumber(data.question.id)) { + if (isString(data.question.answer_status)) { + $(`#answer-status-${data.question.id}`).html(data.question.answer_status); // TODO check partial render of this view on the server + $('abbr.timeago').timeago(); + } + if (isString(data.question.locking)) { + $(`#answer-locking-${data.question.id}`).html(data.question.locking); + } + if (isNumber(data.question.answer_lock_version)) { + $(e.target).closest('.form-answer').find('#answer_lock_version').val(data.question.answer_lock_version); + } } - }); - })(define('dmproadmap.answers.status')); -}); \ No newline at end of file + } + if (isObject(data.plan)) { // Object related to plan within data received + if (isString(data.plan.progress)) { + $('.progress').html(data.plan.progress); + } + } + if (isObject(data.section)) { // Object related to section within data received + if (isNumber(data.section.id)) { + if (isString(data.section.progress)) { + $(`.section-progress-${data.section.id}`).html(data.section.progress); + } + } + } + } + }, () => { + // TODO adequate error handling for network error + }); + } + }); +}); diff --git a/lib/assets/javascripts/views/phases/edit.js b/lib/assets/javascripts/views/phases/edit.js index ffab5ac..f771160 100644 --- a/lib/assets/javascripts/views/phases/edit.js +++ b/lib/assets/javascripts/views/phases/edit.js @@ -1,8 +1,16 @@ +import 'bootstrap-sass/assets/javascripts/bootstrap/collapse'; import expandCollapseAll from '../../utils/expandCollapseAll'; $(() => { // Attach handlers for the expand/collapse all accordions expandCollapseAll(); + $('a[data-toggle="collapse"').click((e) => { + if ($(e.target).hasClass('fa-plus')) { + $(e.target).removeClass('fa-plus').addClass('fa-minus'); + } else { + $(e.target).removeClass('fa-minus').addClass('fa-plus'); + } + }); }); /* $(document).ready(function(){ diff --git a/lib/assets/stylesheets/application.scss b/lib/assets/stylesheets/application.scss index 420a724..1df72cd 100644 --- a/lib/assets/stylesheets/application.scss +++ b/lib/assets/stylesheets/application.scss @@ -19,3 +19,7 @@ @import "dmproadmap/tables"; @import "dmproadmap/forms"; */ + +[class^="bg-"] { + padding: 15px; +} diff --git a/lib/assets/webpack.config.js b/lib/assets/webpack.config.js index 71f1ec7..6e20570 100644 --- a/lib/assets/webpack.config.js +++ b/lib/assets/webpack.config.js @@ -15,7 +15,7 @@ context: __dirname, entry: { - vendor: ['jquery'], + vendor: ['jquery', 'timeago/jquery.timeago'], application: ['./javascripts/application.js', './stylesheets/application.scss'], }, diff --git a/test/functional/answers_controller_test.rb b/test/functional/answers_controller_test.rb index 6ed2db9..372ed47 100644 --- a/test/functional/answers_controller_test.rb +++ b/test/functional/answers_controller_test.rb @@ -69,11 +69,9 @@ private def put_answer(answer, attributes, referrer) - put answer_path(FastGettext.locale, answer, format: "js"), attributes, {'HTTP_REFERER': referrer} + put answer_path(FastGettext.locale, answer, format: "json"), attributes, {'HTTP_REFERER': referrer} assert_response :success - assert_equal "text/javascript", @response.content_type - -# assert_match(/[^\$]*\$\("#answer-locking-[0-9]+"\).html\(""\);[^\$]*\$\("#answer-form-[0-9]+"\)[^\.]*.html\(".+"\);[^\$]*\$\("#answer-status-[0-9]+"\)[^.]*.html\(".+"\);[^\$]*\$.[^$]*\$.[^\$]*\$\(".progress"\).html\(".+"\);[^\$]*\$\("#section-progress-[0-9]+"\)[^.]*.html\(".+"\);/, @response.body) + assert_equal "application/json", @response.content_type end end diff --git a/test/integration/answer_locking_test.rb b/test/integration/answer_locking_test.rb index 0c0bb0f..6dfe674 100644 --- a/test/integration/answer_locking_test.rb +++ b/test/integration/answer_locking_test.rb @@ -26,9 +26,9 @@ # Signin as UserA and insert the new answer sign_in @plan.owner - put answer_path(FastGettext.locale, userA, format: "js"), obj_to_params(userA.attributes) + put answer_path(FastGettext.locale, userA, format: "json"), obj_to_params(userA.attributes) assert_response :success - assert_equal "text/javascript", @response.content_type + assert_equal "application/json", @response.content_type updated = Answer.find_by(plan: @plan, question: @question) assert_equal "Initial answer - by UserA", updated.text assert_equal @plan.owner.id, updated.user_id @@ -40,9 +40,9 @@ # Signin as UserB and try to insert the new answer but fail sign_in @collaborator - put answer_path(FastGettext.locale, userB, format: "js"), obj_to_params(userB.attributes) + put answer_path(FastGettext.locale, userB, format: "json"), obj_to_params(userB.attributes) assert_response :success - assert_equal "text/javascript", @response.content_type + assert_equal "application/json", @response.content_type updated = Answer.find_by(plan: @plan, question: @question) assert_equal "Initial answer - by UserA", updated.text assert_equal @plan.owner.id, updated.user_id @@ -63,9 +63,9 @@ sign_in @plan.owner userA['text'] += " - Updated by userA" - put answer_path(FastGettext.locale, userA['id'], format: "js"), obj_to_params(userA) + put answer_path(FastGettext.locale, userA['id'], format: "json"), obj_to_params(userA) assert_response :success - assert_equal "text/javascript", @response.content_type + assert_equal "application/json", @response.content_type updated = Answer.find_by(plan: @plan, question: @question) assert_equal "Initial answer - by UserA - Updated by userA", updated.text assert_equal @plan.owner.id, updated.user_id @@ -79,9 +79,9 @@ sign_in @collaborator userB['text'] += " - Updated by userB" - put answer_path(FastGettext.locale, userB['id'], format: "js"), obj_to_params(userB) + put answer_path(FastGettext.locale, userB['id'], format: "json"), obj_to_params(userB) assert_response :success - assert_equal "text/javascript", @response.content_type + assert_equal "application/json", @response.content_type updated = Answer.find_by(plan: @plan, question: @question) assert_equal "Initial answer - by UserA - Updated by userA", updated.text assert_equal @plan.owner.id, updated.user_id