From 16b056dbd35afd550d686a9e35ac78ee166ff9bc Mon Sep 17 00:00:00 2001 From: Luis Aleixo Date: Tue, 3 Aug 2021 17:56:27 +0200 Subject: [PATCH] Coordinates of each ```location``` passed from the form to the model --- cara/apps/calculator/model_generator.py | 4 + cara/apps/calculator/static/js/form.js | 931 +++++++++--------- .../templates/calculator.form.html.j2 | 3 + 3 files changed, 473 insertions(+), 465 deletions(-) diff --git a/cara/apps/calculator/model_generator.py b/cara/apps/calculator/model_generator.py index 868b7620..276c9e19 100644 --- a/cara/apps/calculator/model_generator.py +++ b/cara/apps/calculator/model_generator.py @@ -51,6 +51,7 @@ class FormData: infected_people: int infected_start: minutes_since_midnight location: str + location_coordinates: str mask_type: str mask_wearing_option: str mechanical_ventilation_type: str @@ -102,6 +103,7 @@ class FormData: 'infected_people': _NO_DEFAULT, 'infected_start': '08:30', 'location': _NO_DEFAULT, + 'location_coordinates': '(46.2044, 6.1432)', 'mask_type': 'Type I', 'mask_wearing_option': 'mask_off', 'mechanical_ventilation_type': 'not-applicable', @@ -604,6 +606,7 @@ def baseline_raw_form_data(): 'infected_people': '1', 'infected_start': '09:00', 'location': 'Geneva', + 'location_coordinates': '(46.2044, 6.1432)', 'mask_type': 'Type I', 'mask_wearing_option': 'mask_off', 'mechanical_ventilation_type': '', @@ -696,3 +699,4 @@ for _field in dataclasses.fields(FormData): _CAST_RULES_FORM_ARG_TO_NATIVE[_field.name] = lambda v: v == '1' _CAST_RULES_NATIVE_TO_FORM_ARG[_field.name] = int + diff --git a/cara/apps/calculator/static/js/form.js b/cara/apps/calculator/static/js/form.js index 548b1cc6..b617e382 100644 --- a/cara/apps/calculator/static/js/form.js +++ b/cara/apps/calculator/static/js/form.js @@ -1,627 +1,628 @@ /* -------HTML structure------- */ function getChildElement(elem) { - // Get the element named in the given element's data-enables attribute. - return $(elem.data("enables")); + // Get the element named in the given element's data-enables attribute. + return $(elem.data("enables")); } function insertErrorFor(referenceNode, text) { - var element = document.createElement("span"); - element.setAttribute("class", "error_text"); - element.classList.add("red_text"); - element.innerHTML = "  " + text; - referenceNode.parentNode.insertBefore(element, referenceNode.nextSibling); + var element = document.createElement("span"); + element.setAttribute("class", "error_text"); + element.classList.add("red_text"); + element.innerHTML = "  " + text; + referenceNode.parentNode.insertBefore(element, referenceNode.nextSibling); } function removeErrorFor(referenceNode) { - $(referenceNode).next('span.error_text').remove(); + $(referenceNode).next('span.error_text').remove(); } /* -------Required fields------- */ function require_fields(obj) { - switch ($(obj).attr('id')) { - case "room_data_volume": - require_room_volume(true); - require_room_dimensions(false); - break; - case "room_data_dimensions": - require_room_volume(false); - require_room_dimensions(true); - break; - case "mechanical_ventilation": - require_mechanical_ventilation(true); - require_natural_ventilation(false); - break; - case "natural_ventilation": - require_mechanical_ventilation(false); - require_natural_ventilation(true); - break; - case "window_sliding": - require_window_width(false); - break; - case "window_hinged": - require_window_width(true); - break; - case "mech_type_air_changes": - require_air_changes(true); - require_air_supply(false); - break; - case "mech_type_air_supply": - require_air_changes(false); - require_air_supply(true); - break; - case "windows_open_periodically": - require_venting(true); - break; - case "windows_open_permanently": - require_venting(false); - break; - case "hepa_yes": - require_hepa(true); - break; - case "hepa_no": - require_hepa(false); - break; - case "mask_on": - require_mask(true); - break; - case "mask_off": - require_mask(false); - break; - case "exposed_lunch_option_no": - case "infected_lunch_option_no": - require_lunch($(obj).attr('id'), false); - break; - case "exposed_lunch_option_yes": - case "infected_lunch_option_yes": - require_lunch($(obj).attr('id'), true); - break; - default: - break; - } + switch ($(obj).attr('id')) { + case "room_data_volume": + require_room_volume(true); + require_room_dimensions(false); + break; + case "room_data_dimensions": + require_room_volume(false); + require_room_dimensions(true); + break; + case "mechanical_ventilation": + require_mechanical_ventilation(true); + require_natural_ventilation(false); + break; + case "natural_ventilation": + require_mechanical_ventilation(false); + require_natural_ventilation(true); + break; + case "window_sliding": + require_window_width(false); + break; + case "window_hinged": + require_window_width(true); + break; + case "mech_type_air_changes": + require_air_changes(true); + require_air_supply(false); + break; + case "mech_type_air_supply": + require_air_changes(false); + require_air_supply(true); + break; + case "windows_open_periodically": + require_venting(true); + break; + case "windows_open_permanently": + require_venting(false); + break; + case "hepa_yes": + require_hepa(true); + break; + case "hepa_no": + require_hepa(false); + break; + case "mask_on": + require_mask(true); + break; + case "mask_off": + require_mask(false); + break; + case "exposed_lunch_option_no": + case "infected_lunch_option_no": + require_lunch($(obj).attr('id'), false); + break; + case "exposed_lunch_option_yes": + case "infected_lunch_option_yes": + require_lunch($(obj).attr('id'), true); + break; + default: + break; + } } function unrequire_fields(obj) { - switch (obj.id) { - case "mechanical_ventilation": - require_mechanical_ventilation(false); - break; - case "natural_ventilation": - require_natural_ventilation(false); - break; - default: - break; - } + switch (obj.id) { + case "mechanical_ventilation": + require_mechanical_ventilation(false); + break; + case "natural_ventilation": + require_natural_ventilation(false); + break; + default: + break; + } } function require_room_volume(option) { - require_input_field("#room_volume", option); - set_disabled_status("#room_volume", !option); + require_input_field("#room_volume", option); + set_disabled_status("#room_volume", !option); } function require_room_dimensions(option) { - require_input_field("#floor_area", option); - require_input_field("#ceiling_height", option); - set_disabled_status("#floor_area", !option); - set_disabled_status("#ceiling_height", !option); + require_input_field("#floor_area", option); + require_input_field("#ceiling_height", option); + set_disabled_status("#floor_area", !option); + set_disabled_status("#ceiling_height", !option); } function require_mechanical_ventilation(option) { - $("#mech_type_air_changes").prop('required', option); - $("#mech_type_air_supply").prop('required', option); - if (!option) { - require_input_field("#air_changes", option); - require_input_field("#air_supply", option); - } + $("#mech_type_air_changes").prop('required', option); + $("#mech_type_air_supply").prop('required', option); + if (!option) { + require_input_field("#air_changes", option); + require_input_field("#air_supply", option); + } } function require_natural_ventilation(option) { - require_input_field("#windows_number", option); - require_input_field("#window_height", option); - require_input_field("#opening_distance", option); - $("#window_sliding").prop('required', option); - $("#window_hinged").prop('required', option); - $("#windows_open_permanently").prop('required', option); - $("#windows_open_periodically").prop('required', option); - if (!option) { - require_input_field("#window_width", option); - require_input_field("#windows_duration", option); - require_input_field("#windows_frequency", option); - } + require_input_field("#windows_number", option); + require_input_field("#window_height", option); + require_input_field("#opening_distance", option); + $("#window_sliding").prop('required', option); + $("#window_hinged").prop('required', option); + $("#windows_open_permanently").prop('required', option); + $("#windows_open_periodically").prop('required', option); + if (!option) { + require_input_field("#window_width", option); + require_input_field("#windows_duration", option); + require_input_field("#windows_frequency", option); + } } function require_window_width(option) { - require_input_field("#window_width", option); - set_disabled_status("#window_width", !option); + require_input_field("#window_width", option); + set_disabled_status("#window_width", !option); } function require_air_changes(option) { - require_input_field("#air_changes", option); - set_disabled_status("#air_changes", !option); + require_input_field("#air_changes", option); + set_disabled_status("#air_changes", !option); } function require_air_supply(option) { - require_input_field("#air_supply", option); - set_disabled_status("#air_supply", !option); + require_input_field("#air_supply", option); + set_disabled_status("#air_supply", !option); } function require_venting(option) { - require_input_field("#windows_duration", option); - require_input_field("#windows_frequency", option); - set_disabled_status("#windows_duration", !option); - set_disabled_status("#windows_frequency", !option); + require_input_field("#windows_duration", option); + require_input_field("#windows_frequency", option); + set_disabled_status("#windows_duration", !option); + set_disabled_status("#windows_frequency", !option); } function require_lunch(id, option) { - var activity = $(document.getElementById(id)).data('lunch-select'); - var startObj = $(".start_time[data-lunch-for='"+activity+"']")[0]; - var startID = '#'+$(startObj).attr('id'); - var finishObj = $(".finish_time[data-lunch-for='"+activity+"']")[0]; - var finishID = '#'+$(finishObj).attr('id'); + var activity = $(document.getElementById(id)).data('lunch-select'); + var startObj = $(".start_time[data-lunch-for='" + activity + "']")[0]; + var startID = '#' + $(startObj).attr('id'); + var finishObj = $(".finish_time[data-lunch-for='" + activity + "']")[0]; + var finishID = '#' + $(finishObj).attr('id'); - require_input_field(startID, option); - require_input_field(finishID, option); - set_disabled_status(startID, !option); - set_disabled_status(finishID, !option); + require_input_field(startID, option); + require_input_field(finishID, option); + set_disabled_status(startID, !option); + set_disabled_status(finishID, !option); - if (!option) { - $(finishID).removeClass("red_border finish_time_error lunch_break_error"); - removeErrorFor(finishObj); - } - else { - if (startObj.value === "" && finishObj.value === "") { - startObj.value = "12:30"; - finishObj.value = "13:30"; + if (!option) { + $(finishID).removeClass("red_border finish_time_error lunch_break_error"); + removeErrorFor(finishObj); + } else { + if (startObj.value === "" && finishObj.value === "") { + startObj.value = "12:30"; + finishObj.value = "13:30"; + } + validateLunchBreak($(startObj).data('time-group')); } - validateLunchBreak($(startObj).data('time-group')); - } } function require_mask(option) { - $("#mask_type_1").prop('required', option); - $("#mask_type_ffp2").prop('required', option); + $("#mask_type_1").prop('required', option); + $("#mask_type_ffp2").prop('required', option); } function require_hepa(option) { - require_input_field("#hepa_amount", option); - set_disabled_status("#hepa_amount", !option); + require_input_field("#hepa_amount", option); + set_disabled_status("#hepa_amount", !option); } function require_input_field(id, option) { - $(id).prop('required', option); - if (!option) { - removeInvalid(id); - } + $(id).prop('required', option); + if (!option) { + removeInvalid(id); + } } function set_disabled_status(id, option) { - if (option) - $(id).addClass("disabled"); - else - $(id).removeClass("disabled"); + if (option) + $(id).addClass("disabled"); + else + $(id).removeClass("disabled"); } function setMaxInfectedPeople() { - $("#training_limit_error").hide(); - var max = $("#total_people").val() + $("#training_limit_error").hide(); + var max = $("#total_people").val() - if ($("#activity_type").val() === "training") { - max = 1; - $("#training_limit_error").show(); - } + if ($("#activity_type").val() === "training") { + max = 1; + $("#training_limit_error").show(); + } - $("#infected_people").attr("max", max); + $("#infected_people").attr("max", max); } function removeInvalid(id) { - if ($(id).hasClass("red_border")) { - $(id).val(""); - $(id).removeClass("red_border"); - removeErrorFor(id); - } + if ($(id).hasClass("red_border")) { + $(id).val(""); + $(id).removeClass("red_border"); + removeErrorFor(id); + } } function on_ventilation_type_change() { - ventilation_types = $('input[type=radio][name=ventilation_type]'); - ventilation_types.each(function (index) { - if (this.checked) { - getChildElement($(this)).show(); - require_fields(this); - } else { - getChildElement($(this)).hide(); - unrequire_fields(this); + ventilation_types = $('input[type=radio][name=ventilation_type]'); + ventilation_types.each(function(index) { + if (this.checked) { + getChildElement($(this)).show(); + require_fields(this); + } else { + getChildElement($(this)).hide(); + unrequire_fields(this); - //Clear invalid inputs for this newly hidden child element - removeInvalid("#"+getChildElement($(this)).find('input').not('input[type=radio]').attr('id')); - } - }); + //Clear invalid inputs for this newly hidden child element + removeInvalid("#" + getChildElement($(this)).find('input').not('input[type=radio]').attr('id')); + } + }); } /* -------UI------- */ function show_disclaimer() { - var dots = document.getElementById("dots"); - var moreText = document.getElementById("more"); - var btnText = document.getElementById("myBtn"); + var dots = document.getElementById("dots"); + var moreText = document.getElementById("more"); + var btnText = document.getElementById("myBtn"); - if (dots.style.display === "none") { - dots.style.display = "inline"; - btnText.innerHTML = "Read more"; - moreText.style.display = "none"; - } else { - dots.style.display = "none"; - btnText.innerHTML = "Read less"; - moreText.style.display = "inline"; - } + if (dots.style.display === "none") { + dots.style.display = "inline"; + btnText.innerHTML = "Read more"; + moreText.style.display = "none"; + } else { + dots.style.display = "none"; + btnText.innerHTML = "Read less"; + moreText.style.display = "inline"; + } } -$("[data-has-radio]").on('click', function(event){ - $($(this).data("has-radio")).click(); +$("[data-has-radio]").on('click', function(event) { + $($(this).data("has-radio")).click(); }); -$("[data-has-radio]").on('change', function(event){ - $($(this).data("has-radio")).click(); +$("[data-has-radio]").on('change', function(event) { + $($(this).data("has-radio")).click(); }); function toggle_split_breaks() { - $("#DIVinfected_breaks").toggle(this.checked); - $("#exposed_break_title").toggle(this.checked); - require_lunch("infected_lunch_option_yes", document.getElementById("infected_dont_have_breaks_with_exposed").checked); + $("#DIVinfected_breaks").toggle(this.checked); + $("#exposed_break_title").toggle(this.checked); + require_lunch("infected_lunch_option_yes", document.getElementById("infected_dont_have_breaks_with_exposed").checked); } /* -------Form validation------- */ function validate_form(form) { - var submit = true; + var submit = true; - // Activity times and lunch break times are co-dependent - // -> So if 1 fails it doesn't make sense to check the rest + // Activity times and lunch break times are co-dependent + // -> So if 1 fails it doesn't make sense to check the rest - //Validate all finish times - $("input[required].finish_time").each(function() { - var activity = $(this).data('lunch-for'); - if (document.getElementById("infected_dont_have_breaks_with_exposed").checked || activity!="infected") { - if (!validateFinishTime(this)) { - submit = false; - } - } - }); - - //Validate all lunch breaks - if (submit) { - $("input[required].start_time[data-lunch-for]").each(function() { - var activity = $(this).data('lunch-for'); - if (document.getElementById("infected_dont_have_breaks_with_exposed").checked || activity!="infected") { - if (!validateLunchBreak($(this).data('time-group'))) { - submit = false; + //Validate all finish times + $("input[required].finish_time").each(function() { + var activity = $(this).data('lunch-for'); + if (document.getElementById("infected_dont_have_breaks_with_exposed").checked || activity != "infected") { + if (!validateFinishTime(this)) { + submit = false; + } } - } }); - } - //Check if breaks length >= activity length - if (submit) { - $("[data-lunch-for]").each(function() { - var activity = $(this).data('lunch-for'); - if (document.getElementById("infected_dont_have_breaks_with_exposed").checked || activity!="infected") { - var activityBreaksObj= document.getElementById("activity_breaks"); - removeErrorFor(activityBreaksObj); + //Validate all lunch breaks + if (submit) { + $("input[required].start_time[data-lunch-for]").each(function() { + var activity = $(this).data('lunch-for'); + if (document.getElementById("infected_dont_have_breaks_with_exposed").checked || activity != "infected") { + if (!validateLunchBreak($(this).data('time-group'))) { + submit = false; + } + } + }); + } - var lunch_mins = 0; - if (document.getElementById(activity+"_lunch_option_yes").checked) { - var lunch_start = document.getElementById(activity+"_lunch_start"); - var lunch_finish = document.getElementById(activity+"_lunch_finish"); - lunch_mins = parseTimeToMins(lunch_finish.value) - parseTimeToMins(lunch_start.value); + //Check if breaks length >= activity length + if (submit) { + $("[data-lunch-for]").each(function() { + var activity = $(this).data('lunch-for'); + if (document.getElementById("infected_dont_have_breaks_with_exposed").checked || activity != "infected") { + var activityBreaksObj = document.getElementById("activity_breaks"); + removeErrorFor(activityBreaksObj); + + var lunch_mins = 0; + if (document.getElementById(activity + "_lunch_option_yes").checked) { + var lunch_start = document.getElementById(activity + "_lunch_start"); + var lunch_finish = document.getElementById(activity + "_lunch_finish"); + lunch_mins = parseTimeToMins(lunch_finish.value) - parseTimeToMins(lunch_start.value); + } + + var coffee_breaks = parseInt(document.querySelector('input[name="' + activity + '_coffee_break_option"]:checked').value); + var coffee_duration = parseInt(document.getElementById(activity + "_coffee_duration").value); + var coffee_mins = coffee_breaks * coffee_duration; + + var activity_start = document.getElementById(activity + "_start"); + var activity_finish = document.getElementById(activity + "_finish"); + var activity_mins = parseTimeToMins(activity_finish.value) - parseTimeToMins(activity_start.value); + + if ((lunch_mins + coffee_mins) >= activity_mins) { + insertErrorFor(activityBreaksObj, "Length of breaks >= Length of " + activity + " presence"); + submit = false; + } + } + }); + } + + //Validate all non zero values + $("input[required].non_zero").each(function() { + if (!validateValue(this)) { + submit = false; } - - var coffee_breaks = parseInt(document.querySelector('input[name="'+activity+'_coffee_break_option"]:checked').value); - var coffee_duration = parseInt(document.getElementById(activity+"_coffee_duration").value); - var coffee_mins = coffee_breaks * coffee_duration; - - var activity_start = document.getElementById(activity+"_start"); - var activity_finish = document.getElementById(activity+"_finish"); - var activity_mins = parseTimeToMins(activity_finish.value) - parseTimeToMins(activity_start.value); - - if ((lunch_mins + coffee_mins) >= activity_mins) { - insertErrorFor(activityBreaksObj, "Length of breaks >= Length of "+activity+" presence"); - submit = false; - } - } }); - } - //Validate all non zero values - $("input[required].non_zero").each(function() { - if (!validateValue(this)) { - submit = false; + + //Validate window venting duration < venting frequency + if (!$("#windows_duration").hasClass("disabled")) { + var windowsDurationObj = document.getElementById("windows_duration"); + var windowsFrequencyObj = document.getElementById("windows_frequency"); + removeErrorFor(windowsFrequencyObj); + + if (parseInt(windowsDurationObj.value) >= parseInt(windowsFrequencyObj.value)) { + insertErrorFor(windowsFrequencyObj, "Duration >= Frequency"); + submit = false; + } } - }); - - //Validate window venting duration < venting frequency - if (!$("#windows_duration").hasClass("disabled")) { - var windowsDurationObj = document.getElementById("windows_duration"); - var windowsFrequencyObj = document.getElementById("windows_frequency"); - removeErrorFor(windowsFrequencyObj); - - if (parseInt(windowsDurationObj.value) >= parseInt(windowsFrequencyObj.value)) { - insertErrorFor(windowsFrequencyObj, "Duration >= Frequency"); - submit = false; - } - } - - return submit; + return submit; } function validateValue(obj) { - $(obj).removeClass("red_border"); - removeErrorFor(obj); + $(obj).removeClass("red_border"); + removeErrorFor(obj); - if (!isLessThanZeroOrEmpty($(obj).val())) { - $(obj).addClass("red_border"); - insertErrorFor(obj, "Value must be > 0"); - return false; - } - return true; + if (!isLessThanZeroOrEmpty($(obj).val())) { + $(obj).addClass("red_border"); + insertErrorFor(obj, "Value must be > 0"); + return false; + } + return true; } function isLessThanZeroOrEmpty(value) { - if (value === "") return true; - if (value <= 0) - return false; - return true; + if (value === "") return true; + if (value <= 0) + return false; + return true; } function validateDate(obj) { - $(obj).removeClass("red_border"); - removeErrorFor(obj); + $(obj).removeClass("red_border"); + removeErrorFor(obj); - if (!isValidDateOrEmpty($(obj).val())) { - $(obj).addClass("red_border"); - insertErrorFor(obj, "Incorrect date format"); - return false; - } - return true; + if (!isValidDateOrEmpty($(obj).val())) { + $(obj).addClass("red_border"); + insertErrorFor(obj, "Incorrect date format"); + return false; + } + return true; } function isValidDateOrEmpty(date) { - if (date === "") return true; - var matches = /^(\d+)[-\/](\d+)[-\/](\d+)$/.exec(date); - if (matches == null) return false; - var d = matches[1]; - var m = matches[2]; - var y = matches[3]; - if (y > 2100 || y < 1900) return false; - var composedDate = new Date(y + '/' + m + '/' + d); - return composedDate.getDate() == d && composedDate.getMonth() + 1 == m && composedDate.getFullYear() == y; + if (date === "") return true; + var matches = /^(\d+)[-\/](\d+)[-\/](\d+)$/.exec(date); + if (matches == null) return false; + var d = matches[1]; + var m = matches[2]; + var y = matches[3]; + if (y > 2100 || y < 1900) return false; + var composedDate = new Date(y + '/' + m + '/' + d); + return composedDate.getDate() == d && composedDate.getMonth() + 1 == m && composedDate.getFullYear() == y; } function validateFinishTime(obj) { - var groupID = $(obj).data('time-group'); - var startObj = $(".start_time[data-time-group='"+groupID+"']")[0]; - var finishObj = $(".finish_time[data-time-group='"+groupID+"']")[0]; + var groupID = $(obj).data('time-group'); + var startObj = $(".start_time[data-time-group='" + groupID + "']")[0]; + var finishObj = $(".finish_time[data-time-group='" + groupID + "']")[0]; - if ($(finishObj).hasClass("finish_time_error")) { - $(finishObj).removeClass("red_border finish_time_error"); - removeErrorFor(finishObj); - } + if ($(finishObj).hasClass("finish_time_error")) { + $(finishObj).removeClass("red_border finish_time_error"); + removeErrorFor(finishObj); + } - //Check if finish time error (takes precedence over lunch break error) - var startTime = parseValToNumber(startObj.value); - var finishTime = parseValToNumber(finishObj.value); - if (startTime >= finishTime) { - $(finishObj).addClass("red_border finish_time_error"); - removeErrorFor(finishObj); - insertErrorFor(finishObj, "Finish time must be after start"); - return false; - } - return true; + //Check if finish time error (takes precedence over lunch break error) + var startTime = parseValToNumber(startObj.value); + var finishTime = parseValToNumber(finishObj.value); + if (startTime >= finishTime) { + $(finishObj).addClass("red_border finish_time_error"); + removeErrorFor(finishObj); + insertErrorFor(finishObj, "Finish time must be after start"); + return false; + } + return true; } function validateLunchBreak(lunchGroup) { - //Valid if lunch break not selected - if(document.getElementById(lunchGroup+"_option_no").checked) - return true; + //Valid if lunch break not selected + if (document.getElementById(lunchGroup + "_option_no").checked) + return true; - var lunchStartObj = $(".start_time[data-time-group='"+lunchGroup+"']")[0]; - var lunchFinishObj = $(".finish_time[data-time-group='"+lunchGroup+"']")[0]; + var lunchStartObj = $(".start_time[data-time-group='" + lunchGroup + "']")[0]; + var lunchFinishObj = $(".finish_time[data-time-group='" + lunchGroup + "']")[0]; - //Skip if finish time error present (it takes precedence over lunch break error) - if ($(lunchStartObj).hasClass("finish_time_error") || $(lunchFinishObj).hasClass("finish_time_error")) - return false; + //Skip if finish time error present (it takes precedence over lunch break error) + if ($(lunchStartObj).hasClass("finish_time_error") || $(lunchFinishObj).hasClass("finish_time_error")) + return false; - removeErrorFor(lunchFinishObj); - var valid = validateLunchTime(lunchStartObj) & validateLunchTime(lunchFinishObj); - if (!valid) { - insertErrorFor(lunchFinishObj, "Lunch break must be within presence times"); - } + removeErrorFor(lunchFinishObj); + var valid = validateLunchTime(lunchStartObj) & validateLunchTime(lunchFinishObj); + if (!valid) { + insertErrorFor(lunchFinishObj, "Lunch break must be within presence times"); + } - return valid; + return valid; } //Check if exposed/infected lunch time within exposed/infected presence times function validateLunchTime(obj) { - var activityGroup = $(obj).data('lunch-for'); - var activityStart = parseValToNumber($(".start_time[data-time-group='"+activityGroup+"']")[0].value); - var activityFinish = parseValToNumber($(".finish_time[data-time-group='"+activityGroup+"']")[0].value); + var activityGroup = $(obj).data('lunch-for'); + var activityStart = parseValToNumber($(".start_time[data-time-group='" + activityGroup + "']")[0].value); + var activityFinish = parseValToNumber($(".finish_time[data-time-group='" + activityGroup + "']")[0].value); - var time = parseValToNumber(obj.value); - $(obj).removeClass("red_border lunch_break_error"); - if ((time < activityStart) || (time > activityFinish)) { - $(obj).addClass("red_border lunch_break_error"); - return false; - } + var time = parseValToNumber(obj.value); + $(obj).removeClass("red_border lunch_break_error"); + if ((time < activityStart) || (time > activityFinish)) { + $(obj).addClass("red_border lunch_break_error"); + return false; + } - return true; + return true; } function parseValToNumber(val) { - return parseInt(val.replace(':',''), 10); + return parseInt(val.replace(':', ''), 10); } function parseTimeToMins(cTime) { - var time = cTime.match(/(\d+):(\d+)/); - return parseInt(time[1]*60) + parseInt(time[2]); + var time = cTime.match(/(\d+):(\d+)/); + return parseInt(time[1] * 60) + parseInt(time[2]); } /* -------On Load------- */ -$(document).ready(function () { +$(document).ready(function() { - //Pre-fill form with known values - (new URL(decodeURIComponent(window.location.href))).searchParams.forEach((value, name) => { + //Pre-fill form with known values + (new URL(decodeURIComponent(window.location.href))).searchParams.forEach((value, name) => { - //If element exists - if(document.getElementsByName(name).length > 0) { - var elemObj = document.getElementsByName(name)[0]; + //If element exists + if (document.getElementsByName(name).length > 0) { + var elemObj = document.getElementsByName(name)[0]; - //Pre-select checked radios - if (elemObj.type === 'radio') { - // Calculator <= 1.5.0 used to send not-applicable in the URL for radios that - // weren't set. Now those are not sent at all, but we keep the behaviour for compatibility. - if (value !== 'not-applicable') { - $('[name="'+name+'"][value="'+value+'"]').prop('checked',true); - } - } - //Pre-select checkboxes - else if (elemObj.type === 'checkbox') { - elemObj.checked = (value==1); - } - - //Pre-select location - else if (elemObj.id === 'location_select') { - var location_option = document.createElement('option'); - location_option.value = value; - location_option.innerHTML = value; - elemObj.append(location_option); - } - - //Ignore 0 (default) values from server side - else if (!(elemObj.classList.contains("non_zero") || elemObj.classList.contains("remove_zero")) || (value != "0.0" && value != "0")) { - elemObj.value = value; - validateValue(elemObj); - } - } - }); - - // When the document is ready, deal with the fact that we may be here - // as a result of a forward/back browser action. If that is the case, update - // the visibility of some of our inputs. - - // Chrome fix - on back button infected break DIV not shown - if (document.getElementById("infected_dont_have_breaks_with_exposed").checked) { - $("#DIVinfected_breaks").show(); - $("#exposed_break_title").show(); - require_lunch("infected_lunch_option_yes", true); - } - - //Check all radio buttons previously selected - $("input[type=radio]:checked").each(function() {require_fields(this)}); - - // When the ventilation_type changes we want to make its respective - // children show/hide. - $("input[type=radio][name=ventilation_type]").change(on_ventilation_type_change); - // Call the function now to handle forward/back button presses in the browser. - on_ventilation_type_change(); - - // Setup the maximum number of people at page load (to handle back/forward), - // and update it when total people is changed. - setMaxInfectedPeople(); - $("#total_people").change(setMaxInfectedPeople); - $("#activity_type").change(setMaxInfectedPeople); - - //Validate all non zero values - $("input[required].non_zero").each(function() {validateValue(this)}); - $(".non_zero").change(function() {validateValue(this)}); - - //Validate all finish times - $("input[required].finish_time").each(function() {validateFinishTime(this)}); - $(".finish_time").change(function() {validateFinishTime(this)}); - $(".start_time").change(function() {validateFinishTime(this)}); - - //Validate lunch times - $(".start_time[data-lunch-for]").each(function() {validateLunchBreak($(this).data('time-group'))}); - $("[data-lunch-for]").change(function() {validateLunchBreak($(this).data('time-group'))}); - $("[data-lunch-break]").change(function() {validateLunchBreak($(this).data('lunch-break'))}); - - $("#location_select").select2({ - ajax: { - url: "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates", - dataType: 'json', - delay: 250, - data: function (params) { - return { - SingleLine: params.term, // search term - f: 'json', - page: params.page, - outFields: 'country', - }; - }, - processResults: function (data, params) { - // parse the results into the format expected by Select2 - // since we are using custom formatting functions we do not need to - // alter the remote JSON data, except to indicate that infinite - // scrolling can be used - params.page = params.page || 1; - - return { - results: data.candidates.map(function(candidate){ - return { - id: candidate.address, - text: candidate.address, - country: candidate.attributes.country, + //Pre-select checked radios + if (elemObj.type === 'radio') { + // Calculator <= 1.5.0 used to send not-applicable in the URL for radios that + // weren't set. Now those are not sent at all, but we keep the behaviour for compatibility. + if (value !== 'not-applicable') { + $('[name="' + name + '"][value="' + value + '"]').prop('checked', true); + } } - }), - pagination: { - more: (params.page * 30) < data.candidates.length - } - }; - }, - cache: true - }, - placeholder: 'Search for a location', - minimumInputLength: 1, - templateResult: formatlocation, - templateSelection: formatLocationSelection - }); + //Pre-select checkboxes + else if (elemObj.type === 'checkbox') { + elemObj.checked = (value == 1); + } + + //Pre-select location + else if (elemObj.id === 'location_select') { + var location_option = document.createElement('option'); + location_option.value = value; + location_option.innerHTML = value; + elemObj.append(location_option); + } + + //Ignore 0 (default) values from server side + else if (!(elemObj.classList.contains("non_zero") || elemObj.classList.contains("remove_zero")) || (value != "0.0" && value != "0")) { + elemObj.value = value; + validateValue(elemObj); + } + } + }); + + // When the document is ready, deal with the fact that we may be here + // as a result of a forward/back browser action. If that is the case, update + // the visibility of some of our inputs. + + // Chrome fix - on back button infected break DIV not shown + if (document.getElementById("infected_dont_have_breaks_with_exposed").checked) { + $("#DIVinfected_breaks").show(); + $("#exposed_break_title").show(); + require_lunch("infected_lunch_option_yes", true); + } + + //Check all radio buttons previously selected + $("input[type=radio]:checked").each(function() { require_fields(this) }); + + // When the ventilation_type changes we want to make its respective + // children show/hide. + $("input[type=radio][name=ventilation_type]").change(on_ventilation_type_change); + // Call the function now to handle forward/back button presses in the browser. + on_ventilation_type_change(); + + // Setup the maximum number of people at page load (to handle back/forward), + // and update it when total people is changed. + setMaxInfectedPeople(); + $("#total_people").change(setMaxInfectedPeople); + $("#activity_type").change(setMaxInfectedPeople); + + //Validate all non zero values + $("input[required].non_zero").each(function() { validateValue(this) }); + $(".non_zero").change(function() { validateValue(this) }); + + //Validate all finish times + $("input[required].finish_time").each(function() { validateFinishTime(this) }); + $(".finish_time").change(function() { validateFinishTime(this) }); + $(".start_time").change(function() { validateFinishTime(this) }); + + //Validate lunch times + $(".start_time[data-lunch-for]").each(function() { validateLunchBreak($(this).data('time-group')) }); + $("[data-lunch-for]").change(function() { validateLunchBreak($(this).data('time-group')) }); + $("[data-lunch-break]").change(function() { validateLunchBreak($(this).data('lunch-break')) }); + + $("#location_select").select2({ + ajax: { + url: "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates", + dataType: 'json', + delay: 250, + data: function(params) { + return { + SingleLine: params.term, // search term + f: 'json', + page: params.page, + outFields: 'country, location', + }; + }, + processResults: function(data, params) { + // parse the results into the format expected by Select2 + // since we are using custom formatting functions we do not need to + // alter the remote JSON data, except to indicate that infinite + // scrolling can be used + params.page = params.page || 1; + + return { + results: data.candidates.map(function(candidate) { + return { + id: candidate.address, + text: candidate.address, + country: candidate.attributes.country, + latitude: String(candidate.location.x), + longitude: String(candidate.location.y), + } + }), + pagination: { + more: (params.page * 30) < data.candidates.length + } + }; + }, + cache: true + }, + placeholder: 'Search for a location', + minimumInputLength: 1, + templateResult: formatlocation, + templateSelection: formatLocationSelection + }); }); function formatlocation(location) { - if (location.loading) { - return location.text; - } + if (location.loading) { + return location.text; + } - var $container = $( - "
" + - "
" + + var $container = $( + "
" + + "
" + "
" + - "
" + - "
" - ); + "
" + + "
" + ); - $container.find(".select2-result-location__title").text(location.text + " (" + location.country + ")"); - - return $container; + $container.find(".select2-result-location__title").text(location.text + " (" + location.country + ")"); + return $container; } function formatLocationSelection(location) { - return location.text; + $(document.getElementById("coordinates_input").value = (location.latitude + ',' + location.longitude)); + return location.text; } /* -------Debugging------- */ function debug_submit(form) { - //Prevent default posting of form - put here to work in case of errors - event.preventDefault(); + //Prevent default posting of form - put here to work in case of errors + event.preventDefault(); - //Serialize the data in the form - var serializedData = objectifyForm($(form).serializeArray()); + //Serialize the data in the form + var serializedData = objectifyForm($(form).serializeArray()); - console.log(serializedData); + console.log(serializedData); - return false; //don't submit + return false; //don't submit } function objectifyForm(formArray) { - var returnArray = {}; - for (var i = 0; i < formArray.length; i++) - returnArray[formArray[i]['name']] = formArray[i]['value']; - return returnArray; -} + var returnArray = {}; + for (var i = 0; i < formArray.length; i++) + returnArray[formArray[i]['name']] = formArray[i]['value']; + return returnArray; +} \ No newline at end of file diff --git a/cara/apps/calculator/templates/calculator.form.html.j2 b/cara/apps/calculator/templates/calculator.form.html.j2 index 58ce5d5c..b39a54d4 100644 --- a/cara/apps/calculator/templates/calculator.form.html.j2 +++ b/cara/apps/calculator/templates/calculator.form.html.j2 @@ -109,6 +109,9 @@ v{{ calculator_version }} Please sen +