From cbc05c9e37250deda071c3a29ed9e6f582f4da50 Mon Sep 17 00:00:00 2001 From: Luis Aleixo Date: Thu, 26 Aug 2021 14:54:17 +0200 Subject: [PATCH] change line breaks --- cara/apps/calculator/static/js/form.js | 1274 ++++++++++++------------ 1 file changed, 642 insertions(+), 632 deletions(-) diff --git a/cara/apps/calculator/static/js/form.js b/cara/apps/calculator/static/js/form.js index ddfbe620..8110aacf 100644 --- a/cara/apps/calculator/static/js/form.js +++ b/cara/apps/calculator/static/js/form.js @@ -1,632 +1,642 @@ -/* -------HTML structure------- */ -function getChildElement(elem) { - // 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); -} - -function removeErrorFor(referenceNode) { - $(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; - } -} - -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; - } -} - -function require_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); -} - -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); - } -} - -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); - } -} - -function require_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); -} - -function require_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); -} - -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'); - - 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"; - } - validateLunchBreak($(startObj).data('time-group')); - } -} - -function require_mask(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); -} - -function require_input_field(id, option) { - $(id).prop('required', option); - if (!option) { - removeInvalid(id); - } -} - -function set_disabled_status(id, option) { - if (option) - $(id).addClass("disabled"); - else - $(id).removeClass("disabled"); -} - -function setMaxInfectedPeople() { - $("#training_limit_error").hide(); - var max = $("#total_people").val() - - if ($("#activity_type").val() === "training") { - max = 1; - $("#training_limit_error").show(); - } - - $("#infected_people").attr("max", max); -} - -function removeInvalid(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); - - //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"); - - 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('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); -} - -/* -------Form validation------- */ -function validate_form(form) { - 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 - - //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; - } - } - }); - } - - //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; - } - }); - - - //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; -} - -function validateValue(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; -} - -function isLessThanZeroOrEmpty(value) { - if (value === "") return true; - if (value <= 0) - return false; - return true; -} - -function validateDate(obj) { - $(obj).removeClass("red_border"); - removeErrorFor(obj); - - 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; -} - -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]; - - 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; -} - -function validateLunchBreak(lunchGroup) { - //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]; - - //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"); - } - - 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 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; -} - -function parseValToNumber(val) { - return parseInt(val.replace(':',''), 10); -} - -function parseTimeToMins(cTime) { - var time = cTime.match(/(\d+):(\d+)/); - return parseInt(time[1]*60) + parseInt(time[2]); -} - -/* -------On Load------- */ -$(document).ready(function () { - - //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]; - - //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, 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: candidate.location.y, - longitude: candidate.location.x, - } - }), - 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; - } - - var $container = $( - "
" + - "
" + - "
" + - "
" + - "
" - ); - - $container.find(".select2-result-location__title").text(location.text + " (" + location.country + ")"); - return $container; -} - -function formatLocationSelection(location) { - if (location.latitude != null && location.latitude != null) { - console.log('setting!'); - console.log($('input[name="location_latitude"]')); - $('input[name="location_latitude"]').val(location.latitude); - $('input[name="location_longitude"]').val(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(); - - //Serialize the data in the form - var serializedData = objectifyForm($(form).serializeArray()); - - console.log(serializedData); - - 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; -} +/* -------HTML structure------- */ +function getChildElement(elem) { + // 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); +} + +function removeErrorFor(referenceNode) { + $(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; + } +} + +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; + } +} + +function require_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); +} + +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); + } +} + +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); + } +} + +function require_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); +} + +function require_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); +} + +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'); + + 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"; + } + validateLunchBreak($(startObj).data('time-group')); + } +} + +function require_mask(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); +} + +function require_input_field(id, option) { + $(id).prop('required', option); + if (!option) { + removeInvalid(id); + } +} + +function set_disabled_status(id, option) { + if (option) + $(id).addClass("disabled"); + else + $(id).removeClass("disabled"); +} + +function setMaxInfectedPeople() { + $("#training_limit_error").hide(); + var max = $("#total_people").val() + + if ($("#activity_type").val() === "training") { + max = 1; + $("#training_limit_error").show(); + } + + $("#infected_people").attr("max", max); +} + +function removeInvalid(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); + + //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"); + + 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('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); +} + +/* -------Form validation------- */ +function validate_form(form) { + 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 + + //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; + } + } + }); + } + + //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; + } + }); + + + //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; +} + +function validateValue(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; +} + +function isLessThanZeroOrEmpty(value) { + if (value === "") return true; + if (value <= 0) + return false; + return true; +} + +function validateDate(obj) { + $(obj).removeClass("red_border"); + removeErrorFor(obj); + + 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; +} + +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]; + + 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; +} + +function validateLunchBreak(lunchGroup) { + //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]; + + //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"); + } + + 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 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; +} + +function parseValToNumber(val) { + return parseInt(val.replace(':',''), 10); +} + +function parseTimeToMins(cTime) { + var time = cTime.match(/(\d+):(\d+)/); + return parseInt(time[1]*60) + parseInt(time[2]); +} + +/* -------On Load------- */ +$(document).ready(function () { + + //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]; + + //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); + } + //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: candidate.location.y, + longitude: candidate.location.x, + } + }), + 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; +} + +var $container = $( + "
" + + "
" + + "
" + + "
" + + "
" +); + +$container.find(".select2-result-location__title").text(location.text + " (" + location.country + ")"); + return $container; +} + +function formatLocationSelection(location) { + if (location.latitude != null && location.latitude != null) { + console.log('setting!'); + console.log($('input[name="location_latitude"]')); + $('input[name="location_latitude"]').val(location.latitude); + $('input[name="location_longitude"]').val(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(); + + //Serialize the data in the form + var serializedData = objectifyForm($(form).serializeArray()); + + console.log(serializedData); + + 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; +}