From b9311ba5133ae95ee3c50e02dcca13f8f0df32a4 Mon Sep 17 00:00:00 2001 From: Samuel Maldonado Date: Mon, 10 Jul 2023 19:25:48 -0400 Subject: [PATCH 1/4] Tests: increase flaky test coverage for course model (#6667) --- spec/models/course_spec.rb | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/spec/models/course_spec.rb b/spec/models/course_spec.rb index c9233aa59b..b14c464fa7 100644 --- a/spec/models/course_spec.rb +++ b/spec/models/course_spec.rb @@ -567,11 +567,8 @@ student1_data = "#{user1.user_name},#{user1.last_name},#{user1.first_name},,,#{user1.email}\n" student2_data = "#{user2.user_name},#{user2.last_name},#{user2.first_name},,,#{user2.email}\n" - if user1.user_name <= user2.user_name - expected = student1_data + student2_data - else - expected = student2_data + student1_data - end + student_data = [student1_data, student2_data] + expected = student_data.sort.join expect(result).to eq(expected) end end @@ -607,7 +604,6 @@ let!(:student2) { create :student, user: user2, course: course } it 'returns the data of the students' do result = course.export_student_data_yml - expected = [] student1_data = { user_name: user1.user_name, @@ -626,14 +622,7 @@ id_number: nil, section_name: nil } - - if user1.user_name <= user2.user_name - expected.push(student1_data) - expected.push(student2_data) - else - expected.push(student2_data) - expected.push(student1_data) - end + expected = [student1_data, student2_data].sort_by { |a| a[:user_name] } expect(result).to eq(expected.to_yaml) end end From 0ba549fc86fa4e66eeadfe522661db3bbbe6f3df Mon Sep 17 00:00:00 2001 From: Daniel Dervishi <58835213+DanielDervishi@users.noreply.github.com> Date: Tue, 11 Jul 2023 22:29:38 -0400 Subject: [PATCH 2/4] Replace jQuery document load event handler with javascript native version (#6630) --------- Co-authored-by: David Liu --- .../javascripts/Components/groups_manager.jsx | 43 ++++-- app/assets/javascripts/Grader/marking.js | 38 +++-- app/assets/javascripts/Grader/tabs_boot.js | 4 - app/assets/javascripts/Groups/index.js | 20 ++- .../javascripts/MathJax/mathjax_helpers.js | 18 ++- app/assets/javascripts/Students/edit.js | 14 +- app/assets/javascripts/Students/index.js | 14 +- app/assets/javascripts/Students/new.js | 2 +- app/assets/javascripts/Tags/text_updater.js | 36 +++-- app/assets/javascripts/chart_config.js | 82 +++++----- app/assets/javascripts/check_timeout.js | 14 +- app/assets/javascripts/create_assignment.js | 104 +++++++------ app/assets/javascripts/help-system.js | 22 ++- app/assets/javascripts/layouts.js | 16 +- app/assets/javascripts/modals.js | 24 ++- app/assets/javascripts/notes.js | 34 +++-- app/assets/javascripts/redirect.js | 26 ++-- .../javascripts/upload_button_control.js | 12 +- .../_annotation_list.html.erb | 14 +- .../_annotation_text.html.erb | 31 ++-- app/views/annotation_categories/_boot.js.erb | 2 +- .../annotation_categories/index.html.erb | 4 +- app/views/assignments/_boot.js.erb | 8 +- app/views/assignments/_form.html.erb | 38 ++--- app/views/assignments/show.html.erb | 2 +- app/views/courses/role_switch.js.erb | 8 +- app/views/criteria/_boot.js.erb | 2 +- app/views/criteria/_event_listeners.js.erb | 8 +- app/views/criteria/new.js.erb | 20 ++- .../exam_templates/_assign_errors.js.erb | 6 +- app/views/exam_templates/_boot.js | 2 +- app/views/exam_templates/index.html.erb | 12 +- app/views/grade_entry_forms/_boot.js.erb | 2 +- app/views/grade_entry_forms/_form.html.erb | 4 +- .../_ta_grade_distribution_graph.html.erb | 3 - app/views/groups/assign_scans.html.erb | 144 +++++++++--------- app/views/groups/index.html.erb | 5 +- app/views/main/about.js.erb | 7 +- app/views/main/check_timeout.js.erb | 9 +- app/views/notes/_grouping.html.erb | 32 ++-- .../modal_dialogs/_notes_dialog_script.js.erb | 12 +- app/views/shared/_navigation_warning.js.erb | 20 ++- app/views/tags/_boot.js.erb | 2 +- app/views/tags/_edit_dialog.js.erb | 8 +- app/views/tags/index.html.erb | 4 +- 45 files changed, 522 insertions(+), 410 deletions(-) delete mode 100644 app/assets/javascripts/Grader/tabs_boot.js diff --git a/app/assets/javascripts/Components/groups_manager.jsx b/app/assets/javascripts/Components/groups_manager.jsx index f999fd7216..e90c6c9727 100644 --- a/app/assets/javascripts/Components/groups_manager.jsx +++ b/app/assets/javascripts/Components/groups_manager.jsx @@ -25,18 +25,24 @@ class GroupsManager extends React.Component { componentDidMount() { this.fetchData(); // TODO: Remove reliance on global modal - $(document).ready(() => { - $("#create_group_dialog form").on("ajax:success", () => { - modalCreate.close(); - this.fetchData(); - }); + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", this.componentDidMountCB); + } else { + this.componentDidMountCB(); + } + } - $("#rename_group_dialog form").on("ajax:success", () => { - modal_rename.close(); - this.fetchData(); - }); + componentDidMountCB = () => { + $("#create_group_dialog form").on("ajax:success", () => { + modalCreate.close(); + this.fetchData(); }); - } + + $("#rename_group_dialog form").on("ajax:success", () => { + modal_rename.close(); + this.fetchData(); + }); + }; fetchData = () => { fetch(Routes.course_assignment_groups_path(this.props.course_id, this.props.assignment_id), { @@ -89,14 +95,21 @@ class GroupsManager extends React.Component { } else { modalCreate.open(); $("#new_group_name").val(""); - $(function () { - $("#modal-create-close").click(function () { - modalCreate.close(); - }); - }); + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", this.createGroupCB); + } else { + this.createGroupCB(); + } } }; + createGroupCB = () => { + $("#modal-create-close").click(function () { + modalCreate.close(); + }); + }; + createAllGroups = () => { $.get({ url: Routes.create_groups_when_students_work_alone_course_assignment_groups_path( diff --git a/app/assets/javascripts/Grader/marking.js b/app/assets/javascripts/Grader/marking.js index 167995feca..f2c4f22f6b 100644 --- a/app/assets/javascripts/Grader/marking.js +++ b/app/assets/javascripts/Grader/marking.js @@ -1,21 +1,29 @@ -$(document).ready(function () { - // Handle indenting in the new annotation textarea (2 spaces) - $("#new_annotation_content").keydown(function (e) { - var keyCode = e.keyCode || e.which; +(function () { + const domContentLoadedCB = function () { + // Handle indenting in the new annotation textarea (2 spaces) + $("#new_annotation_content").keydown(function (e) { + var keyCode = e.keyCode || e.which; - if (keyCode == 9) { - e.preventDefault(); - var start = this.selectionStart; - var end = this.selectionEnd; + if (keyCode == 9) { + e.preventDefault(); + var start = this.selectionStart; + var end = this.selectionEnd; - // Add the 2 spaces - this.value = this.value.substring(0, start) + " " + this.value.substring(end); + // Add the 2 spaces + this.value = this.value.substring(0, start) + " " + this.value.substring(end); - // Put caret in correct position - this.selectionStart = this.selectionEnd = start + 2; - } - }); -}); + // Put caret in correct position + this.selectionStart = this.selectionEnd = start + 2; + } + }); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB(); + } +})(); // designate $next_criteria as the currently selected criteria function activeCriterion($next_criteria) { diff --git a/app/assets/javascripts/Grader/tabs_boot.js b/app/assets/javascripts/Grader/tabs_boot.js deleted file mode 100644 index 6139cda518..0000000000 --- a/app/assets/javascripts/Grader/tabs_boot.js +++ /dev/null @@ -1,4 +0,0 @@ -$(document).ready(function () { - $("#code_pane").tabs(); - $("#mark_pane").tabs(); -}); diff --git a/app/assets/javascripts/Groups/index.js b/app/assets/javascripts/Groups/index.js index b9cf1cb0e7..2a518483f0 100644 --- a/app/assets/javascripts/Groups/index.js +++ b/app/assets/javascripts/Groups/index.js @@ -2,9 +2,17 @@ var modalCreate, modalNotesGroup, modalAssignmentGroupReUse = null; -$(document).ready(function () { - window.modal_rename = new ModalMarkus("#rename_group_dialog"); - modalCreate = new ModalMarkus("#create_group_dialog"); - modalNotesGroup = new ModalMarkus("#notes_dialog"); - modalAssignmentGroupReUse = new ModalMarkus("#assignment_group_use_dialog"); -}); +(function () { + const domContentLoadedCB = function () { + window.modal_rename = new ModalMarkus("#rename_group_dialog"); + modalCreate = new ModalMarkus("#create_group_dialog"); + modalNotesGroup = new ModalMarkus("#notes_dialog"); + modalAssignmentGroupReUse = new ModalMarkus("#assignment_group_use_dialog"); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB(); + } +})(); diff --git a/app/assets/javascripts/MathJax/mathjax_helpers.js b/app/assets/javascripts/MathJax/mathjax_helpers.js index 0cb72a44c3..d12e911561 100644 --- a/app/assets/javascripts/MathJax/mathjax_helpers.js +++ b/app/assets/javascripts/MathJax/mathjax_helpers.js @@ -20,8 +20,16 @@ function updatePreview(source, destination) { } } -$(document).ready(function () { - $(document).on("keyup", "#new_annotation_content", function () { - updatePreview("new_annotation_content", "annotation_preview"); - }); -}); +(function () { + const domContentLoadedCB = function () { + $(document).on("keyup", "#new_annotation_content", function () { + updatePreview("new_annotation_content", "annotation_preview"); + }); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB(); + } +})(); diff --git a/app/assets/javascripts/Students/edit.js b/app/assets/javascripts/Students/edit.js index f2c205a96a..7eb5d41b45 100644 --- a/app/assets/javascripts/Students/edit.js +++ b/app/assets/javascripts/Students/edit.js @@ -1,3 +1,11 @@ -$(document).ready(function () { - window.modal_add_section = new ModalMarkus("#add_new_section_dialog"); -}); +(function () { + const domContentLoadedCB = function () { + window.modal_add_section = new ModalMarkus("#add_new_section_dialog"); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB(); + } +})(); diff --git a/app/assets/javascripts/Students/index.js b/app/assets/javascripts/Students/index.js index 5fab33e459..c9ca06200a 100644 --- a/app/assets/javascripts/Students/index.js +++ b/app/assets/javascripts/Students/index.js @@ -1,5 +1,13 @@ var modalNotesGroup = null; -$(document).ready(function () { - modalNotesGroup = new ModalMarkus("#notes_dialog"); -}); +(function () { + const domContentLoadedCB = function () { + modalNotesGroup = new ModalMarkus("#notes_dialog"); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB(); + } +})(); diff --git a/app/assets/javascripts/Students/new.js b/app/assets/javascripts/Students/new.js index f2c205a96a..b7621424f1 100644 --- a/app/assets/javascripts/Students/new.js +++ b/app/assets/javascripts/Students/new.js @@ -1,3 +1,3 @@ -$(document).ready(function () { +document.addEventListener("DOMContentLoaded", function () { window.modal_add_section = new ModalMarkus("#add_new_section_dialog"); }); diff --git a/app/assets/javascripts/Tags/text_updater.js b/app/assets/javascripts/Tags/text_updater.js index 47da4ca7cb..dca7584478 100644 --- a/app/assets/javascripts/Tags/text_updater.js +++ b/app/assets/javascripts/Tags/text_updater.js @@ -1,17 +1,25 @@ -$(document).ready(function () { - var MAX_SIZE = 120; - var current_char = 0; +(function () { + const domContentLoadedCB = function () { + var MAX_SIZE = 120; + var current_char = 0; - // Gets the area where the char count is. - var char_count = $("#descript_amount"); - char_count.html(current_char + "/" + MAX_SIZE); + // Gets the area where the char count is. + var char_count = $("#descript_amount"); + char_count.html(current_char + "/" + MAX_SIZE); - //Sets the max size on the text field. - $("#description").attr("maxlength", MAX_SIZE.toString()); + //Sets the max size on the text field. + $("#description").attr("maxlength", MAX_SIZE.toString()); - // Now, on key up, we update. - $("#description").keyup(function () { - current_char = $("#description").val().length; - char_count.html(current_char + "/" + MAX_SIZE); - }); -}); + // Now, on key up, we update. + $("#description").keyup(function () { + current_char = $("#description").val().length; + char_count.html(current_char + "/" + MAX_SIZE); + }); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB(); + } +})(); diff --git a/app/assets/javascripts/chart_config.js b/app/assets/javascripts/chart_config.js index a1b92a3910..07176f7e64 100644 --- a/app/assets/javascripts/chart_config.js +++ b/app/assets/javascripts/chart_config.js @@ -1,45 +1,49 @@ -// Requires Chart.js to have been loaded. -$(document).ready(function () { - let bars = document.documentElement.style.getPropertyValue("--primary_one"); - let ticksColor = document.documentElement.style.getPropertyValue("--line"); - let labelColor = document.documentElement.style.getPropertyValue("--line"); - let gridLineColor = document.documentElement.style.getPropertyValue("--gridline"); - - Chart.defaults.color = labelColor; - Chart.defaults.borderColor = bars; - Chart.defaults.backgroundColor = bars; - Chart.defaults.elements.bar.backgroundColor = bars; - Chart.defaults.elements.bar.borderColor = bars; - - Chart.overrides.bar.scales.y = { - grid: { - color: gridLineColor, - }, - beginAtZero: true, - ticks: { - color: ticksColor, - }, - }; +(function () { + // Requires Chart.js to have been loaded. + const domContentLoadedCB = function () { + let bars = document.documentElement.style.getPropertyValue("--primary_one"); + let ticksColor = document.documentElement.style.getPropertyValue("--line"); + let labelColor = document.documentElement.style.getPropertyValue("--line"); + let gridLineColor = document.documentElement.style.getPropertyValue("--gridline"); + + Chart.defaults.color = labelColor; + Chart.defaults.borderColor = bars; + Chart.defaults.backgroundColor = bars; + Chart.defaults.elements.bar.backgroundColor = bars; + Chart.defaults.elements.bar.borderColor = bars; + + Chart.overrides.bar.scales.y = { + grid: { + color: gridLineColor, + }, + beginAtZero: true, + ticks: { + color: ticksColor, + }, + }; - Chart.defaults.type = "bar"; + Chart.defaults.type = "bar"; - Chart.overrides.bar.scales.x = { - ticks: { - type: "linear", - color: ticksColor, - }, - grid: { - color: gridLineColor, + Chart.overrides.bar.scales.x = { + ticks: { + type: "linear", + color: ticksColor, + }, + grid: { + color: gridLineColor, + offset: true, + }, offset: true, - }, - offset: true, - }; + }; + + Chart.defaults.plugins.legend.display = false; + Chart.defaults.plugins.legend.labels.fontColor = labelColor; - Chart.defaults.plugins.legend.display = false; - Chart.defaults.plugins.legend.labels.fontColor = labelColor; + Chart.defaults.datasets.bar.barPercentage = 0.9; + Chart.defaults.datasets.bar.categoryPercentage = 0.8; - Chart.defaults.datasets.bar.barPercentage = 0.9; - Chart.defaults.datasets.bar.categoryPercentage = 0.8; + Chart.defaults.animation.duration = 0; + }; - Chart.defaults.animation.duration = 0; -}); + document.addEventListener("DOMContentLoaded", domContentLoadedCB); +})(); diff --git a/app/assets/javascripts/check_timeout.js b/app/assets/javascripts/check_timeout.js index 62a5b318ac..7be62e0633 100644 --- a/app/assets/javascripts/check_timeout.js +++ b/app/assets/javascripts/check_timeout.js @@ -1,5 +1,9 @@ -$(document).ready(() => { - setInterval(() => { - $.get(Routes.check_timeout_main_index_path()); - }, 120000); -}); +(function () { + const domContentLoadedCB = () => { + setInterval(() => { + $.get(Routes.check_timeout_main_index_path()); + }, 120000); + }; + + document.addEventListener("DOMContentLoaded", domContentLoadedCB); +})(); diff --git a/app/assets/javascripts/create_assignment.js b/app/assets/javascripts/create_assignment.js index 425131a1c0..c425d8c988 100644 --- a/app/assets/javascripts/create_assignment.js +++ b/app/assets/javascripts/create_assignment.js @@ -1,62 +1,70 @@ -$(document).ready(function () { - // Change repo folder to be same as short identifier - - $("#assignment_due_date").change(function () { - update_due_date($("#assignment_due_date").val()); - }); - - $("#assignment_assignment_properties_attributes_section_due_dates_type").change(function () { - toggle_assessment_section_properties(this.checked); - }); - toggle_assessment_section_properties( - $("#assignment_assignment_properties_attributes_section_due_dates_type").is(":checked") - ); +(function () { + const domContentLoadedCB = function () { + // Change repo folder to be same as short identifier + + $("#assignment_due_date").change(function () { + update_due_date($("#assignment_due_date").val()); + }); + + $("#assignment_assignment_properties_attributes_section_due_dates_type").change(function () { + toggle_assessment_section_properties(this.checked); + }); + toggle_assessment_section_properties( + $("#assignment_assignment_properties_attributes_section_due_dates_type").is(":checked") + ); - $(".assessment_section_properties_input").change(function () { - if ($("#assignment_due_date").val() === "") { - $("#assignment_due_date").val($(this).val()); - } - }); + $(".assessment_section_properties_input").change(function () { + if ($("#assignment_due_date").val() === "") { + $("#assignment_due_date").val($(this).val()); + } + }); - $("#persist_groups").change(function () { - toggle_persist_groups(this.checked); - }); + $("#persist_groups").change(function () { + toggle_persist_groups(this.checked); + }); - $("#is_group_assignment").change(function () { - toggle_group_assignment(this.checked); - }); + $("#is_group_assignment").change(function () { + toggle_group_assignment(this.checked); + }); - toggle_group_assignment($("#is_group_assignment").is(":checked")); + toggle_group_assignment($("#is_group_assignment").is(":checked")); - $("#assignment_assignment_properties_attributes_student_form_groups").change(function () { - toggle_student_form_groups(this.checked); - }); + $("#assignment_assignment_properties_attributes_student_form_groups").change(function () { + toggle_student_form_groups(this.checked); + }); - $("#assignment_assignment_properties_attributes_allow_remarks").change(function () { - toggle_remark_requests(this.checked); - }); + $("#assignment_assignment_properties_attributes_allow_remarks").change(function () { + toggle_remark_requests(this.checked); + }); - toggle_remark_requests(false); + toggle_remark_requests(false); - $("#submission_rule_fields input[type=radio]").change(change_submission_rule); + $("#submission_rule_fields input[type=radio]").change(change_submission_rule); - change_submission_rule(); // Opens the correct rule + change_submission_rule(); // Opens the correct rule - // Min group size must be <= max group size - // If the min value is larger than the max, make the max this new value - $("#assignment_assignment_properties_attributes_group_min").change(function () { - if (!check_group_size()) { - document.getElementById("assignment_group_max").value = this.value; - } - }); + // Min group size must be <= max group size + // If the min value is larger than the max, make the max this new value + $("#assignment_assignment_properties_attributes_group_min").change(function () { + if (!check_group_size()) { + document.getElementById("assignment_group_max").value = this.value; + } + }); - // If the max value is smaller than the min, make the min this new value - $("#assignment_assignment_properties_attributes_group_max").change(function () { - if (!check_group_size()) { - document.getElementById("assignment_group_min").value = this.value; - } - }); -}); + // If the max value is smaller than the min, make the min this new value + $("#assignment_assignment_properties_attributes_group_max").change(function () { + if (!check_group_size()) { + document.getElementById("assignment_group_min").value = this.value; + } + }); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB(); + } +})(); function check_group_size() { var min = document.getElementById("assignment_group_min").value; diff --git a/app/assets/javascripts/help-system.js b/app/assets/javascripts/help-system.js index ce7f2faca9..f7516fdf17 100644 --- a/app/assets/javascripts/help-system.js +++ b/app/assets/javascripts/help-system.js @@ -1,7 +1,15 @@ -$(document).ready(() => { - $(".help, .title-help, .inline-help") - .click(event => { - $(event.currentTarget).children("p").toggle(); - }) - .prepend(HELP_ICON_HTML); -}); +(function () { + const domContentLoadedCB = () => { + $(".help, .title-help, .inline-help") + .click(event => { + $(event.currentTarget).children("p").toggle(); + }) + .prepend(HELP_ICON_HTML); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB(); + } +})(); diff --git a/app/assets/javascripts/layouts.js b/app/assets/javascripts/layouts.js index e3d03542a8..c2f147ef29 100644 --- a/app/assets/javascripts/layouts.js +++ b/app/assets/javascripts/layouts.js @@ -1,6 +1,10 @@ -$(document).ready(() => { - window.role_switch_modal = new ModalMarkus("#role_switch_dialog"); - window.about_modal = new ModalMarkus("#about_dialog"); - window.timeout_imminent_modal = new ModalMarkus("#timeout_imminent_dialog"); - window.session_expired_modal = new ModalMarkus("#session_expired_dialog"); -}); +(function () { + const domContentLoadedCB = () => { + window.role_switch_modal = new ModalMarkus("#role_switch_dialog"); + window.about_modal = new ModalMarkus("#about_dialog"); + window.timeout_imminent_modal = new ModalMarkus("#timeout_imminent_dialog"); + window.session_expired_modal = new ModalMarkus("#session_expired_dialog"); + }; + + document.addEventListener("DOMContentLoaded", domContentLoadedCB); +})(); diff --git a/app/assets/javascripts/modals.js b/app/assets/javascripts/modals.js index 3e00866245..1997a996c9 100644 --- a/app/assets/javascripts/modals.js +++ b/app/assets/javascripts/modals.js @@ -40,12 +40,20 @@ export class ModalMarkus { } } -$(document).ready(() => { - $(".dialog").each((_, dialog) => { - let open_link = dialog.getAttribute("data-open-link") || undefined; - new ModalMarkus("#" + dialog.id, open_link); - $("#" + dialog.id + "-close").click(function () { - dialog.close(); +(function () { + const domContentLoadedCB = () => { + $(".dialog").each((_, dialog) => { + let open_link = dialog.getAttribute("data-open-link") || undefined; + new ModalMarkus("#" + dialog.id, open_link); + $("#" + dialog.id + "-close").click(function () { + dialog.close(); + }); }); - }); -}); + }; + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB(); + } +})(); diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 834da3593d..beb2d5abb7 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -1,20 +1,24 @@ /** Page-specific event handlers for notes/new.html.erb */ -$(document).ready(function () { - $("#noteable_type select").change(function () { - document.getElementById("working").style.display = ""; +(function () { + const domContentLoadedCB = function () { + $("#noteable_type").change(function () { + document.getElementById("working").style.display = ""; - var params = { - noteable_type: this.value, - authenticity_token: AUTH_TOKEN, - }; + var params = { + noteable_type: this.value, + authenticity_token: AUTH_TOKEN, + }; - $.ajax({ - url: "noteable_object_selector", - data: params, - type: "POST", - }).done(() => { - document.getElementById("working").style.display = "none"; + $.ajax({ + url: "noteable_object_selector", + data: params, + type: "POST", + }).done(() => { + document.getElementById("working").style.display = "none"; + }); }); - }); -}); + }; + + document.addEventListener("DOMContentLoaded", domContentLoadedCB); +})(); diff --git a/app/assets/javascripts/redirect.js b/app/assets/javascripts/redirect.js index 249fc908c4..89b260ef7a 100644 --- a/app/assets/javascripts/redirect.js +++ b/app/assets/javascripts/redirect.js @@ -1,11 +1,15 @@ -$(document).ready(() => { - $(document).ajaxError((event, xhr) => { - if (xhr.status === 403) { - session_expired_modal.open(); - $("#session-expired-modal-close").click(function () { - session_expired_modal.close(); - window.location.reload(); - }); - } - }); -}); +(function () { + const domContentLoadedCB = () => { + $(document).ajaxError((event, xhr) => { + if (xhr.status === 403) { + session_expired_modal.open(); + $("#session-expired-modal-close").click(function () { + session_expired_modal.close(); + window.location.reload(); + }); + } + }); + }; + + document.addEventListener("DOMContentLoaded", domContentLoadedCB); +})(); diff --git a/app/assets/javascripts/upload_button_control.js b/app/assets/javascripts/upload_button_control.js index a9314e3e86..e6d5fc999d 100644 --- a/app/assets/javascripts/upload_button_control.js +++ b/app/assets/javascripts/upload_button_control.js @@ -7,7 +7,7 @@ var upload_id = _get("upload_id"); var button_id = _get("button_id"); var Function_List = { - onReady: function (u_id, b_id) { + onDOMContentLoaded: function (u_id, b_id) { // Ensures only one upload field was entered. if ($(u_id).length != 1) return; @@ -31,8 +31,14 @@ var Function_List = { }, }; -// Finally, executes the jQuery ready command. -$(document).ready(Function_List.onReady(upload_id, button_id)); +if (document.readyState === "loading") { + document.addEventListener( + "DOMContentLoaded", + Function_List.onDOMContentLoaded(upload_id, button_id) + ); +} else { + Function_List.onDOMContentLoaded(upload_id, button_id)(); +} function _get(param_name) { // Gets the correct attribute from the script. diff --git a/app/views/annotation_categories/_annotation_list.html.erb b/app/views/annotation_categories/_annotation_list.html.erb index 5f6e43e27a..8095f4dccc 100644 --- a/app/views/annotation_categories/_annotation_list.html.erb +++ b/app/views/annotation_categories/_annotation_list.html.erb @@ -7,20 +7,18 @@ annotation_category.assignment, annotation_category_id: annotation_category ) %> - <%= javascript_tag nonce: true do %> - $(function() { - $('#add-annotation').click(function(e) { - add_annotation_prompt('<%= path %>'); - e.preventDefault(); - }) - }) - <% end %>
<%= link_to t('annotation_categories.add_annotation'), '#', id: 'add-annotation', class: 'button' %>
+ <%= javascript_tag nonce: true do %> + $('#add-annotation').click(function(e) { + add_annotation_prompt('<%= path %>'); + e.preventDefault(); + }) + <% end %>

<%= t('activerecord.models.annotation.other') %> diff --git a/app/views/annotation_categories/_annotation_text.html.erb b/app/views/annotation_categories/_annotation_text.html.erb index 7746dede9b..f57a70120b 100644 --- a/app/views/annotation_categories/_annotation_text.html.erb +++ b/app/views/annotation_categories/_annotation_text.html.erb @@ -1,16 +1,23 @@ <%= javascript_tag nonce: true do %> - $(function() { - $('#annotation-text-details-edit-<%= annotation_text[:id] %>').click(function(e) { - $('#annotation_text_' + '<%= annotation_text[:id] %>' + '_control').hide(); - $('#annotation_text_' + '<%= annotation_text[:id] %>' + '_edit').show(); - e.preventDefault(); - }); - $('#annotation-text-edit-<%= annotation_text[:id] %>').on("reset", function(e) { - $('#annotation_text_' + '<%= annotation_text[:id] %>' + '_edit').hide(); - $('#annotation_text_' + '<%= annotation_text[:id] %>' + '_control').show(); - e.preventDefault(); - }); - }) + (function(){ + const domContentLoadedCB = function() { + $('#annotation-text-details-edit-<%= annotation_text[:id] %>').click(function(e) { + $('#annotation_text_' + '<%= annotation_text[:id] %>' + '_control').hide(); + $('#annotation_text_' + '<%= annotation_text[:id] %>' + '_edit').show(); + e.preventDefault(); + }); + $('#annotation-text-edit-<%= annotation_text[:id] %>').on("reset", function(e) { + $('#annotation_text_' + '<%= annotation_text[:id] %>' + '_edit').hide(); + $('#annotation_text_' + '<%= annotation_text[:id] %>' + '_control').show(); + e.preventDefault(); + }); + } + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + }else{ + domContentLoadedCB(); + } + })(); <% end %>
  • diff --git a/app/views/annotation_categories/_boot.js.erb b/app/views/annotation_categories/_boot.js.erb index 096457d1ed..39a7733083 100644 --- a/app/views/annotation_categories/_boot.js.erb +++ b/app/views/annotation_categories/_boot.js.erb @@ -31,7 +31,7 @@ } } - $(document).ready(function() { + document.addEventListener("DOMContentLoaded", function() { bindSortable(); function bindSortable() { diff --git a/app/views/annotation_categories/index.html.erb b/app/views/annotation_categories/index.html.erb index 025f4cff41..59dd5a9c3a 100644 --- a/app/views/annotation_categories/index.html.erb +++ b/app/views/annotation_categories/index.html.erb @@ -6,12 +6,12 @@ <%= javascript_include_tag 'MathJax_lib/MathJax.js?config=TeX-AMS-MML_HTMLorMML', nonce: true %> <%= javascript_include_tag 'MathJax/mathjax_helpers', nonce: true %> <%= javascript_tag nonce: true do %> - $(function() { + document.addEventListener("DOMContentLoaded", function() { $('#add-annotation-category').click(function(e) { add_annotation_category('<%= new_course_assignment_annotation_category_path(@current_course, @assignment) %>'); e.preventDefault(); }) - }) + }); <% end %> <% end %> diff --git a/app/views/assignments/_boot.js.erb b/app/views/assignments/_boot.js.erb index 42bff17297..e4b43b69cf 100644 --- a/app/views/assignments/_boot.js.erb +++ b/app/views/assignments/_boot.js.erb @@ -46,7 +46,7 @@ function add_assignment_file() { var new_id = new Date().getTime(); - var input_id = `assignment_assignment_files_attributes_${new_id}_filename'`; + var input_id = `assignment_assignment_files_attributes_${new_id}_filename`; var assignment_file = `

    @@ -139,7 +139,7 @@ } } - $(document).ready(function() { + document.addEventListener("DOMContentLoaded", function() { // Handle periods and hiding/showing things if ($('#assignment_due_date').val()) { create_grace_periods(); @@ -156,8 +156,8 @@ // Handle required fields check_required_fields(); $(document).on("change", $('input[required]'), check_required_fields) - .on("keyup", $('input[required]'), check_required_fields) - .on("click", $('#assignment_file_add_link'), check_required_fields); + .on("keyup", $('input[required]'), check_required_fields) + .on("click", $('#assignment_file_add_link'), check_required_fields); // Initialize flatpickr calendar for different elements in the DOM flatpickr("#assignment_due_date") diff --git a/app/views/assignments/_form.html.erb b/app/views/assignments/_form.html.erb index 49f75c5318..cc3f10ff95 100644 --- a/app/views/assignments/_form.html.erb +++ b/app/views/assignments/_form.html.erb @@ -8,25 +8,25 @@ handlers: [:erb] %> <%= javascript_tag nonce: true do %> - $(function() { - $('#grace-period-add').click(function(e) { - add_period("grace_periods", grace_periods); - e.preventDefault(); - }) - $('#penalty-decay-period-add').click(function(e) { - add_period("penalty_decay_periods", penalty_decay_periods); - e.preventDefault(); - }) - $('#penalty-period-add').click(function(e) { - add_period("penalty_periods", penalty_periods); - e.preventDefault(); - }) - $('#required-file-add').click(function(e) { - add_assignment_file(); - e.preventDefault(); - }) - refresh_event_listeners(); - }) + document.addEventListener("DOMContentLoaded", function() { + $('#grace-period-add').click(function(e) { + add_period("grace_periods", grace_periods); + e.preventDefault(); + }) + $('#penalty-decay-period-add').click(function(e) { + add_period("penalty_decay_periods", penalty_decay_periods); + e.preventDefault(); + }) + $('#penalty-period-add').click(function(e) { + add_period("penalty_periods", penalty_periods); + e.preventDefault(); + }) + $('#required-file-add').click(function(e) { + add_assignment_file(); + e.preventDefault(); + }) + refresh_event_listeners(); + }); <% end %> <% end %> diff --git a/app/views/assignments/show.html.erb b/app/views/assignments/show.html.erb index d44893bca2..d9c7b8e429 100644 --- a/app/views/assignments/show.html.erb +++ b/app/views/assignments/show.html.erb @@ -14,7 +14,7 @@ document.getElementById('working').style.display = ''; }) } - $(document).ready(function() { + document.addEventListener("DOMContentLoaded", function() { invite_modal = new ModalMarkus('#invite_dialog'); $('#invite-student').click(function(e) { invite(); diff --git a/app/views/courses/role_switch.js.erb b/app/views/courses/role_switch.js.erb index 3dd28b6004..288196d25f 100644 --- a/app/views/courses/role_switch.js.erb +++ b/app/views/courses/role_switch.js.erb @@ -2,8 +2,6 @@ $("#role_switch_dialog").html("<%= escape_javascript(render(partial: 'role_switc role_switch_modal.open(); $('#effective_user_login').focus(); -$(function() { - $('#role-switch-modal-cancel').click(function() { - role_switch_modal.close(); - }) -}) +$('#role-switch-modal-cancel').click(function() { + role_switch_modal.close(); +}); diff --git a/app/views/criteria/_boot.js.erb b/app/views/criteria/_boot.js.erb index f7c594309f..684af47090 100644 --- a/app/views/criteria/_boot.js.erb +++ b/app/views/criteria/_boot.js.erb @@ -1,5 +1,5 @@ <%= javascript_tag nonce: true do %> - $(document).ready(function() { + document.addEventListener("DOMContentLoaded", function() { bindSortable(); var ajaxRequest; diff --git a/app/views/criteria/_event_listeners.js.erb b/app/views/criteria/_event_listeners.js.erb index d4fe11ad5f..fde49088f4 100644 --- a/app/views/criteria/_event_listeners.js.erb +++ b/app/views/criteria/_event_listeners.js.erb @@ -1,6 +1,4 @@ -$(() => { - $('#add-criterion-level').click((e) => { - add_level("rubric_form"); - e.preventDefault(); - }) +$('#add-criterion-level').click((e) => { + add_level("rubric_form"); + e.preventDefault(); }) diff --git a/app/views/criteria/new.js.erb b/app/views/criteria/new.js.erb index c2e1e40d0d..7738c1a425 100644 --- a/app/views/criteria/new.js.erb +++ b/app/views/criteria/new.js.erb @@ -4,17 +4,15 @@ $('#criteria_pane_list').prepend( document.getElementById('new_criterion_prompt').focus(); -$(document).ready(function() { - $('input[name=criterion_type]:radio').change(function () { - const max_mark = document.getElementById('max_mark_prompt'); - if (this.value === 'RubricCriterion') { - max_mark.defaultValue = <%= RubricCriterion::DEFAULT_MAX_MARK -%>; - } else if (this.value === 'FlexibleCriterion') { - max_mark.defaultValue = <%= FlexibleCriterion::DEFAULT_MAX_MARK -%>; - } else if (this.value === 'CheckboxCriterion') { - max_mark.defaultValue = <%= CheckboxCriterion::DEFAULT_MAX_MARK -%>; - } - }); +$('input[name=criterion_type]:radio').change(function () { + const max_mark = document.getElementById('max_mark_prompt'); + if (this.value === 'RubricCriterion') { + max_mark.defaultValue = <%= RubricCriterion::DEFAULT_MAX_MARK -%>; + } else if (this.value === 'FlexibleCriterion') { + max_mark.defaultValue = <%= FlexibleCriterion::DEFAULT_MAX_MARK -%>; + } else if (this.value === 'CheckboxCriterion') { + max_mark.defaultValue = <%= CheckboxCriterion::DEFAULT_MAX_MARK -%>; + } }); document.getElementById('new_criterion').addEventListener('ajax:success', event => { diff --git a/app/views/exam_templates/_assign_errors.js.erb b/app/views/exam_templates/_assign_errors.js.erb index 38090830fe..7aa7bcbc11 100644 --- a/app/views/exam_templates/_assign_errors.js.erb +++ b/app/views/exam_templates/_assign_errors.js.erb @@ -48,7 +48,7 @@ function getErrorPages(value) { } } -$(document).ready(function () { +document.addEventListener("DOMContentLoaded", function() { var container = document.getElementById('pdfContainer'); let eventBus = new pdfjsViewer.EventBus(); var pdfViewer = new pdfjsViewer.PDFViewer({ @@ -78,8 +78,8 @@ $(document).ready(function () { }); <% if @next_error.nil? %> - getFile('', pdfViewer); + getFile('', pdfViewer); <% else %> - getFile('<%= "#{@next_error.id}.pdf" -%>', pdfViewer); + getFile('<%= "#{@next_error.id}.pdf" -%>', pdfViewer); <% end %> }); diff --git a/app/views/exam_templates/_boot.js b/app/views/exam_templates/_boot.js index 29525c11a8..7da47f9ba4 100644 --- a/app/views/exam_templates/_boot.js +++ b/app/views/exam_templates/_boot.js @@ -3,7 +3,7 @@ const SCALE_CHANGE = 100; let MIN_SIZE = 600; let jcrop_api; -$(document).ready(function () { +document.addEventListener("DOMContentLoaded", function () { window.modal_create_new = new ModalMarkus("#create_new_template"); $("#generate_exam_modal_submit").click(() => { $("#generate_exam_dialog").trigger("closeModal"); diff --git a/app/views/exam_templates/index.html.erb b/app/views/exam_templates/index.html.erb index 004dac6c36..31bc86069b 100644 --- a/app/views/exam_templates/index.html.erb +++ b/app/views/exam_templates/index.html.erb @@ -3,12 +3,12 @@ <% content_for :head do %> <%= javascript_tag nonce: true do %> <%= render partial: 'boot', formats: [:js] %> - $(function() { - $('#add-exam-template').click(function(e) { - modal_create_new.open(); - e.preventDefault(); - }) - }) + document.addEventListener("DOMContentLoaded", function() { + $('#add-exam-template').click(function(e) { + modal_create_new.open(); + e.preventDefault(); + }) + }); <% end %> <% end %> diff --git a/app/views/grade_entry_forms/_boot.js.erb b/app/views/grade_entry_forms/_boot.js.erb index 40e8d302c6..69c27f7d03 100644 --- a/app/views/grade_entry_forms/_boot.js.erb +++ b/app/views/grade_entry_forms/_boot.js.erb @@ -43,7 +43,7 @@ }) } - $(document).ready(function() { + document.addEventListener("DOMContentLoaded", function() { flatpickr(".datepicker", {enableTime: false, dateFormat: I18n.t('date.format_string.flatpickr')}) }); <% end %> diff --git a/app/views/grade_entry_forms/_form.html.erb b/app/views/grade_entry_forms/_form.html.erb index 1f510bc608..e383a649ba 100644 --- a/app/views/grade_entry_forms/_form.html.erb +++ b/app/views/grade_entry_forms/_form.html.erb @@ -11,13 +11,13 @@ formats: [:js], handlers: [:erb] %> <%= javascript_tag nonce: true do %> - $(function() { + document.addEventListener("DOMContentLoaded", function() { $('#add-new-column').click(function(e) { add_column(); e.preventDefault(); }) refresh_event_listeners(); - }) + }); <% end %> <% end %> diff --git a/app/views/graders/_ta_grade_distribution_graph.html.erb b/app/views/graders/_ta_grade_distribution_graph.html.erb index 8203f96bba..5fa83e755a 100644 --- a/app/views/graders/_ta_grade_distribution_graph.html.erb +++ b/app/views/graders/_ta_grade_distribution_graph.html.erb @@ -3,8 +3,6 @@ <%= javascript_tag nonce: true do %> - // Set up graph - $(document).ready(function () { var ctx = document.getElementById('<%= "a#{assignment.id}_ta_#{ta_id}" %>').getContext('2d'); // Set up data @@ -50,5 +48,4 @@ data: data, options: options }); - }); <% end %> diff --git a/app/views/groups/assign_scans.html.erb b/app/views/groups/assign_scans.html.erb index d7c645d9b7..608ea297ef 100644 --- a/app/views/groups/assign_scans.html.erb +++ b/app/views/groups/assign_scans.html.erb @@ -6,83 +6,87 @@ <%= javascript_tag nonce: true do %> pdfjs.GlobalWorkerOptions.workerSrc = '<%= asset_path('pdf.worker.js') %>'; - - $(document).ready(function () { - $("#names").autocomplete({ - source: function (request, response) { - $.getJSON("get_names", - { - assignment_id: <%= @assignment.id %>, - term: $("#names").val() - }, - response); - }, - minLength: 1, - select: function (event, ui) { - $("#student_id").val(ui.item.id); - } - }).data("ui-autocomplete")._renderItem = function (ul, item) { - return $("

  • ") - .data("ui-autocomplete-item", item) - .append(`
    ${item.label}
    ` + - `${item.id_number} | ${item.user_name}
    `) - .appendTo(ul); - }; - $("#assign_student").submit(function (e) { - e.preventDefault(); - const queryString = $("#assign_student").serialize(); - const url = "assign_student_and_next"; - const requestUrl = `${url}?${queryString}`; - fetch(requestUrl, { - headers: { - Accept: "application/json", + (function(){ + const domContentLoadedCB = function() { + $("#names").autocomplete({ + source: function (request, response) { + $.getJSON("get_names", + { + assignment_id: <%= @assignment.id %>, + term: $("#names").val() + }, + response); }, - }) - .then((response) => { - if (response.ok) { - return response.json(); - } + minLength: 1, + select: function (event, ui) { + $("#student_id").val(ui.item.id); + } + }).data("ui-autocomplete")._renderItem = function (ul, item) { + return $("
  • ") + .data("ui-autocomplete-item", item) + .append(`
    ${item.label}
    ` + + `${item.id_number} | ${item.user_name}
    `) + .appendTo(ul); + }; + $("#assign_student").submit(function (e) { + e.preventDefault(); + const queryString = $("#assign_student").serialize(); + const url = "assign_student_and_next"; + const requestUrl = `${url}?${queryString}`; + fetch(requestUrl, { + headers: { + Accept: "application/json", + }, }) - .then((data) => parseNextScan(data)); - }); + .then((response) => { + if (response.ok) { + return response.json(); + } + }) + .then((data) => parseNextScan(data)); + }); - function parseNextScan(data) { - $("#group_members").empty(); - for (var i = 0; i < data.students.length; i++) { - $("#group_members").append("

    " + data.students[i] + "

    ") - } - $("#assign_student").find("input").val(""); - $("#assign_student").find("#skip").val("1").prop('checked', false); - let current_group = $("#grouping_id").val(); - update_bar(data.num_valid, data.num_total); - // Anytime we advance to another assignment - if (data.grouping_id !== current_group) { - $("#grouping_id").val(data.grouping_id); - $("#group_name").html(data.group_name); - if (data.filelink) { - pdfjs.getDocument({url: data.filelink}).promise.then(function (pdfDocument) { - pdfViewer.setDocument(pdfDocument); - }); + function parseNextScan(data) { + $("#group_members").empty(); + for (var i = 0; i < data.students.length; i++) { + $("#group_members").append("

    " + data.students[i] + "

    ") + } + $("#assign_student").find("input").val(""); + $("#assign_student").find("#skip").val("1").prop('checked', false); + let current_group = $("#grouping_id").val(); + update_bar(data.num_valid, data.num_total); + // Anytime we advance to another assignment + if (data.grouping_id !== current_group) { + $("#grouping_id").val(data.grouping_id); + $("#group_name").html(data.group_name); + if (data.filelink) { + pdfjs.getDocument({url: data.filelink}).promise.then(function (pdfDocument) { + pdfViewer.setDocument(pdfDocument); + }); + } + // When an assignment needs to reload because not meeting minimum group members + // or when all assignments are already assigned + } else { + $("#grouping_id").val(current_group); } - // When an assignment needs to reload because not meeting minimum group members - // or when all assignments are already assigned - } else { - $("#grouping_id").val(current_group); } + + let container = document.getElementById('pdfContainer'); + let eventBus = new pdfjsViewer.EventBus(); + let pdfViewer = new pdfjsViewer.PDFViewer({ + eventBus: eventBus, + container: container, + renderer: 'svg' + }); + eventBus.on('pagesinit', function() { + pdfViewer.currentScaleValue = 'page-fit'; + }); + parseNextScan(<%= raw @data.to_json %>); } - let container = document.getElementById('pdfContainer'); - let eventBus = new pdfjsViewer.EventBus(); - let pdfViewer = new pdfjsViewer.PDFViewer({ - eventBus: eventBus, - container: container, - renderer: 'svg' - }); - eventBus.on('pagesinit', function() { - pdfViewer.currentScaleValue = 'page-fit'; - }); - parseNextScan(<%= raw @data.to_json %>); - }); + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + + })(); function update_bar(v) { $('#progress-meter').attr('value', v); diff --git a/app/views/groups/index.html.erb b/app/views/groups/index.html.erb index 8fd17737e3..7a60f4b5dd 100644 --- a/app/views/groups/index.html.erb +++ b/app/views/groups/index.html.erb @@ -21,8 +21,7 @@ current_duration: '<%= duration_string %>' } ); - }); - $(function() { + $('#assignment-group-use').click(function(e) { modalAssignmentGroupReUse.open(); $('#assignment-group-use-close').click(function(e) { @@ -31,7 +30,7 @@ }) e.preventDefault(); }) - }) + }); <% end %> <% end %> diff --git a/app/views/main/about.js.erb b/app/views/main/about.js.erb index 30593ddd6a..7f91092b06 100644 --- a/app/views/main/about.js.erb +++ b/app/views/main/about.js.erb @@ -1,7 +1,6 @@ document.getElementById('about_dialog').innerHTML = "<%= escape_javascript(render partial: 'about_content') %>"; about_modal.open(); -$(function() { - $('#about-modal-close').click(function() { - about_modal.close(); - }) + +$('#about-modal-close').click(function() { + about_modal.close(); }) diff --git a/app/views/main/check_timeout.js.erb b/app/views/main/check_timeout.js.erb index 336d15c22d..705025de24 100644 --- a/app/views/main/check_timeout.js.erb +++ b/app/views/main/check_timeout.js.erb @@ -1,8 +1,5 @@ timeout_imminent_modal.open(); - -$(function() { - $('#timeout-imminent-modal-close').click(function() { - refreshOrLogout(); - timeout_imminent_modal.close(); - }) +$('#timeout-imminent-modal-close').click(function() { + refreshOrLogout(); + timeout_imminent_modal.close(); }) diff --git a/app/views/notes/_grouping.html.erb b/app/views/notes/_grouping.html.erb index 5e64cf3090..01b4e99971 100644 --- a/app/views/notes/_grouping.html.erb +++ b/app/views/notes/_grouping.html.erb @@ -9,18 +9,26 @@ <% end %> <%= javascript_tag nonce: true do %> - $(() => { - $('#assignment_id').on("change", (evt) => { + (function() { + const domContentLoadedCB = function() { + $('#assignment_id').on("change", (evt) => { document.getElementById('working').style.display = ''; document.getElementById('new-note-save').disabled = true; - $.ajax({ - url: Routes.new_update_groupings_course_notes_path(<%= @current_course.id %>, evt.target.value), - type: 'POST', - data: $(evt.target).serialize() + '&authenticity_token=' + AUTH_TOKEN - }).done(function() { - document.getElementById('working').style.display = 'none'; - document.getElementById('new-note-save').disabled = false; - }); - }) - }) + $.ajax({ + url: Routes.new_update_groupings_course_notes_path(<%= @current_course.id %>, evt.target.value), + type: 'POST', + data: $(evt.target).serialize() + '&authenticity_token=' + AUTH_TOKEN + }).done(function() { + document.getElementById('working').style.display = 'none'; + document.getElementById('new-note-save').disabled = false; + }); + }) + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB() + } + })(); <% end %> diff --git a/app/views/notes/modal_dialogs/_notes_dialog_script.js.erb b/app/views/notes/modal_dialogs/_notes_dialog_script.js.erb index 6571cb758f..72f8052d07 100644 --- a/app/views/notes/modal_dialogs/_notes_dialog_script.js.erb +++ b/app/views/notes/modal_dialogs/_notes_dialog_script.js.erb @@ -12,11 +12,9 @@ if ($('#notes_dialog .inline-button.delete').length) { } }); } -$(function () { - $('#notes_submit').click(function() { - modalNotesGroup.close() - }) - $('#notes-cancel').click(function() { - modalNotesGroup.close() - }) +$('#notes_submit').click(function() { + modalNotesGroup.close() +}) +$('#notes-cancel').click(function() { + modalNotesGroup.close() }) diff --git a/app/views/shared/_navigation_warning.js.erb b/app/views/shared/_navigation_warning.js.erb index 21efdab4bb..5a044670ab 100644 --- a/app/views/shared/_navigation_warning.js.erb +++ b/app/views/shared/_navigation_warning.js.erb @@ -15,11 +15,19 @@ addEventListener("change", () => { onbeforeunload_flag = true - }) + }); - $(function() { - $('input[type="submit"]').click(function () { - submit_clicked = true; - }); - }) + (function() { + const domContentLoadedCB = function() { + $('input[type="submit"]').click(function () { + submit_clicked = true; + }); + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", domContentLoadedCB); + } else { + domContentLoadedCB() + } + })(); <% end %> diff --git a/app/views/tags/_boot.js.erb b/app/views/tags/_boot.js.erb index 19982e56af..9490dec7eb 100644 --- a/app/views/tags/_boot.js.erb +++ b/app/views/tags/_boot.js.erb @@ -1,5 +1,5 @@ <%= javascript_tag nonce: true do %> - $(document).ready(function() { + document.addEventListener("DOMContentLoaded", function() { window.modal_create_new = new ModalMarkus('#create_new_dialog'); window.modal_edit = new ModalMarkus('#edit_tags_dialog'); }); diff --git a/app/views/tags/_edit_dialog.js.erb b/app/views/tags/_edit_dialog.js.erb index 659f1f6367..48263c5e39 100644 --- a/app/views/tags/_edit_dialog.js.erb +++ b/app/views/tags/_edit_dialog.js.erb @@ -1,8 +1,6 @@ $('#edit_tags_dialog').html("<%= escape_javascript(render('tags/edit')) %>"); modal_edit.open(); -$(function() { - $('#edit-tag-dialog-cancel').click(function(e) { - modal_edit.close(); - e.preventDefault(); - }) +$('#edit-tag-dialog-cancel').click(function(e) { + modal_edit.close(); + e.preventDefault(); }) diff --git a/app/views/tags/index.html.erb b/app/views/tags/index.html.erb index 1be6576cfb..cbc5dcc549 100644 --- a/app/views/tags/index.html.erb +++ b/app/views/tags/index.html.erb @@ -5,13 +5,11 @@ <%= javascript_tag nonce: true do %> document.addEventListener('DOMContentLoaded', () => { makeTagTable(document.getElementById('tags_table'), {course_id: <%= @current_course.id %>, assignment_id: <%= @assignment.id %>}); - }); - $(function() { $('#add-tag').click(function(e) { modal_create_new.open(); e.preventDefault(); }) - }) + }); <% end %> <% end %> From 38215c83d026e4bf7612136ce1ac566f10c4ca86 Mon Sep 17 00:00:00 2001 From: David Liu Date: Thu, 13 Jul 2023 18:45:14 -0400 Subject: [PATCH 3/4] Added icons to submission/result action buttons (#6666) --- Changelog.md | 1 + .../Components/Result/left_pane.jsx | 10 +-- .../Components/Result/submission_selector.jsx | 31 +++++-- .../Components/peer_review_table.jsx | 4 + .../javascripts/Components/repo_browser.jsx | 9 +- .../Components/submission_table.jsx | 83 +++++++++++++++---- app/assets/javascripts/fontawesome_config.js | 6 ++ app/assets/stylesheets/common/_icons.scss | 20 +++++ app/assets/stylesheets/common/_markus.scss | 26 +++++- app/assets/stylesheets/common/core.scss | 20 ++++- app/assets/stylesheets/grader.scss | 6 -- 11 files changed, 170 insertions(+), 46 deletions(-) diff --git a/Changelog.md b/Changelog.md index 1a9a1e4aa5..1eb596c847 100644 --- a/Changelog.md +++ b/Changelog.md @@ -26,6 +26,7 @@ - Ensure Jupyter notebook HTML rendering does not require external CDNs (#6656) - Prevent Jupyter notebook from reloading when an annotation is added (#6656) - Added a button allowing graders to view a random incomplete submission (#6641) +- Add icons to submission and result grading action buttons (#6666) ## [v2.2.3] - Fix bug where in some circumstances the wrong result would be displayed to students (#6465) diff --git a/app/assets/javascripts/Components/Result/left_pane.jsx b/app/assets/javascripts/Components/Result/left_pane.jsx index 820408145e..f79dc36179 100644 --- a/app/assets/javascripts/Components/Result/left_pane.jsx +++ b/app/assets/javascripts/Components/Result/left_pane.jsx @@ -1,5 +1,6 @@ import React from "react"; import {Tab, Tabs, TabList, TabPanel} from "react-tabs"; +import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {AnnotationPanel} from "./annotation_panel"; import {FeedbackFilePanel} from "./feedback_file_panel"; @@ -130,11 +131,10 @@ export class LeftPane extends React.Component { this.props.result_id )} > - + diff --git a/app/assets/javascripts/Components/Result/submission_selector.jsx b/app/assets/javascripts/Components/Result/submission_selector.jsx index a1c5c3ff4f..0814cf1a13 100644 --- a/app/assets/javascripts/Components/Result/submission_selector.jsx +++ b/app/assets/javascripts/Components/Result/submission_selector.jsx @@ -23,9 +23,10 @@ export class SubmissionSelector extends React.Component { className={className} disabled={disabled} style={{alignSelf: "flex-end", width: "140px"}} + title={buttonText} > {icon} - {buttonText} + {buttonText} ); }; @@ -33,13 +34,23 @@ export class SubmissionSelector extends React.Component { renderReleaseMarksButton() { if (!this.props.can_release) return ""; - let buttonText, disabled; + let buttonText, disabled, icon; if (this.props.released_to_students) { buttonText = I18n.t("submissions.unrelease_marks"); disabled = false; + icon = ( + + + + + ); } else { buttonText = I18n.t("submissions.release_marks"); disabled = this.props.marking_state !== "complete"; + icon = ; } return ( ); } @@ -61,10 +73,10 @@ export class SubmissionSelector extends React.Component { className="fullscreen-exit" onClick={this.props.toggleFullscreen} style={{alignSelf: "flex-end"}} - title="Alt + Enter" + title={`${I18n.t("results.fullscreen_exit")} (Alt + Enter)`} > - {I18n.t("results.fullscreen_exit")} + {I18n.t("results.fullscreen_exit")} ); } else { @@ -73,10 +85,10 @@ export class SubmissionSelector extends React.Component { className="fullscreen-enter" onClick={this.props.toggleFullscreen} style={{alignSelf: "flex-end"}} - title="Alt + Enter" + title={`${I18n.t("results.fullscreen_enter")} (Alt + Enter)`} > - {I18n.t("results.fullscreen_enter")} + {I18n.t("results.fullscreen_enter")} ); } @@ -88,9 +100,10 @@ export class SubmissionSelector extends React.Component { className={"button"} href={Routes.print_course_result_path(this.props.course_id, this.props.result_id)} style={{alignSelf: "flex-end"}} + title={I18n.t("results.print")} > - {I18n.t("results.print")} + {I18n.t("results.print")} ); } diff --git a/app/assets/javascripts/Components/peer_review_table.jsx b/app/assets/javascripts/Components/peer_review_table.jsx index 9694fd7973..a4e30a9fe1 100644 --- a/app/assets/javascripts/Components/peer_review_table.jsx +++ b/app/assets/javascripts/Components/peer_review_table.jsx @@ -186,23 +186,27 @@ class PeerReviewsActionBox extends React.Component { completeButton = ( ); incompleteButton = ( ); if (this.props.can_manage) { releaseMarksButton = ( ); unreleaseMarksButton = ( ); diff --git a/app/assets/javascripts/Components/repo_browser.jsx b/app/assets/javascripts/Components/repo_browser.jsx index 0a7a85cbb7..00b2b21d66 100644 --- a/app/assets/javascripts/Components/repo_browser.jsx +++ b/app/assets/javascripts/Components/repo_browser.jsx @@ -1,5 +1,6 @@ import React from "react"; import {render} from "react-dom"; +import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {SubmissionFileManager} from "./submission_file_manager"; class RepoBrowser extends React.Component { @@ -167,16 +168,18 @@ class ManualCollectionForm extends React.Component { {I18n.t("submissions.collect.apply_late_penalty")}

    - { if (!confirm(I18n.t("submissions.collect.overwrite_warning"))) { event.preventDefault(); } }} - /> + > + + {I18n.t("submissions.collect.this_revision")} + ); diff --git a/app/assets/javascripts/Components/submission_table.jsx b/app/assets/javascripts/Components/submission_table.jsx index 38d26c35e8..2ce0ae8462 100644 --- a/app/assets/javascripts/Components/submission_table.jsx +++ b/app/assets/javascripts/Components/submission_table.jsx @@ -1,5 +1,6 @@ import React from "react"; import {render} from "react-dom"; +import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; import {CheckboxTable, withSelection} from "./markus_with_selection_hoc"; import { @@ -462,54 +463,100 @@ class SubmissionsActionBox extends React.Component { showReleaseUrlsButton; completeButton = ( - ); incompleteButton = ( - ); if (this.props.can_collect) { collectButton = ( - ); releaseMarksButton = ( - ); unreleaseMarksButton = ( - ); if (this.props.release_with_urls) { showReleaseUrlsButton = ( - ); } } if (this.props.can_run_tests) { runTestsButton = ( - ); } let downloadGroupingFilesButton = ( - ); diff --git a/app/assets/javascripts/fontawesome_config.js b/app/assets/javascripts/fontawesome_config.js index bf983b9791..aee577c46a 100644 --- a/app/assets/javascripts/fontawesome_config.js +++ b/app/assets/javascripts/fontawesome_config.js @@ -20,6 +20,7 @@ import { faExpand, faFile, faFileImage, + faFileImport, faFilePdf, faFolder, faFolderOpen, @@ -33,7 +34,9 @@ import { faPrint, faQuestion, faRefresh, + faRocket, faSignOut, + faSlash, faSquareCheck, faTable, faTrash, @@ -69,6 +72,7 @@ library.add( faExpand, faFile, faFileImage, + faFileImport, faFilePdf, faFolder, faFolderOpen, @@ -82,7 +86,9 @@ library.add( faPrint, faQuestion, faRefresh, + faRocket, faSignOut, + faSlash, faSquareCheck, faTable, faTrash, diff --git a/app/assets/stylesheets/common/_icons.scss b/app/assets/stylesheets/common/_icons.scss index b9f26492ea..c2776a6ede 100644 --- a/app/assets/stylesheets/common/_icons.scss +++ b/app/assets/stylesheets/common/_icons.scss @@ -10,12 +10,32 @@ button > .svg-inline--fa, .button > .svg-inline--fa, a[role='button'] > .svg-inline--fa { padding-right: 5px; + vertical-align: baseline; + + @include breakpoint(mobile) { + padding-right: 0; + } &.no-padding { padding-right: 0; } } +button > .fa-layers, +.button > .fa-layers, +a[role='button'] > .fa-layers { + margin-right: 5px; + vertical-align: baseline; + + @include breakpoint(mobile) { + margin-right: 0; + } + + &.no-margin { + margin-right: 0; + } +} + .fa-triangle-exclamation { color: $severe-alert; } diff --git a/app/assets/stylesheets/common/_markus.scss b/app/assets/stylesheets/common/_markus.scss index 15f5d02643..02c858135a 100644 --- a/app/assets/stylesheets/common/_markus.scss +++ b/app/assets/stylesheets/common/_markus.scss @@ -1173,19 +1173,39 @@ nav { padding: 0.3em 0; width: 100%; + /* Icon-only buttons */ .button { + align-items: center; + display: flex; height: 3em; - line-height: 3em; + justify-content: center; margin: 0 5px; - min-width: 40px; + min-width: 3em; padding: 0 0.4em; + + > .svg-inline--fa:only-child { + height: fit-content; + width: 2em; + } } button { + align-items: center; + display: flex; height: 3em; + justify-content: center; margin: 0 5px; min-width: 100px; - padding: 0.4em; + padding: 0 0.4em; + + @include breakpoint(mobile) { + min-width: 3em; + + > .svg-inline--fa:only-child { + height: fit-content; + width: 2em; + } + } } } diff --git a/app/assets/stylesheets/common/core.scss b/app/assets/stylesheets/common/core.scss index edf2b472f6..02a614c83d 100644 --- a/app/assets/stylesheets/common/core.scss +++ b/app/assets/stylesheets/common/core.scss @@ -417,11 +417,27 @@ th.required::after { button, .button, .form-control { + align-items: center; + display: flex; height: 3em; - line-height: 2.75em; + justify-content: center; margin-left: 1em; min-width: 100px; - padding: 0 0.7em; + padding: 0 0.4em; + + @include breakpoint(mobile) { + min-width: 3em; + } + } +} + +@include breakpoint(mobile) { + button, + .button, + .form-control { + .button-text { + display: none; + } } } diff --git a/app/assets/stylesheets/grader.scss b/app/assets/stylesheets/grader.scss index 03377f8649..f3e1b58107 100644 --- a/app/assets/stylesheets/grader.scss +++ b/app/assets/stylesheets/grader.scss @@ -41,12 +41,6 @@ width: 100%; } -#testviewer { - .rt-action-box { - padding: 0 10px; - } -} - /* codeviewer toolbar */ #codeviewer { .toolbar { From 50ebbc11e95fa221630f2f76068cf55048b47598 Mon Sep 17 00:00:00 2001 From: David Liu Date: Thu, 13 Jul 2023 18:50:28 -0400 Subject: [PATCH 4/4] Grader data performance improvements (#6664) * Improve performance of Ta#percentage_grades_array * Improve performance of Assignment#current_grader_data --- app/models/assignment.rb | 5 +--- app/models/result.rb | 12 ++++---- app/models/ta.rb | 63 ++++++++++------------------------------ spec/models/ta_spec.rb | 10 +++---- 4 files changed, 26 insertions(+), 64 deletions(-) diff --git a/app/models/assignment.rb b/app/models/assignment.rb index 8c994b34f6..bf15b4460b 100644 --- a/app/models/assignment.rb +++ b/app/models/assignment.rb @@ -1030,10 +1030,7 @@ def current_grader_data groups[[group_id, group_name, count]] groups[[group_id, group_name, count]] << { grader: ta, hidden: hidden } unless ta.nil? end - group_sections = {} - self.groupings.includes(:section).find_each do |g| - group_sections[g.id] = g.section&.id - end + group_sections = self.groupings.left_outer_joins(:section).pluck('groupings.id', 'sections.id').to_h groups = groups.map do |k, v| { _id: k[0], diff --git a/app/models/result.rb b/app/models/result.rb index 45e816be0d..9af9ffba39 100644 --- a/app/models/result.rb +++ b/app/models/result.rb @@ -89,12 +89,12 @@ def get_subtotal Result.get_subtotals([self.id], user_visibility: user_visibility)[self.id] end - def self.get_subtotals(result_ids, user_visibility: :ta_visible) - marks = Mark.joins(:criterion) - .where(result_id: result_ids) - .where("criteria.#{user_visibility}": true) - .group(:result_id) - .sum(:mark) + def self.get_subtotals(result_ids, user_visibility: :ta_visible, criterion_ids: nil) + all_marks = Mark.joins(:criterion) + .where(result_id: result_ids, "criteria.#{user_visibility}": true) + all_marks = all_marks.where('criteria.id': criterion_ids) if criterion_ids.present? + + marks = all_marks.group(:result_id).sum(:mark) result_ids.index_with { |r_id| marks[r_id] || 0 } end diff --git a/app/models/ta.rb b/app/models/ta.rb index 9bf5c3bfe2..bf62698781 100644 --- a/app/models/ta.rb +++ b/app/models/ta.rb @@ -18,62 +18,29 @@ def get_groupings_by_assignment(assignment) .includes(:students, :tas, :group, :assignment) end - # Determine the total mark for a particular student, as a percentage - def calculate_total_percent(result, out_of) - total = result.get_total_mark - - percent = BLANK_MARK - - # Check for NA mark or division by 0 - unless total.nil? || out_of == 0 - percent = (total / out_of) * 100 - end - percent - end - - # An array of all the grades for an assignment + # An array of all the grades for an assignment for this TA. + # If TAs are assigned to grade criteria, returns just the subtotal + # for the criteria the TA was assigned. def percentage_grades_array(assignment) - groupings = assignment.groupings - .joins(:tas) - .where(memberships: { role_id: id }) - grades = [] + result_ids = assignment.current_results + .joins(grouping: :tas) + .where(marking_state: Result::MARKING_STATES[:complete], 'roles.id': self.id) + .ids if assignment.assign_graders_to_criteria - criteria_ids = self.criterion_ta_associations.where(assessment_id: assignment.id).pluck(:criterion_id) - out_of = criteria_ids.sum do |criterion_id| - Criterion.find(criterion_id).max_mark - end + criterion_ids = self.criterion_ta_associations.where(assessment_id: assignment.id).pluck(:criterion_id) + out_of = assignment.ta_criteria.where(id: criterion_ids).sum(:max_mark) return [] if out_of.zero? - mark_data = groupings.joins(current_result: :marks) - .where('marks.criterion_id': criteria_ids) - .where.not('marks.mark': nil) - .pluck('results.id', 'marks.mark') - .group_by { |x| x[0] } - mark_data.each_value do |marks| - next if marks.empty? - - subtotal = 0 - has_mark = false - marks.each do |_, mark| - subtotal += mark - has_mark = true - end - grades << subtotal / out_of * 100 if has_mark - end + raw_marks = Result.get_subtotals(result_ids, criterion_ids: criterion_ids).values else out_of = assignment.max_mark - groupings.includes(:current_result).find_each do |grouping| - result = grouping.current_result - unless result.nil? || result.get_total_mark.nil? || result.marking_state != Result::MARKING_STATES[:complete] - percent = calculate_total_percent(result, out_of) - unless percent == BLANK_MARK - grades << percent - end - end - end + return [] if out_of.zero? + + raw_marks = Result.get_total_marks(result_ids).values end - grades + + raw_marks.map { |mark| mark * 100 / out_of } end # Returns grade distribution for a grade entry item for each student diff --git a/spec/models/ta_spec.rb b/spec/models/ta_spec.rb index 9cc4072aa5..60f5841613 100644 --- a/spec/models/ta_spec.rb +++ b/spec/models/ta_spec.rb @@ -21,12 +21,11 @@ context 'when TAs are not assigned criteria' do it 'returns the grades for their assigned groupings based on total marks' do expected = ta.groupings.where(assessment_id: assignment.id).map do |g| - g.current_result.get_total_mark / assignment.max_mark * 100 + be_within(1e-4).of(g.current_result.get_total_mark / assignment.max_mark * 100) end actual = ta.percentage_grades_array(assignment) - expect(actual.length).to eq 2 - expect(actual.sort).to eq expected.sort + expect(actual).to match_array(expected) end end @@ -48,12 +47,11 @@ result.marks.find_by(criterion: criterion1).mark + result.marks.find_by(criterion: criterion2).mark ) - subtotal / out_of * 100 + be_within(1e-4).of(subtotal / out_of * 100) end actual = ta.percentage_grades_array(assignment) - expect(actual.length).to eq 2 - expect(actual.sort).to eq expected.sort + expect(actual).to match_array expected end end end