Skip to content

Commit

Permalink
Fix dynamic fields elements for IE11 (#5052)
Browse files Browse the repository at this point in the history
#### 🎩 What? Why?
This fixes the dynamic field elements for IE11 as explained in #5035.

This is an unfortunately complex fix for IE11 but it is the only way to make it compatible with that browser. The biggest issue with this is not actually the admin panel where we initially noticed issues with this but another component we built for the participation interface using the same component. Therefore, this component should consider both cases to support IE11 as well.

This should also maintain backwards compatibility in case someone is using the `<template>` tags with the dynamic fields component.

#### 📌 Related Issues
- Fixes #5035

#### 📋 Subtasks
- [x] Add `CHANGELOG` entry
- [X] Fix tests
  • Loading branch information
ahukkanen authored and mrcasals committed Apr 5, 2019
1 parent d99ab53 commit a524dd3
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 38 deletions.
6 changes: 6 additions & 0 deletions .erb-lint.yml
Expand Up @@ -10,6 +10,12 @@ linters:
SpaceAroundErbTag:
enabled: true

AllowedScriptType:
enabled: true
allowed_types:
- text/javascript
- text/template

Rubocop:
enabled: true

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -23,6 +23,7 @@
- **decidim-proposals**: Filter emendations by rendering only amendments. [#5025](https://github.com/decidim/decidim/pull/5025)
- **decidim-proposals**: Add documents folder in proposals manifest for precompile assets. [#5015](https://github.com/decidim/decidim/pull/5015)
- **decidim-core**: Fix user notification and interest settings on IE11. [#5044](https://github.com/decidim/decidim/pull/5044)
- **decidim-admin**, **decidim-forms**, **decidim-meetings**: Fix dynamic fields components on IE11. [#5052](https://github.com/decidim/decidim/pull/5052)

**Removed**:

Expand Down
Expand Up @@ -29,12 +29,26 @@
}

$.fn.template = function(placeholder, value) {
const $subtemplate = $(this).find("template");
// See the comment below in the `_addField()` method regarding the
// `<template>` tag support in IE11.
const $subtemplate = $(this).find("template, .decidim-template");

if ($subtemplate.length > 0) {
$subtemplate.html((index, oldHtml) => $(oldHtml).template(placeholder, value)[0].outerHTML);
}

// Handle those subtemplates that are mapped with the `data-template`
// attribute. This is also because of the IE11 support.
const $subtemplateParents = $(this).find("[data-template]");

if ($subtemplateParents.length > 0) {
$subtemplateParents.each((_i, elem) => {
const $self = $(elem);
const $tpl = $($self.data("template"));
$tpl.html((index, oldHtml) => $(oldHtml).template(placeholder, value)[0].outerHTML);
});
}

$(this).replaceAttribute("id", placeholder, value);
$(this).replaceAttribute("name", placeholder, value);
$(this).replaceAttribute("data-tabs-content", placeholder, value);
Expand Down Expand Up @@ -81,8 +95,27 @@
}

_addField() {
const $container = $(this.wrapperSelector).find(this.containerSelector);
const $template = $(this.wrapperSelector).children("template");
const $wrapper = $(this.wrapperSelector);
const $container = $wrapper.find(this.containerSelector);

// Allow defining the template using a `data-template` attribute on the
// wrapper element. This is to allow child templates which would otherwise
// be impossible using `<script type="text/template">`. See the comment
// below regarding the `<template>` tag and IE11.
const templateSelector = $wrapper.data("template");
let $template = null;
if (templateSelector) {
$template = $(templateSelector);
}
if ($template === null || $template.length < 1) {
// To preserve IE11 backwards compatibility, the views are using
// `<script type="text/template" class="decidim-template">` instead of
// `<template>`. The `<template> tags are parsed in IE11 along with the
// DOM which may cause the form elements inside them to break the forms
// as they are submitted with them.
$template = $wrapper.children("template, .decidim-template");
}

const $newField = $($template.html()).template(this.placeholderId, this._getUID());

$newField.find("ul.tabs").attr("data-tabs", true);
Expand Down Expand Up @@ -141,6 +174,14 @@
}

_activateFields() {
// Move the `<script type="text/template">` elements to the bottom of the
// list container so that they will not cause the question moving
// functionality to break since it assumes that all children elements are
// the dynamic field list child items.
const $wrapper = $(this.wrapperSelector);
const $container = $wrapper.find(this.containerSelector);
$container.append($container.find("script"));

$(this.fieldSelector).each((idx, el) => {
$(el).template(this.placeholderId, this._getUID());

Expand Down
@@ -0,0 +1,7 @@
<% question = form.object %>

<script type="text/template" class="decidim-template" id="<%= template_id %>">
<%= fields_for "questionnaire[questions][#{question.to_param}][answer_options][]", blank_answer_option do |answer_option_form| %>
<%= render "decidim/forms/admin/questionnaires/answer_option", form: answer_option_form, question: question, editable: editable %>
<% end %>
</script>
Expand Up @@ -22,21 +22,23 @@

<div class="questionnaire-questions">
<% if questionnaire.questions_editable? %>
<template>
<%= fields_for "questionnaire[questions][#{blank_question.to_param}]", blank_question do |question_form| %>
<%= render "decidim/forms/admin/questionnaires/question", form: question_form, id: tabs_id_for_question(blank_question), editable: questionnaire.questions_editable? %>
<% end %>
</template>
<%= fields_for "questionnaire[questions][#{blank_question.to_param}]", blank_question do |question_form| %>
<script type="text/template" class="decidim-template">
<%= render "decidim/forms/admin/questionnaires/question", form: question_form, id: tabs_id_for_question(blank_question), editable: questionnaire.questions_editable?, child_template_selector: "#answer-option-template-dummy" %>
</script>
<%= render "decidim/forms/admin/questionnaires/answer_option_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "answer-option-template-dummy" %>
<% end %>
<% else %>
<div class="callout warning">
<%= t(".already_answered_warning") %>
</div>
<% end %>

<div class="questionnaire-questions-list">
<% @form.questions.each do |question| %>
<% @form.questions.each_with_index do |question, index| %>
<%= fields_for "questionnaire[questions][]", question do |question_form| %>
<%= render "decidim/forms/admin/questionnaires/question", form: question_form, id: tabs_id_for_question(question), editable: questionnaire.questions_editable? %>
<%= render "decidim/forms/admin/questionnaires/question", form: question_form, id: tabs_id_for_question(question), editable: questionnaire.questions_editable?, child_template_selector: "#answer-option-template-#{index}" %>
<%= render "decidim/forms/admin/questionnaires/answer_option_template", form: question_form, editable: questionnaire.questions_editable?, template_id: "answer-option-template-#{index}" %>
<% end %>
<% end %>
</div>
Expand Down
Expand Up @@ -81,13 +81,7 @@
<%= form.hidden_field :position, value: question.position || 0, disabled: !editable %>
<%= form.hidden_field :deleted, disabled: !editable %>

<div class="questionnaire-question-answer-options">
<template>
<%= fields_for "questionnaire[questions][#{question.to_param}][answer_options][]", blank_answer_option do |answer_option_form| %>
<%= render "decidim/forms/admin/questionnaires/answer_option", form: answer_option_form, question: question, editable: editable %>
<% end %>
</template>

<div class="questionnaire-question-answer-options" data-template="<%= child_template_selector %>">
<div class="questionnaire-question-answer-options-list">
<% question.answer_options.each do |answer_option| %>
<%= fields_for "questionnaire[questions][#{question.to_param}][answer_options][]", answer_option do |answer_option_form| %>
Expand Down
Expand Up @@ -504,9 +504,9 @@
within ".questionnaire-question:last-of-type" do
click_button "Up"
end

it_behaves_like "switching questions order"
end

it_behaves_like "switching questions order"
end

context "when moving a question down" do
Expand All @@ -522,9 +522,9 @@
it "properly decides which button to show after adding/removing questions" do
click_button "Add question"

expect(page.find(".questionnaire-question:nth-child(1)")).to look_like_first_question
expect(page.find(".questionnaire-question:nth-child(2)")).to look_like_intermediate_question
expect(page.find(".questionnaire-question:nth-child(3)")).to look_like_last_question
expect(page.find(".questionnaire-question:nth-of-type(1)")).to look_like_first_question
expect(page.find(".questionnaire-question:nth-of-type(2)")).to look_like_intermediate_question
expect(page.find(".questionnaire-question:nth-of-type(3)")).to look_like_last_question

within ".questionnaire-question:first-of-type" do
click_button "Remove"
Expand Down
Expand Up @@ -28,13 +28,7 @@
<h2 class="card-title"><%= t(".agenda_item_children") %></h2>
</div>
<div class="card-section">
<div class="meeting-agenda-item-childs">
<template>
<%= fields_for "meeting_agenda[agenda_items][#{agenda_item.to_param}][agenda_item_children][#{blank_agenda_item.to_param_child}]", blank_agenda_item do |agenda_item_child_form| %>
<%= render "agenda_item_child", form: agenda_item_child_form, tabs_id: tabs_id, tabs_id_child: tabs_id_for_agenda_item_child(blank_agenda_item), editable: true %>
<% end %>
</template>

<div class="meeting-agenda-item-childs" data-template="<%= child_template_selector %>">
<div class="meeting-agenda-item-childs-list">
<% agenda_item.agenda_item_children.each do |agenda_item_child| %>
<%= fields_for "meeting_agenda[agenda_items][#{agenda_item.to_param}][agenda_item_children][]", agenda_item_child do |agenda_item_child_form| %>
Expand Down
@@ -0,0 +1,7 @@
<% agenda_item = form.object %>

<script type="text/template" class="decidim-template" id="<%= template_id %>">
<%= fields_for "meeting_agenda[agenda_items][#{agenda_item.to_param}][agenda_item_children][#{blank_agenda_item.to_param_child}]", blank_agenda_item do |agenda_item_child_form| %>
<%= render "agenda_item_child", form: agenda_item_child_form, tabs_id: tabs_id_for_agenda_item(blank_agenda_item), tabs_id_child: tabs_id_for_agenda_item_child(blank_agenda_item), editable: editable %>
<% end %>
</script>
Expand Up @@ -45,16 +45,18 @@

<div class="card-section">
<div class="meeting-agenda-items">
<template>
<%= fields_for "meeting_agenda[agenda_items][#{blank_agenda_item.to_param}]", blank_agenda_item do |agenda_item_form| %>
<%= render "agenda_item", form: agenda_item_form, tabs_id: tabs_id_for_agenda_item(blank_agenda_item), editable: true %>
<% end %>
</template>
<%= fields_for "meeting_agenda[agenda_items][#{blank_agenda_item.to_param}]", blank_agenda_item do |agenda_item_form| %>
<script type="text/template" class="decidim-template">
<%= render "agenda_item", form: agenda_item_form, tabs_id: tabs_id_for_agenda_item(blank_agenda_item), editable: true, child_template_selector: "#agenda-item-child-template-dummy" %>
</script>
<%= render "agenda_item_child_template", form: agenda_item_form, editable: true, template_id: "agenda-item-child-template-dummy" %>
<% end %>

<div class="meeting-agenda-items-list">
<% @form.agenda_items.each do |agenda_item| %>
<% @form.agenda_items.each_with_index do |agenda_item, index| %>
<%= fields_for "meeting_agenda[agenda_items][]", agenda_item do |agenda_item_form| %>
<%= render "agenda_item", form: agenda_item_form, tabs_id: tabs_id_for_agenda_item(agenda_item), editable: true %>
<%= render "agenda_item", form: agenda_item_form, tabs_id: tabs_id_for_agenda_item(agenda_item), editable: true, child_template_selector: "#agenda-item-child-template-#{index}" %>
<%= render "agenda_item_child_template", form: agenda_item_form, editable: true, template_id: "agenda-item-child-template-#{index}" %>
<% end %>
<% end %>
</div>
Expand Down
Expand Up @@ -5,11 +5,11 @@

<div class="card-section">
<div class="meeting-services">
<template>
<script type="text/template" class="decidim-template">
<%= fields_for "meeting[services][#{blank_service.to_param}]", blank_service do |service_form| %>
<%= render "decidim/meetings/admin/meetings/service", form: service_form, id: tabs_id_for_service(blank_service) %>
<% end %>
</template>
</script>

<div class="meeting-services-list">
<% form.object.services.each do |service| %>
Expand Down

0 comments on commit a524dd3

Please sign in to comment.