1// Custom TailwindCSS modals for confirm dialogs 2// 3// Example usage: 4// 5// <%= button_to "Delete", my_path, method: :delete, form: { 6// data: { 7// turbo_confirm: "Are you sure?", 8// turbo_confirm_description: "This will delete your record. Enter the record name to confirm.", 9// turbo_confirm_text: "record name", # require the user to type this before confirming 10// turbo_confirm_accept: "Yes, delete it", 11// turbo_confirm_reject: "No, keep it" 12// } 13// } %> 14 15function insertConfirmModal(message, element, button) { 16 let confirmInput = "" 17 18 // button is nil if using link_to with data-turbo-confirm 19 let confirmText = button?.dataset?.turboConfirmText || element.dataset.turboConfirmText 20 let description = button?.dataset?.turboConfirmDescription || element.dataset.turboConfirmDescription || "" 21 let accept = button?.dataset?.turboConfirmAccept || element.dataset.turboConfirmAccept || "Confirm" 22 let reject = button?.dataset?.turboConfirmReject || element.dataset.turboConfirmReject || "Cancel" 23 24 if (confirmText) { 25 confirmInput = `<input type="text" class="mt-4 form-control" data-behavior="confirm-text" />` 26 } 27 let id = `confirm-modal-${new Date().getTime()}` 28 29 let content = ` 30 <dialog id="${id}" class="modal rounded-lg max-w-md w-full backdrop:backdrop-blur-xs backdrop:bg-black/50"> 31 <form method="dialog"> 32 <div class="bg-white mx-auto rounded-sm shadow-sm p-6 max-w-md dark:bg-gray-900"> 33 <h5 class="text-lg">${message}</h5> 34 <p class="mt-2 text-sm text-gray-700 dark:text-gray-200">${description}</p> 35 36 ${confirmInput} 37 38 <div class="flex justify-end items-center flex-wrap gap-2 mt-4"> 39 <button value="cancel" class="btn btn-secondary">${reject}</button> 40 <button value="confirm" class="btn btn-danger">${accept}</button> 41 </div> 42 </div> 43 </form> 44 </dialog> 45 ` 46 47 document.body.insertAdjacentHTML('beforeend', content) 48 let modal = document.getElementById(id) 49 50 // Focus on the first button in the modal after rendering 51 modal.querySelector("button").focus() 52 53 // Disable commit button until the value matches confirmText 54 if (confirmText) { 55 let commitButton = modal.querySelector("[value='confirm']") 56 commitButton.disabled = true 57 modal.querySelector("input[data-behavior='confirm-text']").addEventListener("input", (event) => { 58 commitButton.disabled = (event.target.value != confirmText) 59 }) 60 } 61 62 return modal 63} 64 65Turbo.config.forms.confirm = (message, element, button) => { 66 let dialog = insertConfirmModal(message, element, button) 67 dialog.showModal() 68 69 return new Promise((resolve, reject) => { 70 dialog.addEventListener("close", () => { 71 resolve(dialog.returnValue == "confirm") 72 }, { once: true }) 73 }) 74}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.