1// app/javascript/controllers/form_builder_controller.js 2import { Controller } from "@hotwired/stimulus" 3 4export default class extends Controller { 5 static targets = ["fieldList", "previewContainer", "formTitle", "formDescription", "formType"] 6 static values = { 7 formId: String, 8 masjidSlug: String 9 } 10 11 connect() { 12 console.log("Form Builder controller connected") 13 this.setupSortable() 14 this.boundRefresh = this.refreshPreview.bind(this) 15 this.element.addEventListener("field-properties:fieldUpdated", this.boundRefresh) 16 this.element.addEventListener("info-block-options:fieldUpdated", this.boundRefresh) 17 this.element.addEventListener("waiver-field-options:fieldUpdated", this.boundRefresh) 18 this.element.addEventListener("tag-field-options:fieldUpdated", this.boundRefresh) 19 this.element.addEventListener("registrant-builder:fieldUpdated", this.boundRefresh) 20 } 21 22 disconnect() { 23 this.element.removeEventListener("field-properties:fieldUpdated", this.boundRefresh) 24 this.element.removeEventListener("info-block-options:fieldUpdated", this.boundRefresh) 25 this.element.removeEventListener("waiver-field-options:fieldUpdated", this.boundRefresh) 26 this.element.removeEventListener("tag-field-options:fieldUpdated", this.boundRefresh) 27 this.element.removeEventListener("registrant-builder:fieldUpdated", this.boundRefresh) 28 } 29 30 setupSortable() { 31 if (typeof Sortable !== 'undefined') { 32 this.sortable = Sortable.create(this.fieldListTarget, { 33 animation: 150, 34 handle: '.drag-handle', 35 ghostClass: 'bg-gray-100', 36 // Add these options to fix the conflict 37 group: "form-fields", // Give it a unique group name 38 draggable: "[data-field-id]", // Only make existing fields draggable 39 onEnd: this.updateFieldOrder.bind(this) 40 }) 41 } else { 42 console.error('Sortable.js is not available. Please make sure it is properly imported.') 43 } 44 } 45 46 updateFieldOrder(event) {
47 // Get all field IDs in their new order 48 const fieldIds = Array.from(this.fieldListTarget.children).map(el => el.dataset.fieldId) 49 50 // Send the new order to the server 51 fetch(`/forms/${this.formIdValue}/fields/reorder`, { 52 method: 'POST', 53 headers: { 54 'Content-Type': 'application/json', 55 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content 56 }, 57 body: JSON.stringify({ field_ids: fieldIds }) 58 }) 59 .then(response => response.json()) 60 .then(data => { 61 if (data.success) { 62 console.log('Field order updated successfully') 63 this.refreshPreview() 64 } else { 65 console.error('Failed to update field order:', data.errors || 'Unknown error') 66 } 67 }) 68 .catch(error => { 69 console.error('Error updating field order:', error) 70 }) 71 } 72 73 updateFormTitle(event) { 74 this.updateFormAttribute('title', this.formTitleTarget.value) 75 } 76 77 updateFormDescription(event) { 78 this.updateFormAttribute('formatted_description', this.formDescriptionTarget.value) 79 } 80 81 updateFormAttribute(attribute, value) { 82 const formData = new FormData() 83 formData.append(`form[${attribute}]`, value) 84 85 fetch(`/forms/${this.formIdValue}`, { 86 method: 'PATCH', 87 headers: { 88 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content, 89 'Accept': 'application/json' 90 }, 91 body: formData 92 }) 93 .then(response => response.json()) 94 .then(data => { 95 if (!data.success) { 96 console.error(`Failed to update form ${attribute}`) 97 } else { 98 this.refreshPreview() 99 } 100 }) 101 } 102 103 updateFormType(event) { 104 const formType = event.target.value 105 106 fetch(`/forms/${this.formIdValue}`, { 107 method: 'PATCH', 108 headers: { 109 'Content-Type': 'application/json', 110 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content, 111 'Accept': 'application/json' 112 }, 113 body: JSON.stringify({ 114 form: { form_type: formType } 115 }) 116 }) 117 .then(response => response.json()) 118 .then(data => { 119 if (data.success) { 120 // Reload the page to update the contact fields section 121 window.location.reload() 122 } else { 123 console.error('Failed to update form type:', data.errors) 124 } 125 }) 126 .catch(error => { 127 console.error('Error updating form type:', error) 128 }) 129 } 130 131 refreshPreview() { 132 const previewEl = document.getElementById('form_preview') 133 if (!previewEl) return 134 135 fetch(`/forms/${this.formIdValue}/preview_content`, { 136 headers: { 137 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content 138 } 139 }) 140 .then(response => response.text()) 141 .then(html => { previewEl.outerHTML = html }) 142 .catch(error => console.error('Error refreshing preview:', error)) 143 } 144};
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.