1var Formoid = (function () { 2 3 var API_URL = 'https://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 }; 43 44 Form.prototype.email = function (value) { 45 return prop.call(this, 'email', arguments); 46 }; 47 48 Form.prototype.title = function (value) { 49 return prop.call(this, 'title', arguments); 50 }; 51 52 Form.prototype.data = function (value) { 53 return prop.call(this, 'data', arguments); 54 }; 55 56 Form.prototype.send = function (data) { 57 return $ajax(API_URL, { 58 type: 'POST', 59 data: JSON.stringify({ 60 email: this.__email__, 61 form: { 62 title: this.__title__, 63 data: (arguments.length ? data : this.__data__) 64 } 65 }) 66 }) 67 .then(function(responseText) { 68 var data; 69 try { 70 data = JSON.parse(responseText); 71 } catch (e) { 72 throw new Error('Incorrect server response.'); 73 } 74 if (data.error) { 75 throw new Error(data.error); 76 } 77 return data.response; 78 }); 79 }; 80 81 return { 82 Form: function (settings) { 83 return new Form(settings); 84 } 85 } 86 87})(); 88 89var isValidEmail = function (input) { 90 return input.value ? /^([^@]+?)@(([a-z0-9]-*)*[a-z0-9]+\.)+([a-z0-9]+)$/i.test(input.value) : true; 91}; 92 93var formComponents = document.querySelectorAll('[data-form-type="formoid"]'); 94 95formComponents.forEach(function (component) { 96 var formData, 97 form = component.tagName === 'FORM' ? component : component.querySelector('form'), 98 alert = component.querySelector('[data-form-alert]'), 99 title = component.getAttribute('data-form-title') ? component : component.querySelector('[data-form-title]'), 100 submit = component.querySelector('[type="submit"]'), 101 inputArr = component.querySelectorAll('[data-form-field]'), 102 alertSuccess = alert.innerHTML; 103 104 form.addEventListener('change', function (event) { 105 if (event.target.type === 'file') { 106 if (event.target.files[0].size > 1000000) { 107 alert.removeAttribute('hidden'); 108 alert.classList.remove('alert-success'); 109 alert.classList.add('alert-danger'); 110 alert.innerHTML = 'File size must be less than 1mb'; 111 submit.classList.add('btn-loading'); 112 submit.setAttribute('disabled', true); 113 } 114 } 115 }); 116 117 form.addEventListener('submit', function (event) { 118 event.stopPropagation(); 119 event.preventDefault(); 120 121 if (submit.classList.contains('btn-loading')) return; 122 123 var inputs = inputArr; 124 125 form.classList.add('form-active'); 126 submit.classList.add('btn-loading'); 127 submit.setAttribute('disabled', true); 128 alert.innerHTML = ''; 129 130 formData = formData || Formoid.Form({ 131 email: component.querySelector('[data-form-email]').value, 132 title: title.getAttribute('data-form-title') || title.innerText 133 }); 134 135 function parseInput(input) { 136 return new Promise(function (resolve, reject) { 137 // valide email 138 if (input.getAttribute('name') === 'email' && !isValidEmail(input)) {
139 return reject(new Error('Form is not valid')); 140 } 141 var name = input.getAttribute('data-form-field') || input.getAttribute('name'); 142 switch (input.getAttribute('type')) { 143 case 'file': 144 var file = input.files[0]; 145 if (!file) return resolve(); 146 var reader = new FileReader() 147 reader.onloadend = function () { 148 resolve([name, reader.result]); 149 }; 150 reader.onerror = function () { 151 reject(reader.error); 152 }; 153 reader.readAsDataURL(file); 154 break; 155 case 'checkbox': 156 resolve([name, input.checked ? input.value : 'No']); 157 break; 158 case 'radio': 159 resolve(input.checked && [name, input.value]); 160 break; 161 default: 162 resolve([name, input.value]); 163 } 164 }); 165 } 166 167 Promise 168 .all(Array.prototype.map.call(inputs, function (input) { return parseInput(input); })) 169 .then(function (data) { return formData.send(data.filter(function (v) { return v; })); }) 170 .then(function (message) { 171 form.reset(); 172 form.classList.remove('form-active'); 173 alert.innerText = alertSuccess || message; 174 alert.classList.remove('alert-danger'); 175 alert.classList.add('alert-success'); 176 }, function (err) { 177 alert.innerText = err.message; 178 alert.classList.remove('alert-success') 179 alert.classList.add('alert-danger') 180 }) 181 .then(function () { 182 submit.classList.remove('btn-loading'); 183 submit.removeAttribute('disabled'); 184 alert.removeAttribute('hidden'); 185 }); 186 }); 187 188 inputArr.forEach(function (elem) { 189 elem.addEventListener('focus', function () { 190 alert.setAttribute('hidden', 'hidden'); 191 alert.classList.add('alert-success') 192 alert.classList.remove('alert-danger'); 193 alert.innerHTML = ''; 194 submit.classList.remove('btn-loading') 195 submit.removeAttribute('disabled'); 196 }); 197 }); 198})
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.