1import { Controller } from "@hotwired/stimulus" 2import { Turbo } from "@hotwired/turbo-rails" 3 4export default class extends Controller { 5 static targets = ["modalContainer"] 6 7 connect() { 8 this.modal = new Modal(this.element, { 9 backdrop: "dynamic", 10 closable: true, 11 onHide: () => { 12 this.frame?.replaceChildren() 13 this.resetWidth() 14 } 15 }) 16 17 document.addEventListener("turbo:before-cache", this.close) 18 document.addEventListener("click", this.handleLoadingClick) 19 } 20 21 disconnect() { 22 document.removeEventListener("turbo:before-cache", this.close) 23 document.removeEventListener("click", this.handleLoadingClick) 24 this.modal?.destroyAndRemoveInstance() 25 } 26 27 captureWidth(event) { 28 this.pendingWidth = event.detail.newFrame?.dataset.width 29 } 30 31 get frame() { 32 return this.element.querySelector("turbo-frame") 33 } 34 35 get hasContent() { 36 return this.frame?.children.length > 0 37 } 38 39 open() { 40 if (this.hasContent) { 41 this.applyWidth() 42 this.modal.show() 43 } 44 } 45 46 applyWidth() { 47 if (!this.hasModalContainerTarget) return 48 const width = this.pendingWidth 49 this.pendingWidth = null 50 if (!width) return 51 52 this.appliedWidth = width 53 this.modalContainerTarget.classList.remove("max-w-lg") 54 this.modalContainerTarget.classList.add(width) 55 } 56 57 resetWidth() { 58 if (!this.hasModalContainerTarget || !this.appliedWidth) return 59 this.modalContainerTarget.classList.remove(this.appliedWidth) 60 this.modalContainerTarget.classList.add("max-w-lg") 61 this.appliedWidth = null 62 } 63 64 close = () => this.modal.hide() 65 66 handleLoadingClick = (event) => { 67 if (!this.frame) return 68 const link = event.target.closest("[data-modal-loading]") 69 if (!link) return 70 71 this.frame.innerHTML = ` 72 <div class="flex justify-center items-center py-12"> 73 <svg class="animate-spin h-8 w-8 text-body" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> 74 <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> 75 <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> 76 </svg> 77 </div>` 78 this.modal.show() 79 } 80 81 submitEnd(event) { 82 if (!event.detail.success) return 83 84 const response = event.detail.fetchResponse?.response 85 if (!response?.redirected) return 86 87 this.close() 88 89 // Skip Turbo.visit() for forms with turbo-frame="_top" to avoid duplicate navigation 90 if (event.target.getAttribute("data-turbo-frame") !== "_top") { 91 Turbo.visit(response.url) 92 } 93 } 94}
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.