1/*jshint esversion: 11 */ 2 3function timeSince(timeStamp) { 4 if (typeof timeStamp === "string") { 5 timeStamp = new Date(timeStamp.replace(/-/g, "/")); 6 } 7 8 let now = new Date(); 9 let secondsPast = parseInt((now.getTime() - timeStamp.getTime()) / 1000); 10 11 if (secondsPast <= 86400) { 12 let hour = timeStamp.getHours(); 13 hour = ("0" + hour).slice(-2); 14 let min = timeStamp.getMinutes(); 15 min = ("0" + min).slice(-2); 16 return hour + ':' + min; 17 } 18 if (secondsPast > 86400) { 19 day = timeStamp.getDate(); 20 month = timeStamp.toDateString().match(/ [a-zA-Z]*/)[0].replace(" ", ""); 21 year = timeStamp.getFullYear() == now.getFullYear() ? "": " "+timeStamp.getFullYear(); 22 return day + " " + month + year; 23 } 24} 25 26function initForms() { 27 // validation 28 document.querySelectorAll('form.validate').forEach(function(form) { 29 const fileInputs = form.querySelectorAll('*[type="file"], *[type="files"]'); 30 if (fileInputs.length) { 31 form.setAttribute('enctype', 'multipart/form-data'); 32 } 33 }); 34 35 const validateForms = document.querySelectorAll('form.validate'); 36 37 validateForms.forEach(form => { 38 form.addEventListener('submit', function(event) { 39 // Your form validation logic goes here 40 event.preventDefault(); // Prevent default form submission 41 42 let form = this; 43 44 // Disable the buttons 45 const submitButtons = form.querySelectorAll('*[type="submit"], *[type="image"]'); 46 submitButtons.forEach(button => button.disabled = true); 47 48 // Remove error messages 49 const errorDivs = form.querySelectorAll('div.error'); 50 errorDivs.forEach(div => div.remove()); 51 52 let url = form.action ? form.action : location.href; 53 54 let data = new URLSearchParams(); 55 for (const pair of new FormData(form)) { 56 let value = pair[1] instanceof File ? pair[1].name : pair[1]; 57 data.append(pair[0], value); 58 } 59 60 data.append('validate', 1); 61 data.append('nospam', 1); 62 63 //validate 64 if (form.method.toUpperCase() === 'GET') { 65 url += '?' + data; 66 data = null; 67 } 68 69 //validate 70 fetch(url, { 71 method: form.method, 72 body: data, 73 headers: { 74 'Content-Type': 'application/x-www-form-urlencoded' // For POST requests 75 } 76 }) 77 .then(response => response.json()) // Parse JSON response 78 .then(data => { 79 // Handle successful response (replace with your logic) 80 console.log('Success:', data); 81 82 if (!data.success && data != 1) { 83 // display errors 84 let errors = data.errors ? data.errors: data; 85 86 errors.forEach(function(item) { 87 let pos = item.indexOf(' '); 88 let fieldName; 89 90 if (pos === -1) { 91 fieldName = item; 92 error = 'required'; 93 } else { 94 fieldName = item.substring(0, pos); 95 error = item.substring(pos + 1); 96 } 97 98 let parent = ''; 99 let fieldInput = form[fieldName + '[]'] ? form[fieldName + '[]'] : form[fieldName]; 100 101 if (fieldInput) { 102 if (fieldInput.style) { 103 parent = fieldInput.parentNode; 104 } else if (fieldInput[0]) { 105 parent = fieldInput[0].parentNode.parentNode; 106 } 107 } else { 108 console.log('field not found: ' + fieldName); 109 } 110 111 if (parent) { 112 div = document.createElement("div"); 113 div.innerHTML = error; 114 div.style.color = 'red'; 115 div.className = 'error'; 116 parent.appendChild(div); 117 } 118 }) 119 120 // scroll to first error 121 const elements = document.getElementsByClassName('error'); 122 if (elements && elements.length > 0) { 123 elements[0].scrollIntoView({ behavior: 'smooth', block: 'center' }); 124 } 125 126 } else { 127 // Create the hidden input element 128 const hiddenInput = document.createElement('input'); 129 hiddenInput.type = 'hidden'; 130 hiddenInput.name = 'nospam'; 131 hiddenInput.value = '1'; 132 133 // Append the hidden input to the form 134 form.appendChild(hiddenInput); 135 136 const recaptchaSiteKey = document.querySelector('#recaptcha')?.dataset?.key; 137 138 if (recaptchaSiteKey) { 139 grecaptcha.ready(() => { 140 grecaptcha.execute(recaptchaSiteKey, { 141 action: 'submit' 142 }).then(token => { 143 const recaptchaTextarea = form.querySelector('.recaptcha') || document.createElement('textarea'); 144 145 if (!recaptchaTextarea.classList.contains('recaptcha')) { 146 recaptchaTextarea.style.display = 'none'; 147 recaptchaTextarea.classList.add('recaptcha'); 148 recaptchaTextarea.name = 'g-recaptcha-response'; 149 form.appendChild(recaptchaTextarea); 150 } 151 152 recaptchaTextarea.value = token; 153 form.submit(); 154 }); 155 }); 156 } else { 157 form.submit(); 158 } 159 } 160 161 // re-enable submit 162 const submitButtons = form.querySelectorAll('*[type="submit"], *[type="image"]'); 163 submitButtons.forEach(button => button.disabled = false); 164 }) 165 .catch(error => { 166 // Handle errors 167 console.error('Error:', error); 168 alert(error.message); // Example error message display 169 }); 170 171 }); 172 }); 173} 174 175function clearFile(field) 176{ 177 inputFile = document.createElement("input"); 178 inputFile.setAttribute('name', field.getAttribute('name'));
179 inputFile.setAttribute('type', 'file'); 180 181 var cell = field.parentNode; 182 183 while ( cell.childNodes.length >= 1 ) 184 { 185 cell.removeChild( cell.firstChild ); 186 } 187 188 cell.appendChild(inputFile); 189} 190 191function initSortables() { 192 // sortable 193 document.querySelectorAll('ul.files').forEach(list => { 194 let draggedItem = null; 195 196 list.addEventListener('dragstart', e => { 197 const li = e.target.closest('li'); 198 if (li && list.contains(li)) { 199 draggedItem = li; 200 e.dataTransfer.effectAllowed = "move"; 201 e.dataTransfer.setData("text/plain", ""); // required in some browsers 202 li.style.opacity = '0.5'; 203 } 204 }); 205 206 list.addEventListener('dragend', e => { 207 if (draggedItem) { 208 draggedItem.style.opacity = ''; 209 draggedItem = null; 210 } 211 }); 212 213 list.addEventListener('dragover', e => { 214 e.preventDefault(); // allow drop 215 const li = e.target.closest('li'); 216 if (li && draggedItem && li.parentNode === list && li !== draggedItem) { 217 const rect = li.getBoundingClientRect(); 218 const next = (e.clientY - rect.top) > rect.height / 2; 219 list.insertBefore(draggedItem, next ? li.nextSibling : li); 220 } 221 }); 222 }); 223} 224 225window.addEventListener('DOMContentLoaded', function() { 226 initForms(); 227 initSortables(); 228});
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.