1var Formoid = (function () { 2 3 var API_URL = ('https:' == location.protocol ? 'https:' : 'http:') + '//formoid.net/api/push'; 4 5 function $ajax(url, settings) { 6 return new Promise(function (resolve, reject) { 7 var xhr = new XMLHttpRequest(); 8 xhr.open(settings.type, url); 9 xhr.onload = function () { 10 if (xhr.status !== 200) { 11 return reject(new Error('Incorrect server response.')); 12 } 13 resolve(xhr.responseText); 14 }; 15 xhr.onerror = function () { 16 var message = 'Failed to query the server. '; 17 if ('onLine' in navigator && !navigator.onLine) { 18 message += 'No connection to the Internet.'; 19 } else { 20 message += 'Check the connection and try again.'; 21 } 22 reject(new Error(message)); 23 }; 24 xhr.send(settings.data); 25 }) 26 }; 27 28 var prop = function (name, args) { 29 name = '__' + name + '__'; 30 if (args.length) { 31 this[name] = args[0]; 32 return this; 33 } 34 return this[name]; 35 }; 36 37 var Form = function (settings) { 38 settings = settings || {}; 39 this.__email__ = settings.email || ''; 40 this.__title__ = settings.title || ''; 41 this.__data__ = settings.data || []; 42 this.__recaptcha__ = settings.recaptcha || ''; 43 }; 44 45 Form.prototype.email = function (value) { 46 return prop.call(this, 'email', arguments); 47 }; 48 49 Form.prototype.title = function (value) { 50 return prop.call(this, 'title', arguments); 51 }; 52 53 Form.prototype.recaptcha_token = function (value) { 54 return prop.call(this, 'recaptcha_token', arguments); 55 }; 56 57 Form.prototype.data = function (value) { 58 return prop.call(this, 'data', arguments); 59 }; 60 61 Form.prototype.getCaptchaToken = function () { 62 var recaptcha = this.__recaptcha__; 63 return new Promise(function (resolve, reject) { 64 if (!recaptcha) return resolve(); 65 if (!grecaptcha) return reject(new Error('"grecaptcha" is not found')); 66 grecaptcha.ready(function () { 67 try { 68 grecaptcha 69 .execute(recaptcha, { action: 'homepage' }) 70 .then(resolve, reject); 71 } catch (err) { 72 reject(err); 73 } 74 }); 75 }); 76 }; 77 78 Form.prototype.send = function (data) { 79 data = { 80 email: this.__email__, 81 form: { 82 title: this.__title__, 83 data: arguments.length ? data : this.__data__ 84 } 85 }; 86 return this.getCaptchaToken() 87 .then(function (token) { 88 if (token) data.recaptcha_token = token; 89 return $ajax(API_URL, { 90 type: 'POST', 91 data: JSON.stringify(data) 92 }); 93 }) 94 .then(function(responseText) { 95 var data; 96 try { 97 data = JSON.parse(responseText); 98 } catch (e) { 99 throw new Error('Incorrect server response.'); 100 } 101 if (data.error) { 102 throw new Error(data.error); 103 } 104 return data.response; 105 }); 106 }; 107 108 return { 109 Form: function (settings) { 110 return new Form(settings); 111 } 112 } 113 114})(); 115 116const formModalDOM = document.createElement('div'); 117let formModal; 118 119formModalDOM.classList.add('modal'); 120formModalDOM.setAttribute('tabindex', -1); 121formModalDOM.style.overflow = 'hidden'; 122 123if (typeof bootstrap !== 'undefined') { 124 if (bootstrap.Tooltip.VERSION.startsWith(5)) { 125 //bs5 126 formModalDOM.innerHTML = ` 127 <div class="modal-dialog d-flex align-items-center" style=""> 128 <div class="modal-content" style="height:auto;border-radius:0;border:none;box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.25);"> 129 <div class="modal-body d-flex justify-content-end flex-column align-items-end"> 130 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 131 <p class="display-7" style="text-align:center;width:100%;">Modal body text goes here.</p> 132 </div> 133 </div> 134 </div>`; 135 formModal = new bootstrap.Modal(formModalDOM); 136 } else { 137 // bs4 138 formModalDOM.innerHTML = ` 139 <div class="modal-dialog d-flex align-items-center" style=""> 140 <div class="modal-content" style="height:auto;border-radius:0;border:none;box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.25);"> 141 <div class="modal-body d-flex justify-content-end flex-column align-items-end"> 142 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> 143 <p class="display-7" style="text-align:center;width:100%;">Modal body text goes here.</p> 144 </div> 145 </div> 146 </div>`; 147 formModal = new bootstrap.Modal(formModalDOM); 148 } 149} else if ($.fn.tooltip) { 150 // bs3 151 formModalDOM.innerHTML = ` 152 <div class="modal-dialog d-flex align-items-center" style="display:flex; align-items:center; margin:auto; height:100%"> 153 <div class="modal-content" style="height:auto;border-radius:0;border:none;box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.25); width:100%"> 154 <div class="modal-body d-flex justify-content-end flex-column align-items-end" style="display:flex; justify-content:end; flex-direction:column; align-items:end"> 155 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> 156 <p class="display-7" style="text-align:center;width:100%;">Modal body text goes here.</p> 157 </div> 158 </div> 159 </div>`; 160 formModal = $(formModalDOM); 161} 162 163var isValidEmail = function (input) { 164 return input.value ? /^([^@]+?)@(([a-z0-9]-*)*[a-z0-9]+\.)+([a-z0-9]+)$/i.test(input.value) : true; 165}; 166 167var formComponents = document.querySelectorAll('[data-form-type="formoid"]'); 168
169formComponents.forEach(function (component) { 170 var formData, 171 form = component.tagName === 'FORM' ? component : component.querySelector('form'), 172 alert = component.querySelector('[data-form-alert]'), 173 title = component.getAttribute('data-form-title') ? component : component.querySelector('[data-form-title]'), 174 submit = component.querySelector('[type="submit"]'), 175 inputArr = component.querySelectorAll('[data-form-field]'), 176 alertSuccess = alert.innerHTML; 177 178 form.addEventListener('change', function (event) { 179 if (event.target.type === 'file') { 180 if (event.target.files[0].size > 1000000) { 181 if (typeof bootstrap !== 'undefined') { 182 formModal._element.querySelector('.modal-body p').innerText = 'File size must be less than 1mb'; 183 formModal._element.querySelector('.modal-content').classList.add('alert-danger'); 184 formModal._element.querySelector('.modal-content').style.backgroundColor = '#ff9966'; 185 formModal.show(); 186 } else { 187 formModal[0].querySelector('.modal-body p').innerText = 'File size must be less than 1mb'; 188 formModal[0].querySelector('.modal-content').classList.add('alert-danger'); 189 formModal[0].querySelector('.modal-content').style.backgroundColor = '#ff9966'; 190 formModal.modal(); 191 } 192 submit.classList.add('btn-loading'); 193 submit.setAttribute('disabled', true); 194 } 195 } 196 }); 197 198 form.addEventListener('submit', function (event) { 199 event.stopPropagation(); 200 event.preventDefault(); 201 202 if (submit.classList.contains('btn-loading')) return; 203 204 var inputs = inputArr; 205 206 form.classList.add('form-active'); 207 submit.classList.add('btn-loading'); 208 submit.setAttribute('disabled', true); 209 210 formData = formData || Formoid.Form({ 211 email: component.querySelector('[data-form-email]').value, 212 title: title.getAttribute('data-form-title') || title.innerText, 213 recaptcha: form.querySelector('[data-form-captcha]') ? form.querySelector('[data-form-captcha]').value : false 214 }); 215 216 function parseInput(input) { 217 return new Promise(function (resolve, reject) { 218 // valide email 219 if (input.getAttribute('name') === 'email' && !isValidEmail(input)) { 220 return reject(new Error('Form is not valid')); 221 } 222 var name = input.getAttribute('data-form-field') || input.getAttribute('name'); 223 switch (input.getAttribute('type')) { 224 case 'file': 225 var file = input.files[0]; 226 if (!file) return resolve(); 227 var reader = new FileReader() 228 reader.onloadend = function () { 229 resolve([name, reader.result]); 230 }; 231 reader.onerror = function () { 232 reject(reader.error); 233 }; 234 reader.readAsDataURL(file); 235 break; 236 case 'checkbox': 237 resolve([name, input.checked ? input.value : 'No']); 238 break; 239 case 'radio': 240 resolve(input.checked && [name, input.value]); 241 break; 242 default: 243 resolve([name, input.value]); 244 } 245 }); 246 } 247 248 Promise 249 .all(Array.prototype.map.call(inputs, function (input) { return parseInput(input); })) 250 .then(function (data) { return formData.send(data.filter(function (v) { return v; })); }) 251 .then(function (message) { 252 form.reset(); 253 form.classList.remove('form-active'); 254 if (typeof bootstrap !== 'undefined') { 255 formModal._element.querySelector('.modal-body p').innerText = alertSuccess || message; 256 formModal._element.querySelector('.modal-content').classList.add('alert-success'); 257 formModal._element.querySelector('.modal-content').style.backgroundColor = '#70c770' 258 formModal.show(); 259 } else { 260 formModal[0].querySelector('.modal-body p').innerText = message || alertSuccess; 261 formModal[0].querySelector('.modal-content').classList.add('alert-success'); 262 formModal[0].querySelector('.modal-content').style.backgroundColor = '#70c770'; 263 formModal.modal(); 264 } 265 }, function (err) { 266 if (typeof bootstrap !== 'undefined') { 267 formModal._element.querySelector('.modal-body p').innerText = err.message; 268 formModal._element.querySelector('.modal-content').classList.add('alert-danger'); 269 formModal._element.querySelector('.modal-content').style.backgroundColor = '#ff9966' 270 } else { 271 formModal[0].querySelector('.modal-body p').innerText = err.message; 272 formModal[0].querySelector('.modal-content').classList.add('alert-danger'); 273 formModal[0].querySelector('.modal-content').style.backgroundColor = '#ff9966' 274 } 275 }) 276 .then(function () { 277 submit.classList.remove('btn-loading'); 278 submit.removeAttribute('disabled'); 279 }); 280 }); 281 282 inputArr.forEach(function (elem) { 283 elem.addEventListener('focus', function () { 284 submit.classList.remove('btn-loading') 285 submit.removeAttribute('disabled'); 286 }); 287 }); 288})
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.