1export default class Form { 2 $form; 3 $loading; 4 $submitButton; 5 $requiredFields; 6 onSuccess; 7 constructor($form, $loading = null, onSuccess = null) { 8 if ($form.hasClass("initialized")) { 9 return; 10 } 11 this.$form = $form; 12 this.getOrCreateLoading($loading); 13 this.$submitButton = this.$form.find("button[type='submit']"); 14 this.$requiredFields = this.$form.find("input[required], select[required], textarea[required]"); 15 this.onSuccess = onSuccess; 16 this.initialize(); 17 this.$form.addClass("initialized"); 18 } 19 initialize() { 20 var context = this; 21 this.enableSubmit(); 22 if (this.$requiredFields.length > 0) { 23 setTimeout(() => { 24 // disable submit button when not all aria-required="true" fields are filled 25 this.onRequiredFieldChange(); 26 }, 400); 27 this.$form.find("input[required]").on("input", function () { 28 context.onRequiredFieldChange(); 29 }); 30 this.$form.find("textarea[required]").on("input", function () { 31 context.onRequiredFieldChange(); 32 }); 33 this.$form.find("select[required]").on("change", function () { 34 context.onRequiredFieldChange(); 35 }); 36 } 37 // handle form submit 38 this.$form.on('submit', function (e) { 39 context.$loading.show(); 40 if (context.onSuccess != null) { 41 e.preventDefault(); 42 const url = context.$form.attr('action'); 43 const data = new URLSearchParams(context.$form.serialize()); 44 fetch(url, { 45 method: 'POST', 46 body: data, 47 }) 48 .then(response => { 49 if (!response.ok) { 50 return response.text().then(text => { 51 const displayedError = text.length > 300 ? response.statusText : text; 52 toastr.error(displayedError); 53 throw new Error(displayedError); 54 }); 55 } 56 context.onSuccess(response); 57 }) 58 .catch(error => { 59 // console.error(error) 60 }).finally(() => { 61 context.$loading.hide(); 62 }); 63 } 64 }); 65 } 66 getOrCreateLoading($loading) { 67 this.$loading = $loading; 68 if (this.$loading == null) { 69 // try to find loading container 70 this.$loading = this.$form.find(".loading"); 71 if (this.$loading.length == 0) { 72 // build loading container 73 this.$loading = $(` 74 <div class="loading loading-with-backdrop" style="display: none;"> 75 <div class="absolute-center"> 76 <div class="spinner-border" role="status"> 77 <span class="visually-hidden">Loading...</span> 78 </div> 79 </div> 80 </div> 81 `); 82 this.$form.append(this.$loading); 83 } 84 } 85 } 86 onRequiredFieldChange() { 87 var context = this; 88 var allFilled = true; 89 this.$requiredFields.each(function () { 90 if (!context.hasValue(this)) { 91 allFilled = false; 92 return false; 93 } 94 }); 95 allFilled ? this.enableSubmit() : this.disableSubmit(); 96 } 97 hasValue(field) { 98 if ($(field).is(":checkbox")) { 99 var isChecked = $(field).is(":checked"); 100 return isChecked; 101 } 102 else if ($(field).is(":radio")) { 103 var name = $(field).attr("name"); 104 var $radioGroup = $(`input[name='${name}']`); 105 var isChecked = $radioGroup.is(":checked"); 106 return isChecked; 107 } 108 else { 109 var hasValue = $(field).val() != null && $(field).val() != ""; 110 if (CSS.supports('selector(:-internal-autofill-selected)')) { 111 var isAutofilled = field.matches(":-internal-autofill-selected"); 112 return hasValue || isAutofilled; 113 } 114 return hasValue; 115 } 116 } 117 enableSubmit() { 118 this.$submitButton.prop("disabled", false); 119 this.$submitButton.parent("[data-bs-toggle='tooltip']").tooltip("disable"); 120 } 121 disableSubmit() { 122 this.$submitButton.prop("disabled", true); 123 this.$submitButton.parent("[data-bs-toggle='tooltip']").tooltip("enable"); 124 } 125} 126//# sourceMappingURL=form.js.map
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.