1class SubscribeForm { 2 form = null; 3 submitBtn = null; 4 successMsgDiv = null; 5 recaptchaInput = null; 6 recaptchaSitekey = ''; 7 emailInput = null; 8 isRecaptchaEnabled = false; 9 tokenValidityTime = 110 * 1000; 10 tokenRefreshTime = null; 11 12 constructor(id) { 13 this.form = $(`#${id}`); 14 this.submitBtn = this.form.find('[type="submit"]'); 15 this.emailInput = this.form.find('[type="email"]'); 16 this.successMsgDiv = this.form.find('.form-subscribe--success-msg'); 17 this.recaptchaInput = this.form.find('.field-blogsubscriber-recaptcha>input'); 18 this.isRecaptchaEnabled = this.form.data('recaptchaEnabled') ?? false; 19 this.recaptchaSitekey = this.form.data('recaptchaSitekey') ?? ''; 20 this.refreshToken.bind(this); 21 this.refreshToken(); 22 this.initEvents(); 23 } 24 25 initEvents() { 26 this.form.on('afterValidate', (e, data, errors) => { 27 if (errors.length === 0) { 28 this.form.yiiActiveForm('data').forceSubmit = true; 29 } 30 }).on('submit', () => { 31 if (!this.form.yiiActiveForm('data').forceSubmit) { 32 return false; 33 } 34 PrettyLoader.init(this.submitBtn.get(0)).show(); 35 this.submitWithRecaptcha(() => this.subscribe()); 36 return false; 37 }); 38 } 39 40 subscribe() { 41 $.post(this.form.attr('action'), this.form.serialize()).done((result) => { 42 if (result.status) { 43 this.form.get(0).reset(); 44 if (result.message) { 45 this.successMsgDiv.html(result.message); 46 } 47 } else if (result.error) { 48 for (const field in result.error) { 49 const error = result.error[field]; 50 let fieldId = `blogsubscriber-${field}`; 51 if (field === 'recaptcha') { 52 fieldId = `blogsubscriber-email`; 53 } 54 this.form.yiiActiveForm('updateAttribute', fieldId, [error]); 55 } 56 } 57 }).always(() => { 58 PrettyLoader.init(this.submitBtn.get(0)).hide(); 59 }); 60 } 61 62 submitWithRecaptcha(callback = () => {}) { 63 if (!this.isRecaptchaEnabled) { 64 callback(); 65 return; 66 } 67 if (new Date() - this.tokenRefreshTime <= this.tokenValidityTime) { 68 callback(); 69 return; 70 } 71 72 this.refreshToken().then(callback).then(() => this.refreshToken()); 73 } 74 75 refreshToken() { 76 if (!this.isRecaptchaEnabled) { 77 return Promise.resolve(); 78 } 79 return new Promise((resolve) => { 80 grecaptcha.ready(() => { 81 grecaptcha.execute(this.recaptchaSitekey, { 82 action: 'homepage', 83 }).then((token) => { 84 this.recaptchaInput.val(token); 85 this.tokenRefreshTime = new Date(); 86 resolve(); 87 }); 88 }); 89 }); 90 } 91}
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.