Skip to content

Commit

Permalink
Replace (some) jQuery code with native javascript (#2013)
Browse files Browse the repository at this point in the history
Also removes some (what we think is) obsolete code (`makeDisabledClickHandler`).
  • Loading branch information
richardebeling authored Sep 24, 2023
1 parent d520f08 commit 93cf241
Show file tree
Hide file tree
Showing 23 changed files with 365 additions and 353 deletions.
10 changes: 8 additions & 2 deletions evap/contributor/templates/contributor_evaluation_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,14 @@ <h5 class="modal-title" id="previewModalLabel">{% trans 'Preview' %}</h5>
{% include 'confirmation_modal.html' with modal_id='approveEvaluationModal' title=title question=question action_text=action_text btn_type='primary' %}
<script type="text/javascript">
function approveEvaluationModalAction(dataId) {
$('#evaluation-form').append('<input type="hidden" name="operation" value="approve" />');
$('#evaluation-form').submit();
const input = document.createElement("input");
input.type = "hidden";
input.name = "operation";
input.value = "approve";

const form = document.getElementById("evaluation-form");
form.appendChild(input);
form.requestSubmit();
};
</script>

Expand Down
7 changes: 4 additions & 3 deletions evap/contributor/templates/contributor_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,15 @@ <h5 class="modal-title" id="{{ modal_id }}Label">{% trans 'Delegate preparation'

<script type="text/javascript">
function {{ modal_id }}Show(evaluationName, action) {
const modal = document.getElementById("{{ modal_id }}");
// set form's action location
$('#{{ modal_id }} form').attr('action', action);
modal.querySelectorAll("form").forEach(form => form.action = action);

// put the correct evaluation name in the modal
$('#{{ modal_id }} [data-label=""]').text(evaluationName);
modal.querySelectorAll('[data-label=""]').forEach(el => el.innerText = evaluationName);

// unselect any previously selected options in the modal
$('#{{ modal_id }} select').val(null).trigger('change');
modal.querySelectorAll("select").forEach(select => select.tomselect.clear());

// show modal
var {{ modal_id }} = new bootstrap.Modal(document.getElementById('{{ modal_id }}'));
Expand Down
59 changes: 34 additions & 25 deletions evap/evaluation/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
<script type="text/javascript" src="{% static 'js/Sortable.min.js' %}"></script>

<script type="module" src="{% static 'js/csrf-utils.js' %}"></script>
<script type="module" src="{% static 'js/utils.js' %}"></script>

<script type="module" src="{% static 'js/base-template.js' %}"></script>
<script type="text/javascript">
Expand All @@ -82,17 +83,23 @@
activateTooltips();

// These are workarounds around incompatibilities of django, django-dynamic-formsets, and tomselect.
// tomselect can't handle already tomselect'd forms that were copies made by
// django-dynamic-formsets' "add another" button, so we take a copy of a non-tomselect'd form here
var templateForm = $(".tomselecttr").last().clone();

// later we use this class to give this to django-dynamic-formsets
// as template and to make sure it does not get tomselect'd
templateForm.addClass("form-template").css("display", "none");
// for some reason django-dynamic-formsets does not hide the checkbox like it should
templateForm.find(':checkbox').last().attr("type", "hidden");
// For some reason, django validates this template if it's part of the form, so we insert the copy outside of the form.
templateForm.insertAfter($('.tomselectform'));
// tomselect can't handle already tomselect'd forms that were copies made by django-dynamic-formsets'
// "add another" button, so we take a copy of a non-tomselect'd form here
const tomSelectRows = document.querySelectorAll(".tomselecttr");

if(tomSelectRows.length != 0) {
const templateForm = tomSelectRows[tomSelectRows.length - 1].cloneNode(true);

// later we use this class to give this to django-dynamic-formsets as template and to make sure it does not get tomselect'd
templateForm.classList.add("form-template");
templateForm.style.display = "none";

// django-dynamic-formsets doesn't hide the "delete this row" input in the clone since it's not part of the formset.
templateForm.querySelectorAll("input[id$=-DELETE]").forEach(input => {input.type = "hidden";});

// For some reason, django validates this template if it's part of the form, so we insert the copy outside of the form.
document.querySelector(".tomselectform").insertAdjacentElement("afterend", templateForm);
}

// used in derived templates. Tag inputs are multi-inputs where users can add options
const tagTomSelectOptions = {
Expand Down Expand Up @@ -160,27 +167,29 @@
};
applyTomSelect(document.querySelectorAll("select:not(.form-template select):not(.no-tomselect)"));

document.addEventListener('change', function(e){
$(e.target).removeClass("invalid")
}, true);
document.addEventListener('change', e => e.target.classList.remove("invalid"), true);

// activate clickable hover tables
$(".table-seamless-links [data-url]").each(function() {
const row = $(this);
const link = "<a href='" + row.data("url") + "'></a>";
row.children().wrapInner(link);
document.querySelectorAll(".table-seamless-links [data-url]").forEach(row => {
for(const table_data of row.children) {
const wrapping_anchor = document.createElement("a");
wrapping_anchor.href = row.dataset["url"];
wrapping_anchor.append(...table_data.children);
table_data.replaceChildren(wrapping_anchor);
}
});

$(".hover-row").each(function() {
const row = $(this);
row
.find(".btn:not(.btn-row-hover)")
.mouseover(() => row.removeClass("hover-row"))
.mouseout(() => row.addClass("hover-row"));
document.querySelectorAll(".hover-row").forEach(row => {
row.querySelectorAll(".btn:not(.btn-row-hover)").forEach(button => {
button.addEventListener("mouseover", () => row.classList.remove("hover-row"));
button.addEventListener("mouseout", () => row.classList.add("hover-row"));
});
});

function setSpinnerIcon(id) {
$("#" + id).empty().removeClass().addClass('fas fa-spinner fa-spin');
const element = document.getElementById(id);
element.innerHTML = "";
element.className = "fas fa-spinner fa-spin"; // clears all other classes
};
</script>

Expand Down
56 changes: 26 additions & 30 deletions evap/evaluation/templates/evap_evaluation_edit_js.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

questionnaireChanged = false;
$(row.find("input[name$=-questionnaires]")).each(function () {
if(this.checked)
if (this.checked)
questionnaireChanged = true;
})

Expand All @@ -29,52 +29,48 @@
{% endif %}

<script type="text/javascript">
function makeDisabledClickHandler() {
return function () {
// suppress toggling disabled buttons
if ($(this).hasClass("disabled"))
return false;
}
}

function makeDoesNotContributeChangeHandler(i) {
return function () {
// don't do anything on disabled buttons
if ($(this).hasClass("disabled"))
return () => {
const doesNotContributeInput = document.querySelector("input[name=contributions-" + i + "-does_not_contribute]");

if (doesNotContributeInput.disabled)
return false;
if($("input[name=contributions-" + i + "-does_not_contribute]").prop("checked")) {

if (doesNotContributeInput.checked) {
// uncheck and disable all questionnaire checkboxes
$("input[name=contributions-" + i + "-questionnaires]").prop("checked", false);
$("input[name=contributions-" + i + "-questionnaires]").prop("disabled", true);
}
else {
document.querySelectorAll("input[name=contributions-" + i + "-questionnaires]").forEach(checkbox => {
checkbox.checked = false;
checkbox.disabled = true;
});
} else {
// enable all questionnaire checkboxes
$("input[name=contributions-" + i + "-questionnaires]").prop("disabled", false);
document.querySelectorAll("input[name=contributions-" + i + "-questionnaires]").forEach(checkbox => {
checkbox.disabled = false;
});
}
}
};
}

function getContributorCount() {
return $("#contribution_table select").length;
return document.querySelectorAll("#contribution_table select").length;
}

function assignClickHandlers() {
var count = getContributorCount();
for(var i = 0; i < count; i++)
{
$("input[name=contributions-" + i + "-role]").parent().click(makeDisabledClickHandler());
$("input[name=contributions-" + i + "-textanswer_visibility]").parent().click(makeDisabledClickHandler());
$("input[name=contributions-" + i + "-does_not_contribute]").parent().change(makeDoesNotContributeChangeHandler(i));
const count = getContributorCount();
for (let i = 0; i < count; i++) {
document.querySelector(`input[name=contributions-${i}-does_not_contribute]`).parentElement.addEventListener("click", makeDoesNotContributeChangeHandler(i));
}
}

assignClickHandlers();

// apply initial settings
for(var i = 0; i < getContributorCount(); i++){
if($("input[name=contributions-" + i + "-does_not_contribute]").prop("checked")) {
$("input[name=contributions-" + i + "-questionnaires]").prop("checked", false);
$("input[name=contributions-" + i + "-questionnaires]").prop("disabled", true);
for (let i = 0; i < getContributorCount(); i++){
if (document.querySelector("input[name=contributions-" + i + "-does_not_contribute]").checked) {
document.querySelectorAll("input[name=contributions-" + i + "-questionnaires]").forEach(checkbox => {
checkbox.checked = false;
checkbox.disabled = true;
});
}
}
</script>
Expand Down
1 change: 0 additions & 1 deletion evap/evaluation/templates/faq.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ <h2 id="faq-{{ question.id }}-q" class="accordion-header">

if(type == "q"){
// open collapsed answer and scroll into center
const answer_div = $("#faq-"+id+"-a");
window.history.pushState('', id, '/faq#faq-' + id + '-q');
var answerCard = document.getElementById("faq-"+id+"-a");
var answerCardCollapse = bootstrap.Collapse.getOrCreateInstance(answerCard);
Expand Down
15 changes: 8 additions & 7 deletions evap/grades/templates/grades_course_view.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,14 @@ <h3 class="mb-3">{{ course.name }} ({{ semester.name }})</h3>
{% include 'confirmation_modal.html' with modal_id='deleteGradedocumentModal' title=title question=question action_text=action_text btn_type='danger' %}
<script type="text/javascript">
function deleteGradedocumentModalAction(dataId) {
$.ajax({
type: "POST",
url: "{% url 'grades:delete_grades' %}",
data: {"grade_document_id": dataId},
success: function(){ $('#grade_document-row-'+dataId).hide('slow', function(){ $('#grade_document-row-'+dataId).remove(); }); },
error: function(){ window.alert("{% trans 'The server is not responding.' %}"); }
});
fetch("{% url 'grades:delete_grades' %}", {
body: new URLSearchParams({grade_document_id: dataId}),
headers: CSRF_HEADERS,
method: "POST",
}).then(response => {
assert(response.ok);
fadeOutThenRemove(document.getElementById('grade_document-row-'+dataId));
}).catch(error => {window.alert("{% trans 'The server is not responding.' %}");});
};
</script>
{% endblock %}
15 changes: 8 additions & 7 deletions evap/grades/templates/grades_semester_view.html
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,14 @@ <h3 class="col-8 mb-0">
{% include 'confirmation_modal.html' with modal_id='confirmNouploadModal' title=title question=question action_text=action_text btn_type='primary' %}
<script type="text/javascript">
function confirmNouploadModalAction(dataId) {
$.ajax({
type: "POST",
url: "{% url 'grades:toggle_no_grades' %}",
data: {"course_id": dataId},
success: function(){ location.reload(); },
error: function(){}
});
fetch("{% url 'grades:toggle_no_grades' %}", {
body: new URLSearchParams({course_id: dataId}),
headers: CSRF_HEADERS,
method: "POST",
}).then(response => {
assert(response.ok);
location.reload();
}).catch(error => {window.alert("{% trans 'The server is not responding.' %}");});
};
</script>
{% trans 'Will final grades be uploaded?' as title %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@
{% trans 'Do you really want to delete the event <strong data-label=""></strong>?' as question %}
{% trans 'Delete event' as action_text %}
{% include 'confirmation_modal.html' with modal_id='deleteEventModal' title=title question=question action_text=action_text btn_type='danger' %}

<script type="text/javascript">
function deleteEventModalAction(dataId) {
$.ajax({
type: "POST",
url: "{% url 'rewards:reward_point_redemption_event_delete' %}",
data: {"event_id": dataId},
success: function(){ $('#event-row-'+dataId).hide('slow', function(){ $('#event-row-'+dataId).remove(); }); },
error: function(){ window.alert("{% trans 'The server is not responding.' %}"); }
});
fetch("{% url 'rewards:reward_point_redemption_event_delete' %}", {
body: new URLSearchParams({event_id: dataId}),
headers: CSRF_HEADERS,
method: "POST",
}).then(response => {
assert(response.ok);
fadeOutThenRemove(document.querySelector('#event-row-'+dataId));
}).catch(error => {window.alert("{% trans 'The server is not responding.' %}");});
};
</script>
{% endblock %}
2 changes: 1 addition & 1 deletion evap/staff/templates/staff_email_preview_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% if heading %}<h4 class="card-title">{{ heading }}</h4>{% endif %}
<div class="form-check mb-2">
<input class="form-check-input" id="send_email{{ id_suffix }}" type="checkbox" name="send_email{{ id_suffix }}"
checked onclick="$('#email_form{{ id_suffix }}').toggle();" />
checked onclick="document.getElementById('email_form').classList.toggle('d-none');" />
<label class="form-check-label" for="send_email{{ id_suffix }}">{% trans 'Send email notifications' %}</label>
</div>
<div class="email-form" id="email_form{{ id_suffix}}">
Expand Down
Loading

0 comments on commit 93cf241

Please sign in to comment.