diff --git a/app/assets/javascripts/inline_replacements.js b/app/assets/javascripts/inline_replacements.js index b307df32a5d..9ade199b0f9 100644 --- a/app/assets/javascripts/inline_replacements.js +++ b/app/assets/javascripts/inline_replacements.js @@ -16,6 +16,29 @@ function enableButton(button) { .removeClass('disabled'); }; +function restoreModalFocus(triggerElement, options) { + options = Object.assign({ + fallbackElement: document.body, + delay: 100 + }, options); + + setTimeout(function() { + if (triggerElement && triggerElement.offsetParent !== null) { + triggerElement.focus(); + return; + } + + if (options.fallbackElement.matches && + options.fallbackElement.matches('button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href]:not([disabled])')) { + options.fallbackElement.focus(); + } else { + options.fallbackElement.querySelector( + 'button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href]:not([disabled])' + ).focus(); + } + }, options.delay); +}; + $(document).on('click', '.remove-child-row-btn', function () { $('tr.child-row:visible').remove(); }); diff --git a/components/financial_assistance/app/assets/javascripts/financial_assistance/benefit.js b/components/financial_assistance/app/assets/javascripts/financial_assistance/benefit.js index 3a75718b23c..25b2c6bbf75 100644 --- a/components/financial_assistance/app/assets/javascripts/financial_assistance/benefit.js +++ b/components/financial_assistance/app/assets/javascripts/financial_assistance/benefit.js @@ -50,14 +50,22 @@ function stopEditing() { function deleteAllBenefits(e, kind) { benefitList = $('.benefits-list.is_' + kind + ' .benefit'); + var self = e.target; if (benefitList.length) { e.preventDefault(); // prompt to delete all these benefits $("#destroyAllBenefits").modal(); + focusTarget = self.parentElement; + $("#destroyAllBenefits").off('hidden.bs.modal').on('hidden.bs.modal', function() { + $('#has_' + kind + '_health_coverage_true').prop('checked', true).trigger('change'); + restoreModalFocus(focusTarget.previousElementSibling); + }); + $("#destroyAllBenefits .modal-cancel-button").click(function(e) { $("#destroyAllBenefits").modal('hide'); $('#has_' + kind + '_health_coverage_true').prop('checked', true).trigger('change'); + restoreModalFocus(focusTarget.previousElementSibling); }); $("#destroyAllBenefits .modal-continue-button").click(function(e) { @@ -73,6 +81,7 @@ function deleteAllBenefits(e, kind) { }); $('select#insurance_kind_is_' + kind).prop('selectedIndex', 0); + restoreModalFocus(focusTarget); }); } } @@ -294,7 +303,12 @@ document.addEventListener("turbolinks:load", function() { var self = this; $("#destroyBenefit").modal(); + // Clean up previous event handlers $("#destroyBenefit .modal-cancel-button").off('click'); + $("#destroyBenefit").off('hidden.bs.modal').on('hidden.bs.modal', function() { + restoreModalFocus(self); + }); + $("#destroyBenefit .modal-cancel-button").on('click', function() { $("#destroyBenefit").modal('hide'); }); @@ -310,18 +324,22 @@ document.addEventListener("turbolinks:load", function() { url: url, success: function() { var benefitList = benefit.parents('.benefits-list')[0]; - var kind = $(self).data('kind') + var kind = $(self).data('kind'); + var fallbackElement = null; $(benefit).remove(); if (benefitList.querySelectorAll('.benefit').length == 0) { - document.getElementById('new-benefit-form-' + kind).classList.remove('hidden'); + fallbackElement = document.getElementById('new-benefit-form-' + kind); $('select#insurance_kind_' + kind).prop('selectedIndex', 0); document.getElementById('add_new_benefit_kind_' + kind).classList.add('hidden'); } else { - document.getElementById('add_new_benefit_kind_' + kind).classList.remove('hidden'); + fallbackElement = document.getElementById('add_new_benefit_kind_' + kind); } - stopEditing() + + fallbackElement.classList.remove('hidden'); + stopEditing(); + restoreModalFocus(self, { fallbackElement: fallbackElement }); } }); }); @@ -349,14 +367,28 @@ document.addEventListener("turbolinks:load", function() { return 'You have an unsaved benefit, are you sure you want to proceed?'; }); - $(document).on('click', 'a[href]:not(.disabled):not(.benefit-support-modal):not([target="_blank"])', function(e) { + // Use direct binding like income.js instead of event delegation + $('a[href]:not(.disabled):not(.benefit-support-modal):not([target="_blank"])').off('click.unsavedBenefits'); + $('a[href]:not(.disabled):not(.benefit-support-modal):not([target="_blank"])').on('click.unsavedBenefits', function(e) { if (currentlyEditing()) { e.preventDefault(); var self = this; $('#unsavedBenefitChangesWarning').modal('show'); - $('.btn.btn-danger, #leave').click(function() { - window.location.href = $(self).attr('href'); + + $('#unsavedBenefitChangesWarning').off('hidden.bs.modal').on('hidden.bs.modal', function() { + restoreModalFocus(self); + }); + + $('.btn.btn-danger, #leave').on('click.unsavedBenefits', function() { + // these two lines are necessary to prevent the modal from showing again + $('.interaction-click-control-continue').removeClass('disabled'); + $('#nav-buttons a').removeClass('disabled'); + + $('#unsavedBenefitChangesWarning').off('hidden.bs.modal.unsavedBenefits'); + + // re-triggering the click as navigating based on the href got flagged in security check + self.click(); }); return false; @@ -381,7 +413,6 @@ document.addEventListener("turbolinks:load", function() { } else { // prompt to delete all these benefits e.preventDefault(); - // prompt to delete all these dedcutions $("#destroyAllBenefits").modal(); $("#destroyAllBenefits .modal-cancel-button").click(function(e) { @@ -438,6 +469,10 @@ document.addEventListener("turbolinks:load", function() { e.preventDefault(); $("#destroyBenefit").modal(); + $("#destroyBenefit").off('hidden.bs.modal').on('hidden.bs.modal', function() { + restoreModalFocus(self); + }); + $("#destroyBenefit .modal-cancel-button").click(function(e) { $("#destroyBenefit").modal('hide'); }); diff --git a/components/financial_assistance/app/assets/javascripts/financial_assistance/deduction.js b/components/financial_assistance/app/assets/javascripts/financial_assistance/deduction.js index cc3d6d83811..87a09f323bd 100644 --- a/components/financial_assistance/app/assets/javascripts/financial_assistance/deduction.js +++ b/components/financial_assistance/app/assets/javascripts/financial_assistance/deduction.js @@ -106,17 +106,29 @@ $(document).on('turbolinks:load', function () { }) }); - $(document).on('click', 'a[href]:not(.disabled)', function(e) { + $('a[href]:not(.disabled)').off('click'); + $('a[href]:not(.disabled)').on('click', function (e) { if (currentlyEditing()) { e.preventDefault(); var self = this; $('#unsavedDeductionChangesWarning').modal('show'); + + $('button#leave').off('click.unsavedDeduction'); + $('#unsavedDeductionChangesWarning').off('hidden.bs.modal.unsavedDeduction'); + + // restore focus to original link + $('#unsavedDeductionChangesWarning').on('hidden.bs.modal.unsavedDeduction', function() { + restoreModalFocus(self); + }); + $('button#leave').on('click', function() { // these two lines are necessary to prevent the modal from showing again $('.interaction-click-control-continue').removeClass('disabled'); $('#nav-buttons a').removeClass('disabled'); + $('#unsavedDeductionChangesWarning').off('hidden.bs.modal.unsavedDeduction'); + // retriggering the click as navigating based on the href got flagged in security check self.click(); }); @@ -161,8 +173,15 @@ $(document).on('turbolinks:load', function () { var deduction_kind_name = $(this).val().replace(/_/g, ' '); deduction_kind_name = deduction_kind_name.charAt(0).toUpperCase() + deduction_kind_name.slice(1); $('#deduction_kind_modal').text(deduction_kind_name); + + $("#destroyAllDeductions").off('hidden.bs.modal').on('hidden.bs.modal', function() { + restoreModalFocus(self); + }); + + $("#destroyAllDeductions .modal-cancel-button").off('click'); $("#destroyAllDeductions .modal-cancel-button").click(function(e) { $("#destroyAllDeductions").modal('hide'); + restoreModalFocus(self); }); $("#destroyAllDeductions .modal-continue-button").click(function(e) { @@ -170,6 +189,7 @@ $(document).on('turbolinks:load', function () { stopEditingDeduction(); deleteDeductions($(self).parents('.deduction-kind')); + restoreModalFocus(self); }); } }); @@ -205,15 +225,20 @@ $(document).on('turbolinks:load', function () { e.preventDefault(); $("#destroyDeduction").modal(); + $("#destroyDeduction").off('hidden.bs.modal').on('hidden.bs.modal', function() { + restoreModalFocus(self); + }); + $("#destroyDeduction .modal-cancel-button").off('click'); $("#destroyDeduction .modal-cancel-button").on('click', function(e) { $("#destroyDeduction").modal('hide'); + restoreModalFocus(self); }); $("#destroyDeduction .modal-continue-button").off('click'); $("#destroyDeduction .modal-continue-button").on('click', function(e) { $("#destroyDeduction").modal('hide'); - + var focusTarget = self.closest('.deduction-kind').querySelector('button.add_new_deduction_kind'); var url = $(self).parents('.deduction').attr('id').replace('deduction_', 'deductions/'); $.ajax({ type: 'DELETE', @@ -221,8 +246,10 @@ $(document).on('turbolinks:load', function () { success: function() { if ($(self).parents('.deductions-list').find('.deduction').length == 1) { // reset kind if this is the last deduction for the kind resetDeductionKind(self); + focusTarget = self.closest('.deduction-kind').querySelector('input[type="checkbox"]'); } $(self).parents('.deduction').remove(); + restoreModalFocus(focusTarget); } }) }); @@ -231,6 +258,7 @@ $(document).on('turbolinks:load', function () { /* DELETING all Deductions on selcting 'no' on Driver Question */ $('#has_deductions_false').on('change', function(e) { self = this; + focusTarget = this.parentElement; //$('#DestroyExistingJobIncomesWarning').modal('show'); if ($('.deductions-list .deduction').length) { e.preventDefault(); @@ -240,6 +268,7 @@ $(document).on('turbolinks:load', function () { $("#destroyAllDeductions .modal-cancel-button").click(function(e) { $("#destroyAllDeductions").modal('hide'); $('#has_deductions_true').prop('checked', true).trigger('change'); + restoreModalFocus(focusTarget); }); $("#destroyAllDeductions .modal-continue-button").click(function(e) { @@ -248,6 +277,7 @@ $(document).on('turbolinks:load', function () { $(".deduction-kinds > .deduction-kind").each(function(_, kind) { deleteDeductions(kind); }); + restoreModalFocus(focusTarget); }); } }); diff --git a/components/financial_assistance/app/assets/javascripts/financial_assistance/income.js b/components/financial_assistance/app/assets/javascripts/financial_assistance/income.js index a0027e7da60..38fd3daaba4 100644 --- a/components/financial_assistance/app/assets/javascripts/financial_assistance/income.js +++ b/components/financial_assistance/app/assets/javascripts/financial_assistance/income.js @@ -104,6 +104,8 @@ function deleteIncomes(kind) { }); }); + // let focusTarget = document.querySelector(`${kind} input[type="checkbox"]`); + // restoreModalFocus(focusTarget); $.when.apply($, requests).done(function () { const args = [].slice.apply(arguments); const responses = requests.length == 1 ? [args] : args; @@ -173,12 +175,18 @@ document.addEventListener('turbolinks:load', function () { var self = this; $('#unsavedIncomeChangesWarning').modal('show'); - $('button#leave').on('click', function () { + + $('#unsavedIncomeChangesWarning').off('hidden.bs.modal').on('hidden.bs.modal.unsavedIncome', function() { + restoreModalFocus(self); + }); + + $('button#leave').off('click.unsavedIncome'); + $('button#leave').on('click.unsavedIncome', function () { // these two lines are necessary to prevent the modal from showing again $('.interaction-click-control-continue').removeClass('disabled'); $('#nav-buttons a').removeClass('disabled'); - // re-triggering the click as navigating based on the href got flagged in security check + $('#unsavedIncomeChangesWarning').off('hidden.bs.modal.unsavedIncome'); self.click(); }); @@ -234,17 +242,25 @@ document.addEventListener('turbolinks:load', function () { /* DELETING all Job Incomes on selcting 'no' on Driver Question */ $('#has_job_income_false').on('change', function (e) { var self = this; + var focusTarget = self.parentElement; //$('#DestroyExistingJobIncomesWarning').modal('show'); if ($('.incomes-list:not(.self-employed-incomes-list) .income').length) { e.preventDefault(); // prompt to delete all these dedcutions $('#destroyAllJobIncomes').modal(); $('#destroyAllJobIncomes .modal-cancel-button').off('click'); + + $("#destroyAllJobIncomes").off('hidden.bs.modal').on('hidden.bs.modal', function() { + $('#has_job_income_true').prop('checked', true).trigger('change'); + restoreModalFocus(focusTarget.previousElementSibling); + }); + $('#destroyAllJobIncomes .modal-cancel-button').on( 'click', function (e) { $('#destroyAllJobIncomes').modal('hide'); $('#has_job_income_true').prop('checked', true).trigger('change'); + restoreModalFocus(focusTarget.previousElementSibling); } ); @@ -267,6 +283,7 @@ document.addEventListener('turbolinks:load', function () { url: url, }); }); + restoreModalFocus(focusTarget); } ); } @@ -277,6 +294,7 @@ document.addEventListener('turbolinks:load', function () { 'change', function (e) { var self = this; + var focusTarget = self.parentElement; //$('#DestroyExistingJobIncomesWarning').modal('show'); if ( $('.ai-an-incomes-list:not(.other-incomes-list) .ai-an-income').length @@ -284,15 +302,16 @@ document.addEventListener('turbolinks:load', function () { e.preventDefault(); // prompt to delete all these dedcutions $('#destroyAllAIANIncomes').modal(); - $('#destroyAllAIANIncomes .modal-cancel-button').off('click'); + $('#destroyAllAIANIncomes .modal-cancel-button').on( 'click', function (e) { - $('#destroyAllAIAN').modal('hide'); + $('#destroyAllAIANIncomes').modal('hide'); $('#has_american_indian_alaskan_native_income_true') .prop('checked', true) .trigger('change'); + restoreModalFocus(focusTarget.previousElementSibling); } ); @@ -322,6 +341,7 @@ document.addEventListener('turbolinks:load', function () { }, }); }); + restoreModalFocus(focusTarget); } ); } @@ -331,6 +351,7 @@ document.addEventListener('turbolinks:load', function () { /* DELETING all Job Incomes on selcting 'no' on Driver Question */ $('#has_unemployment_income_false').on('change', function (e) { var self = this; + var focusTarget = self.parentElement; stopEditingIncome(); //$('#DestroyExistingJobIncomesWarning').modal('show'); if ( @@ -342,6 +363,11 @@ document.addEventListener('turbolinks:load', function () { // prompt to delete all these dedcutions $('#destroyAllUnemploymentIncomes').modal('show'); + $("#destroyAllUnemploymentIncomes").off('hidden.bs.modal').on('hidden.bs.modal', function() { + $('#has_unemployment_income_true').prop('checked', true).trigger('change'); + restoreModalFocus(focusTarget.previousElementSibling); + }); + $('#destroyAllUnemploymentIncomes .modal-cancel-button').off('click'); $('#destroyAllUnemploymentIncomes .modal-cancel-button').on( 'click', @@ -350,6 +376,7 @@ document.addEventListener('turbolinks:load', function () { $('#has_unemployment_income_true') .prop('checked', true) .trigger('change'); + restoreModalFocus(focusTarget.previousElementSibling); } ); @@ -376,6 +403,7 @@ document.addEventListener('turbolinks:load', function () { }, }); }); + restoreModalFocus(focusTarget); } ); } @@ -384,12 +412,18 @@ document.addEventListener('turbolinks:load', function () { /* DELETING all Self Employment Incomes on selcting 'no' on Driver Question */ $('#has_self_employment_income_false').on('change', function (e) { self = this; + var focusTarget = self.parentElement; //$('#DestroyExistingJobIncomesWarning').modal('show'); if ($('.self-employed-incomes-list .income').length) { e.preventDefault(); // prompt to delete all these dedcutions $('#destroyAllSelfEmploymentIncomes').modal(); + $("#destroyAllSelfEmploymentIncomes").off('hidden.bs.modal').on('hidden.bs.modal', function() { + $('#has_self_employment_income_true').prop('checked', true).trigger('change'); + restoreModalFocus(focusTarget.previousElementSibling); + }); + $('#destroyAllSelfEmploymentIncomes .modal-cancel-button').off('click'); $('#destroyAllSelfEmploymentIncomes .modal-cancel-button').on( 'click', @@ -398,6 +432,7 @@ document.addEventListener('turbolinks:load', function () { $('#has_self_employment_income_true') .prop('checked', true) .trigger('change'); + restoreModalFocus(focusTarget.previousElementSibling); } ); @@ -422,6 +457,7 @@ document.addEventListener('turbolinks:load', function () { url: url, }); }); + restoreModalFocus(focusTarget); } ); } @@ -458,11 +494,17 @@ document.addEventListener('turbolinks:load', function () { e.preventDefault(); $('#DestroyJobIncomeWarning').modal(); + $("#DestroyJobIncomeWarning").off('hidden.bs.modal').on('hidden.bs.modal', function() { + restoreModalFocus(self); + }); + $('#DestroyJobIncomeWarning .modal-cancel-button').off('click'); $('#DestroyJobIncomeWarning .modal-cancel-button').on( 'click', function (e) { $('#DestroyJobIncomeWarning').modal('hide'); + // restore focus to original link + restoreModalFocus(self); } ); @@ -470,6 +512,8 @@ document.addEventListener('turbolinks:load', function () { $('#DestroyJobIncomeWarning .modal-continue-button').on( 'click', function (e) { + var focusTargetId = "new-" + self.id.split('-delete-')[0]; + var focusTarget = document.getElementById(focusTargetId); $('#DestroyJobIncomeWarning').modal('hide'); $(self).parents('.income').remove(); @@ -481,6 +525,7 @@ document.addEventListener('turbolinks:load', function () { type: 'delete', url: url, }); + restoreModalFocus(focusTarget); } ); } @@ -495,11 +540,17 @@ document.addEventListener('turbolinks:load', function () { e.preventDefault(); $('#DestroySelfEmplyedIncomeWarning').modal(); + $("#DestroySelfEmplyedIncomeWarning").off('hidden.bs.modal').on('hidden.bs.modal', function() { + restoreModalFocus(self); + }); + $('#DestroySelfEmplyedIncomeWarning .modal-cancel-button').off('click'); $('#DestroySelfEmplyedIncomeWarning .modal-cancel-button').on( 'click', function (e) { $('#DestroySelfEmplyedIncomeWarning').modal('hide'); + // restore focus to original link + restoreModalFocus(self); } ); @@ -509,6 +560,8 @@ document.addEventListener('turbolinks:load', function () { $('#DestroySelfEmplyedIncomeWarning .modal-continue-button').on( 'click', function (e) { + var focusTargetId = self.id.split('-delete-')[0]; + var focusTarget = document.getElementById(focusTargetId); $('#DestroySelfEmplyedIncomeWarning').modal('hide'); $(self).parents('.income').remove(); @@ -520,6 +573,7 @@ document.addEventListener('turbolinks:load', function () { type: 'delete', url: url, }); + restoreModalFocus(focusTarget); } ); } @@ -1098,10 +1152,12 @@ $(document).on('turbolinks:load', function () { e.preventDefault(); $('#destroyAllOtherIncomesOfKind').modal(); $('#destroyAllOtherIncomesOfKind .modal-cancel-button').off('click'); + $('#destroyAllOtherIncomesOfKind .modal-cancel-button').on( 'click', function (e) { $('#destroyAllOtherIncomesOfKind').modal('hide'); + restoreModalFocus(self); } ); @@ -1112,6 +1168,7 @@ $(document).on('turbolinks:load', function () { $('#destroyAllOtherIncomesOfKind').modal('hide'); stopEditingIncome(); deleteIncomes($(self).parents('.other-income-kind')); + restoreModalFocus(self); } ); } @@ -1134,11 +1191,16 @@ $(document).on('turbolinks:load', function () { e.preventDefault(); $('#destroyAllOtherIncomes').modal(); $('#destroyAllOtherIncomes .modal-cancel-button').off('click'); + + let focusTarget = self.parentElement; + $('#destroyAllOtherIncomes .modal-cancel-button').on( 'click', function (e) { $('#destroyAllOtherIncomes').modal('hide'); $('#has_other_income_true').prop('checked', true).trigger('change'); + + restoreModalFocus(focusTarget.previousElementSibling); } ); @@ -1151,6 +1213,7 @@ $(document).on('turbolinks:load', function () { $('.other_income_kinds .other-income-kind').each(function (_, kind) { deleteIncomes($(kind)); }); + restoreModalFocus(focusTarget); } ); } @@ -1223,15 +1286,20 @@ $(document).on('turbolinks:load', function () { e.preventDefault(); $('#destroyOtherIncome').modal(); + $("#destroyOtherIncome").off('hidden.bs.modal').on('hidden.bs.modal', function() { + restoreModalFocus(self); + }); + $('#destroyOtherIncome .modal-cancel-button').off('click'); $('#destroyOtherIncome .modal-cancel-button').on('click', function (e) { $('#destroyOtherIncome').modal('hide'); + restoreModalFocus(self); }); $('#destroyOtherIncome .modal-continue-button').off('click'); $('#destroyOtherIncome .modal-continue-button').on('click', function (e) { $('#destroyOtherIncome').modal('hide'); - + var focusTarget = self.closest('.other-income-kind').querySelector('button.add_new_other_income_kind'); var url = $(self) .parents('.other-income') .attr('id') @@ -1257,8 +1325,10 @@ $(document).on('turbolinks:load', function () { .parents('.other-income-kind') .find('a.interaction-click-control-add-more') .addClass('hide'); + focusTarget = self.closest('.other-income-kind').querySelector('input[type="checkbox"]'); } $(self).parents('.other-income').remove(); + restoreModalFocus(focusTarget); }, }); }); @@ -1340,11 +1410,16 @@ $(document).on('turbolinks:load', function () { e.preventDefault(); $('#destroyUnemploymentIncome').modal(); + $("#destroyUnemploymentIncome").off('hidden.bs.modal').on('hidden.bs.modal', function() { + restoreModalFocus(self); + }); + $('#destroyUnemploymentIncome .modal-cancel-button').off('click'); $('#destroyUnemploymentIncome .modal-cancel-button').on( 'click', function (e) { $('#destroyUnemploymentIncome').modal('hide'); + restoreModalFocus(self); } ); @@ -1353,7 +1428,7 @@ $(document).on('turbolinks:load', function () { 'click', function (e) { $('#destroyUnemploymentIncome').modal('hide'); - + var focusTarget = document.getElementById('new-unemployment-income'); var url = $(self) .parents('.unemployment-income') .attr('id') @@ -1374,7 +1449,9 @@ $(document).on('turbolinks:load', function () { $('#has_unemployment_income_false') .prop('checked', true) .trigger('change'); + focusTarget = document.getElementById('has_unemployment_income_false').parentElement; } + restoreModalFocus(focusTarget); }, }); } @@ -1455,12 +1532,13 @@ $(document).on('turbolinks:load', function () { $('#destroyAIANIncome .modal-cancel-button').off('click'); $('#destroyAIANIncome .modal-cancel-button').on('click', function (e) { $('#destroyAIANIncome').modal('hide'); + restoreModalFocus(self); }); $('#destroyAIANIncome .modal-continue-button').off('click'); $('#destroyAIANIncome .modal-continue-button').on('click', function (e) { $('#destroyAIANIncome').modal('hide'); - + var focusTarget = document.getElementById('new-ai-an-income'); var url = $(self) .parents('.ai-an-income') .attr('id') @@ -1478,7 +1556,9 @@ $(document).on('turbolinks:load', function () { $('#has_american_indian_alaskan_native_income_false') .prop('checked', true) .trigger('change'); + focusTarget = document.getElementById('has_american_indian_alaskan_native_income_false').parentElement; } + restoreModalFocus(focusTarget); }, }); });