Skip to content
Permalink
Browse files

Fix dynamic fields elements for IE11 (#5052)

#### 🎩 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 a524dd3aa6332afd78acef8e51688e51a78cdb26
@@ -10,6 +10,12 @@ linters:
SpaceAroundErbTag:
enabled: true

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

Rubocop:
enabled: true

@@ -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**:

@@ -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);
@@ -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);
@@ -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());

@@ -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>
@@ -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>
@@ -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| %>
@@ -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
@@ -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"
@@ -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| %>
@@ -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>
@@ -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>
@@ -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| %>

0 comments on commit a524dd3

Please sign in to comment.
You can’t perform that action at this time.