1;(function ($) { 2 3 var Form = function (element, options) { 4 this.$form = $(element); 5 this.options = options; 6 7 if (this.options.advanceNotice > 0) { 8 const now = new Date(); 9 const future = new Date(now.getTime() + this.options.advanceNotice * 1000); 10 this.options.advanceNotice = future; 11 } else { 12 this.options.advanceNotice = new Date(); 13 } 14 15 this.init(); 16 this.attachEvents(); 17 }; 18 19 Form.prototype.init = function () { 20 var self = this; 21 22 self.formOptions(); 23 }; 24 25 Form.prototype.attachEvents = function () { 26 var self = this; 27 28 self.$form.on( 29 'submit', function () { 30 self.requestLeadsApi(); 31 return false; 32 } 33 ); 34 35 self.$form.find('.fileField').each( 36 function () { 37 $(this).uploadField( 38 { 39 attributes: { 40 id: $(this).data('id'), 41 name: $(this).data('name'), 42 type:'file' 43 }, 44 fileTypes: self.$form.data('file-types'), 45 label: $(this).data('label'), 46 helpText : $(this).data('placeholder'), 47 required : $(this).data('required') 48 } 49 ); 50 } 51 ); 52 53 self.$form.find('input:checkbox').each( 54 function () { 55 var refName = $(this).data("refName"); 56 if (!$(this).attr("required") || refName.trim() == "") { return; } 57 58 this.checkValidity = function () { 59 return $('*[data-ref-name="' + refName + '"]:checkbox:checked').length > 0; 60 }; 61 } 62 ); 63 64 self.$form.find("input[data-form-datepicker='default']").each( 65 function () { 66 if ($(this).attr("name") == "preferred_date") { 67 $(this).datepicker( 68 { 69 minDate: self.options.advanceNotice, 70 onSelect: function () { 71 self.fillAvailableHours($(this).datepicker('getDate')); 72 } 73 } 74 ); 75 } else { 76 $(this).datepicker(); 77 } 78 } 79 ); 80 } 81 82 Form.prototype.requestLeadsApi = function () { 83 var self = this; 84 85 if(!this.checkFormValidity()) { 86 return false; 87 } 88 89 $(':submit', self.$form).prop('disabled', true); 90 91 var postData = self.buildPostData(); 92 93 const errorDialog = document.getElementById('error-form-dialog'); 94 const errorMessage = document.getElementById('p-error-message'); 95 const closeDialogButton = document.getElementById('close-dialog'); 96 97 function showErrorDialog(message) { 98 errorMessage.textContent = message; 99 errorDialog.showModal(); 100 document.body.style.overflow = 'hidden'; 101 errorDialog.style.display = 'block'; 102 } 103 104 closeDialogButton.addEventListener('click', () => { 105 errorDialog.close(); 106 errorDialog.style.display = 'none'; 107 document.body.style.overflow = 'auto'; 108 }); 109 110 if(this.checkUrlsInComments(postData)) { 111 showErrorDialog( 112 'Error: Your message could not be delivered because it contains a link to an external website. ' + 113 'Please review your message and try again.' 114 ); 115 $(':submit', self.$form).prop('disabled', false); 116 return false; 117 } 118 119 postData['source'] = window.location.hostname; 120 postData['__lf_ref_name'] = ''; 121 postData['__lf_title_name'] = ''; 122 postData['__lf__ref_contact_field'] = ''; 123 postData['mh_template_id'] = self.$form.data('template-id'); 124 postData['mh_orgId'] = self.$form.data('mhorgid'); 125 $.ajax( 126 { 127 url: self.$form.data('submit-url'), 128 type: "POST", 129 dataType: 'json', 130 data: postData, 131 success: function (result) { 132 self.submitSuccessMessage(); 133 }, 134 error: function (result, status, error) { 135 if (result.hasOwnProperty('responseText')) { 136 var errorObj = $.parseJSON(result.responseText); 137 if (!errorObj.error_message) { 138 showErrorDialog("Error: " + result.status + " " + result.statusText); 139 if (!$.support.placeholder) { 140 $("[placeholder]").each( 141 function () { 142 this.value = $(this).attr('placeholder'); 143 } 144 ); 145 } 146 } else { 147 if (typeof errorObj.error_message === 'object'){ 148 showErrorDialog("Error: " + errorObj.error_message); 149 } else if (typeof errorObj.error_message === 'string') { 150 try { 151 let error_message = JSON.parse(errorObj.error_message); 152 error_message = error_message[0].message; 153 showErrorDialog("Error: " + error_message); 154 } catch (e) { 155 showErrorDialog("Error: " + errorObj.error_message); 156 } 157 } 158 } 159 } else { 160 showErrorDialog("Oops! Something went wrong!"); 161 } 162 }, 163 complete: function () { 164 $(':submit', self.$form).prop('disabled', false); 165 } 166 } 167 ); 168 } 169 170 Form.prototype.checkFormValidity = function () { 171 var self = this, valid = true; 172 self.$form.find('input').each( 173 function () { 174 if (!$(this).attr('required')) { return; } 175 176 if (!this.checkValidity()) { 177 valid = false;
178 } 179 180 self.$form.addClass('was-validated'); 181 } 182 ); 183 return valid; 184 } 185 186 Form.prototype.submitSuccessMessage = function () { 187 var self = this; 188 189 if (self.options.submitType == 'message') { 190 self.$form.hide(); 191 self.$form.parent().find('.div-success-message.'+ self.$form.data('hash')).show(); 192 } else if (self.options.submitType == 'redirect') { 193 window.location.replace(self.options.submitValue); 194 } 195 } 196 197 Form.prototype.buildPostData = function () { 198 var self = this; 199 var postData = {}; 200 var postFields = {}; 201 var refFieldsMapping = {}; 202 203 postData['hash'] = self.options.hash; 204 205 $.each( 206 self.$form.find(':input').not(':submit'), function () { 207 postFields[this.name] = self.$form.find(":input[name='" + this.name + "']"); 208 refFieldsMapping[this.getAttribute("data-ref-name")] = this.name; 209 } 210 ); 211 212 if (window.CampaignTracker != undefined) { 213 var referredData = window.CampaignTracker.readCookie(); 214 } 215 216 if (referredData) { 217 postData['source'] = referredData['source']; 218 postData['medium'] = (referredData['medium'] != 'undefined') ? referredData['medium'] : ''; 219 postData['campaign'] = (referredData['campaign'] != 'undefined') ? referredData['campaign'] : ''; 220 postData['content'] = (referredData['content'] != 'undefined') ? referredData['content'] : ''; 221 postData['term'] = (referredData['term'] != 'undefined') ? referredData['term'] : ''; 222 } 223 224 self.$form.find(':input').each( 225 function () { 226 if (this.type == 'submit' || this.type == 'button') { 227 return; 228 } 229 230 if(this.getAttribute('type') == 'tel') { 231 postData[this.name] = this.value.replace(/[^0-9]/g, ''); 232 } 233 else if(this.getAttribute('type') == 'date' && $(this).prop('type') != 'date') { 234 postData[this.name] = self.convertDate(this.value); 235 } 236 else if (this.getAttribute('data-ref-name') == 'preferred_date' && !$(this).data('isCustom')) { 237 postData[refFieldsMapping['preferred_date']] = self.convertDate(this.value); 238 } 239 else if (this.type == "checkbox" || this.type == "radio") { 240 postData[this.name] = $('input[name=' + this.name + ']:checked').map( 241 function (_, el) { 242 return $(el).val(); 243 } 244 ).get(); 245 } 246 else if (this.type == "file") { 247 postData[this.name] = $(this).data('item'); 248 } 249 else { 250 postData[this.name] = this.value; 251 } 252 } 253 ); 254 255 return postData; 256 } 257 258 Form.prototype.convertDate = function (date) { 259 var dateArr = date.split("/"); 260 if (dateArr.length > 0 && dateArr[0]) { 261 return dateArr[2] + "-" + dateArr[0] + "-" + dateArr[1]; 262 } 263 264 return date; 265 }; 266 267 Form.prototype.formOptions = function (date) { 268 var $formLabel = $('.forms-option--b .form-a .form__group label'); 269 $formLabel.each( 270 function () { 271 if (!$(this).hasClass('hidden')) { 272 $(this).parent().find(".form__input:not([type='radio']):not([type='checkbox']):not(.form__input--file)>:first-child , .form__input--file").addClass('optionB-enabled'); 273 } 274 } 275 ); 276 }; 277 278 Form.prototype.fillAvailableHours = function (date) { 279 var self = this; 280 $(self.$form).find(':submit').attr('disabled', false); 281 282 //Grab the hours for the day selected 283 var dayName = $.datepicker.formatDate('D', date); 284 285 if (!Array.isArray(self.options.availableHours)) { 286 return; 287 } 288 289 //Clean up and populate hours array 290 var hours = []; 291 $.each( 292 self.options.availableHours, function () { 293 if (dayName === this.day_of_week) { 294 if (this.closed == 1) { 295 hours.push('Closed'); 296 } else { 297 $.each( 298 this.hours, function () { 299 var hr = self.populateHours(this.from, this.to, self.options.timeInterval, date); 300 hours = hours.concat(hr); 301 } 302 ); 303 } 304 return false;
305 } 306 } 307 ); 308 309 if ($(hours).length == 0) { 310 hours.push('Closed'); 311 } 312 313 //Populate hours dropdown 314 self.$form.find("[name='preferred_time']").empty(); 315 $.each( 316 hours, function (key, value) { 317 self.$form.find("[name='preferred_time']").append($('<option>', {value: value, text: value})); 318 319 //Disable submit button if selected date is closed 320 if (value == 'Closed') { 321 $(self.$form).find(':submit').attr('disabled', true); 322 } 323 } 324 ); 325 }; 326 327 Form.prototype.populateHours = function (from, to, interval, date) { 328 var hours = [], 329 date = (typeof date !== 'undefined') ? date : new Date(), 330 331 // Note: new Date().getMonth() returns current month in number starting from 0 332 // need to +1 to reflect actual month 333 first = Date.parse(date.getFullYear() + '/' + (date.getMonth()+1) + '/' + date.getDate() + " " + from), 334 last = Date.parse(date.getFullYear() + '/' + (date.getMonth()+1) + '/' + date.getDate() + " " + to); 335 336 while (first < last) { 337 var date = new Date(first); 338 var hr = date.getHours() > 12 ? date.getHours() - 12 : date.getHours(); 339 var am_pm = date.getHours() >= 12 ? "PM" : "AM"; 340 var min = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes(); 341 var time = hr + ":" + min + " " + am_pm; 342 hours.push(time); 343 344 first += interval * 1000; 345 } 346 347 return hours; 348 }; 349 350 Form.prototype.checkUrlsInComments = function (postData) { 351 if (!('comments' in postData)) { 352 return false; 353 } 354 function getUrlRegex() { 355 var regex = "((https?|ftp):\\/\\/)?"; 356 regex += "([a-z0-9+!*(),;?&=$_.-]+(:[a-z0-9+!*(),;?&=$_.-]+)?@)?"; 357 regex += "([a-z0-9-.]*)\\.([a-z]{2,3})"; 358 regex += "(:[0-9]{2,5})?"; 359 regex += "(\\/([a-z0-9+$_-]\\.?)+)*\\/?"; 360 regex += "(\\?[a-z+&$_.-][a-z0-9;:@&%=+\\/$_.-]*)?"; 361 regex += "(#[a-z_.-][a-z0-9+$_.-]*)?"; 362 return new RegExp(regex, 'i'); 363 } 364 365 var urlRegex = getUrlRegex(); 366 367 var comments = postData['comments']; 368 return !! comments.match(urlRegex); 369 }; 370 371 Form.DEFAULTS = {}; 372 373 var old = $.fn.Form; 374 375 $.fn.Form = function (option) { 376 var args = arguments, 377 result; 378 379 this.each( 380 function () { 381 var $this = $(this); 382 var options = $.extend({}, Form.DEFAULTS, $this.data(), typeof option == 'object' && option); 383 var data = ''; 384 385 $this.data('se.form', (data = new Form(this, options))); 386 387 if (typeof result != 'undefined') { return false; 388 } 389 } 390 ); 391 392 return result ? result : this; 393 }; 394 395 $.fn.Form.Constructor = Form; 396 397 $.fn.Form.noConflict = function () { 398 $.fn.Form = old; 399 return this 400 }; 401 402 $(window).load(function () { 403 var $formSection = $('[data-control="form"]'); 404 if ($formSection.length) { 405 $formSection.each(function () { 406 $(this).Form({}); 407 }); 408 } 409 }); 410 411})(jQuery);
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.