diff --git a/app/assets/javascripts/administrate_batch_actions/script.js b/app/assets/javascripts/administrate_batch_actions/script.js index 74508a1..45b3fb1 100644 --- a/app/assets/javascripts/administrate_batch_actions/script.js +++ b/app/assets/javascripts/administrate_batch_actions/script.js @@ -1,13 +1,25 @@ -const init = function() { - var buttons = document.querySelectorAll("[data-batch-action-option='button']"); - var checkboxes = document.querySelectorAll("[data-batch-action-option='checkbox']"); - var selectAllCheckboxes = document.querySelector("[data-batch-action-option='select_all']"); +const boundForms = new WeakSet(); +const boundCheckboxes = new WeakSet(); +const boundSelectAllCheckboxes = new WeakSet(); - if (selectAllCheckboxes && checkboxes && buttons) { +const init = function () { + var buttons = document.querySelectorAll( + "[data-batch-action-option='button']", + ); + const forms = document.querySelectorAll( + "form:has([data-batch-action-option='button'])", + ); + var checkboxes = document.querySelectorAll( + "[data-batch-action-option='checkbox']", + ); + var selectAllCheckboxes = document.querySelector( + "[data-batch-action-option='select_all']", + ); - window.onpageshow = function(event) { - if (selectedItemIds()) { - checkboxes.forEach(function(checkbox) { + if (selectAllCheckboxes && checkboxes && buttons) { + window.onpageshow = function (event) { + if (selectedItemIds() && selectedItemIds().length === 0) { + checkboxes.forEach(function (checkbox) { checkbox.checked = false; }); @@ -15,57 +27,98 @@ const init = function() { } }; - selectAllCheckboxes.addEventListener('click', function(){ - checkboxes.forEach(function(checkbox) { - checkbox.checked = selectAllCheckboxes.checked; + if (!isBoundElement(boundSelectAllCheckboxes, selectAllCheckboxes)) { + boundSelectAllCheckboxes.add(selectAllCheckboxes); + + selectAllCheckboxes.addEventListener("click", function () { + checkboxes.forEach(function (checkbox) { + checkbox.checked = selectAllCheckboxes.checked; + }); + + checkAndToggleActionButtons(); }); + } - checkAndToggleActionButtons(); - }); + forms.forEach(function (form) { + if (isBoundElement(boundForms, form)) return; + boundForms.add(form); + + const confirmMessage = + form.querySelector("[data-confirm]")?.dataset?.confirm || + "Are you sure you want to submit this form?"; - buttons.forEach(function(button){ - button.addEventListener('click', function(event){ - button.href += '?' + selectedItemIds() + form.addEventListener("submit", function (event) { + event.preventDefault(); + + if (confirm(confirmMessage) === true) { + selectedItemIds().forEach(function (id) { + const hiddenInput = document.createElement("input"); + hiddenInput.type = "hidden"; + hiddenInput.name = "batch_action_ids[]"; + hiddenInput.value = id; + form.appendChild(hiddenInput); + }); + form.submit(); + } else { + return; + } }); }); - checkboxes.forEach(function(checkbox){ - checkbox.closest('td').addEventListener('click', function(event){ + checkboxes.forEach(function (checkbox) { + if (isBoundElement(boundCheckboxes, checkbox)) { + return; + } + boundCheckboxes.add(checkbox); + + checkbox.closest("td").addEventListener("click", function (event) { event.stopImmediatePropagation(); - }) + }); - checkbox.addEventListener('click', function(event) { + checkbox.addEventListener("click", function (event) { event.stopImmediatePropagation(); checkAndToggleActionButtons(); - }) - }) + }); + }); } function selectedItemIds() { - var ids = Array.prototype.filter.call(checkboxes, function(checkbox) { - if (checkbox.checked) { return checkbox } - }).map(function(checkbox) { - return 'batch_action_ids[]=' + checkbox.value - }).join('&'); + var ids = Array.prototype.filter + .call(checkboxes, function (checkbox) { + if (checkbox.checked) { + return checkbox; + } + }) + .map(function (checkbox) { + return checkbox.value; + }); return ids; } function checkAndToggleActionButtons() { - if (selectedItemIds()) { - buttons.forEach(function(button){ - button.classList.remove('disabled'); - button.removeAttribute('disabled'); + if (selectedItemIds() && selectedItemIds().length > 0) { + buttons.forEach(function (button) { + button.disabled = false; }); } else { - buttons.forEach(function(button){ - button.classList.add('disabled'); - button.setAttribute('disabled', 'disabled'); + buttons.forEach(function (button) { + button.disabled = true; }); } } + + function isBoundElement(boundElement, incomingElement) { + return boundElement.has(incomingElement); + } }; -document.addEventListener("DOMContentLoaded", function() { init() }); -document.addEventListener("turbolinks:load", function() { init() }); -document.addEventListener("turbo:load", function() { init() }); +document.addEventListener("DOMContentLoaded", function () { + init(); +}); +document.addEventListener("turbolinks:load", function () { + init(); +}); +document.addEventListener("turbo:load", function () { + init(); +}); diff --git a/app/views/shared/administrate_batch_actions/_button.html.erb b/app/views/shared/administrate_batch_actions/_button.html.erb index f9eea45..de55928 100644 --- a/app/views/shared/administrate_batch_actions/_button.html.erb +++ b/app/views/shared/administrate_batch_actions/_button.html.erb @@ -1 +1,7 @@ -<%= link_to name, path, class: "btn disabled #{html_options[:class]}", data: { batch_action_option: 'button', confirm: html_options[:confirm] }, method: :post %> +<%= button_to path, + class: "btn #{html_options[:class]}", + data: { batch_action_option: 'button', confirm: html_options[:confirm] }, + method: :post, + disabled: true do %> + <%= name %> +<% end%> diff --git a/app/views/shared/administrate_batch_actions/_checkbox.html.erb b/app/views/shared/administrate_batch_actions/_checkbox.html.erb index accd3d4..2bd4e5a 100644 --- a/app/views/shared/administrate_batch_actions/_checkbox.html.erb +++ b/app/views/shared/administrate_batch_actions/_checkbox.html.erb @@ -1,3 +1,3 @@ - + diff --git a/spec/helpers_spec.rb b/spec/helpers_spec.rb index 58471cc..d8ace46 100644 --- a/spec/helpers_spec.rb +++ b/spec/helpers_spec.rb @@ -2,15 +2,33 @@ RSpec.describe 'Helpers', type: :helper do it 'renders action button (default)' do - expect(helper.administrate_batch_actions_button('Delete All', '/')).to include 'Delete All' + expected_html = <<~HTML +
+ HTML + + expect(helper.administrate_batch_actions_button('Delete All', '/').squish).to include(expected_html.squish) end it 'renders action button (with class)' do - expect(helper.administrate_batch_actions_button('Delete All', '/', class: 'button text-danger')).to include 'Delete All' + expected_html = <<~HTML +
+ HTML + + expect(helper.administrate_batch_actions_button('Delete All', '/', class: 'button text-danger').squish).to include(expected_html.squish) end it 'renders action button (with confirm window)' do - expect(helper.administrate_batch_actions_button('Delete All', '/', class: 'button', confirm: 'Are you sure to do this?')).to include 'Delete All' + expected_html = <<~HTML +
+ HTML + + expect(helper.administrate_batch_actions_button('Delete All', '/', class: 'button', confirm: 'Are you sure to do this?').squish).to include(expected_html.squish) end it 'renders select all' do @@ -18,6 +36,10 @@ end it 'renders checkbox' do - expect(helper.administrate_batch_actions_checkbox(1)).to include '' + expected_html = <<~HTML + + HTML + + expect(helper.administrate_batch_actions_checkbox(1).squish).to include(expected_html.squish) end end