1/** 2 * CodeDropz Uploader v1.3.7.2 3 * Copyright 2018 Glen Mongaya 4 * CodeDrop Drag&Drop Uploader 5 * @version 1.3.7.2 6 * @author CodeDropz, Glen Don L. Mongaya 7 * @license The MIT License (MIT) 8 */ 9 10// CodeDropz Drag and Drop Plugin 11(function() { 12 13 const CodeDropz_Uploader = function( settings ){ 14 15 // Generate & check nonce 16 const form = document.querySelector('form.wpcf7-form'); 17 if( form ) { 18 const data = new FormData(); 19 data.append('action', '_wpcf7_check_nonce'); 20 data.append('_ajax_nonce', dnd_cf7_uploader.ajax_nonce ); 21 fetch(dnd_cf7_uploader.ajax_url, { method: 'POST', body: data }) 22 .then(res => res.json()) 23 .then(({ data, success }) => success && (dnd_cf7_uploader.ajax_nonce = data)) 24 .catch(console.error) 25 } 26 27 // Parent input file type 28 var input = this; 29 30 // Define default options 31 const defaultOptions = { 32 handler: input, 33 color: '#000', 34 background: '', 35 server_max_error: 'Uploaded file exceeds the maximum upload size of your server.', 36 max_file: input.dataset.max ? input.dataset.max : 10, // default 10 37 max_upload_size: input.dataset.limit ? input.dataset.limit : '10485760', // should be a bytes it's (5MB) 38 supported_type: input.dataset.type ? input.dataset.type : 'jpg|jpeg|JPG|png|gif|pdf|doc|docx|ppt|pptx|odt|avi|ogg|m4a|mov|mp3|mp4|mpg|wav|wmv|xls', 39 text: 'Drag & Drop Files Here', 40 separator: 'or', 41 button_text: 'Browse Files', 42 on_success: '', 43 }; 44 45 // Merge options with default options 46 const options = Object.assign({}, defaultOptions, settings); 47 48 // Get storage name 49 var dataStorageName = input.dataset.name + '_count_files'; 50 51 // File Counter 52 localStorage.setItem( dataStorageName, 1); 53 54 // Template Container 55 const cdropz_template = ` 56 <div class="codedropz-upload-handler"> 57 <div class="codedropz-upload-container"> 58 <div class="codedropz-upload-inner"> 59 <${dnd_cf7_uploader.drag_n_drop_upload.tag}>${options.text}</${dnd_cf7_uploader.drag_n_drop_upload.tag}> 60 <span>${options.separator}</span> 61 <div class="codedropz-btn-wrap"><a class="cd-upload-btn" href="javascript:void(0)">${options.button_text}</a></div> 62 </div> 63 </div> 64 <span class="dnd-upload-counter"><span>0</span> ${dnd_cf7_uploader.dnd_text_counter} ${parseInt(options.max_file)}</span> 65 </div> 66 `; 67 68 // Wrap input fields 69 const wrapper = document.createElement('div'); 70 71 // Begin to wrap upload fields 72 wrapper.classList.add('codedropz-upload-wrapper'); 73 options.handler.parentNode.insertBefore(wrapper, options.handler); 74 wrapper.appendChild(options.handler); 75 76 // Remove special character 77 options.supported_type = options.supported_type.replace(/[^a-zA-Z0-9| ]/g, ""); 78 79 // Element Handler 80 const form_handler = options.handler.closest('form'); 81 const options_handler = options.handler.closest('.codedropz-upload-wrapper'); 82 const btnOBJ = form_handler.querySelector('input[type="submit"]'); 83 84 // Append Format 85 options.handler.insertAdjacentHTML('afterend', cdropz_template); 86 87 // preventing the unwanted behaviours 88 ['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'].forEach(function(eventName) { 89 options_handler.querySelector('.codedropz-upload-handler').addEventListener(eventName, function(e) { 90 e.preventDefault(); 91 e.stopPropagation(); 92 }); 93 }); 94 95 // dragover and dragenter - add class 96 ['dragover', 'dragenter'].forEach(function(eventName) { 97 options_handler.querySelector('.codedropz-upload-handler').addEventListener(eventName, function(e) { 98 options_handler.querySelector('.codedropz-upload-handler').classList.add('codedropz-dragover'); 99 }); 100 }); 101 102 // dragleave dragend drop - remove class 103 ['dragleave', 'dragend', 'drop'].forEach(function(eventName){ 104 options_handler.querySelector('.codedropz-upload-handler').addEventListener(eventName, function(e) { 105 options_handler.querySelector('.codedropz-upload-handler').classList.remove('codedropz-dragover'); 106 }); 107 }); 108 109 // Browse button clicked 110 options_handler.querySelector('.cd-upload-btn').addEventListener('click', function(e){ 111 // stops the default action of an element from happening 112 e.preventDefault(); 113 114 // Reset value 115 options.handler.value = null; 116 117 // Click input type[file] element 118 options.handler.click(); 119 }); 120 121 // when dropping files 122 options_handler.querySelector('.codedropz-upload-handler').addEventListener('drop', function(event) { 123 // Run the uploader 124 DND_Setup_Uploader(event.dataTransfer.files, 'drop'); 125 }); 126 127 // Trigger when input type[file] is click/changed 128 options.handler.addEventListener('change', function(e) { 129 // Run the uploader 130 DND_Setup_Uploader(this.files, 'click'); 131 }); 132 133 // Remove accept attribute on mobile devices 134 if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) { 135 input.removeAttribute('accept'); 136 } 137 138 // Setup Uploader 139 var DND_Setup_Uploader = function( files, action ) { 140 141 // make sure we have files 142 if (files.length == 0 ) return; 143 144 // gathering the form data 145 var formData = new FormData(); 146 147 // Append file 148 //formData.append('supported_type', options.supported_type ); @note : removed due Vulnerability 149 //formData.append('size_limit', options.max_upload_size ); 150 formData.append('action', 'dnd_codedropz_upload' ); 151 formData.append('type', action ); 152 formData.append('security', dnd_cf7_uploader.ajax_nonce ); 153 154 // CF7 - upload field name & cf7 id 155 formData.append('form_id', input.dataset.id); 156 formData.append('upload_name', input.dataset.name); 157 158 // black list file types 159 /*if( input.hasAttribute('data-black-list') ){ 160 formData.append('blacklist-types', input.dataset.blackList); 161 }*/ 162 163 // remove has error 164 const errorHandler = options.handler.querySelector('.has-error'); 165 if (errorHandler) { 166 errorHandler.remove(); 167 } 168
169 // Loop files 170 for (const file of files) { 171 172 // Reset upload file type 173 if( typeof formData.delete !== 'undefined' ) { 174 formData.delete('upload-file'); 175 } 176 177 // Limit file upload 178 if( Number( localStorage.getItem(dataStorageName) ) > options.max_file ) { 179 var hasErrorMsg = options_handler.querySelector('span.has-error-msg'); 180 if (!hasErrorMsg) { 181 var err_msg = dnd_cf7_uploader.drag_n_drop_upload.max_file_limit; 182 var errorMsgEl = document.createElement('span'); 183 errorMsgEl.className = 'has-error-msg'; 184 errorMsgEl.textContent = err_msg.replace('%count%', options.max_file); 185 options_handler.appendChild(errorMsgEl); 186 } 187 return false; 188 } 189 190 191 // Create progress bar 192 const progressBarID = CodeDropz_Object.createProgressBar( file ); 193 var has_error = false; 194 195 // File size limit - validation 196 if (file.size > options.max_upload_size) { 197 const parentProgressBar = document.getElementById(progressBarID); 198 const errorSpan = document.createElement('span'); 199 errorSpan.classList.add('has-error'); 200 errorSpan.textContent = dnd_cf7_uploader.drag_n_drop_upload.large_file; 201 parentProgressBar.querySelector('.dnd-upload-details').appendChild(errorSpan); 202 has_error = true; 203 } 204 205 // Validate file type 206 regex_type = new RegExp("(.*?)\.("+ options.supported_type +")$"); 207 if ( has_error === false && !( regex_type.test( file.name.toLowerCase() ) ) ) { 208 document.querySelector('#' + progressBarID + ' .dnd-upload-details').insertAdjacentHTML('beforeend', '<span class="has-error">' + dnd_cf7_uploader.drag_n_drop_upload.inavalid_type + '</span>'); 209 has_error = true; 210 } 211 212 // Increment count 213 localStorage.setItem( dataStorageName, ( Number( localStorage.getItem( dataStorageName ) ) + 1 ) ); 214 215 // Make sure there's no error 216 if( has_error === false ) { 217 218 // Append file 219 formData.append('upload-file', file ); 220 221 // Process ajax upload 222 var xhr = new XMLHttpRequest(); 223 224 // Get progress bar element 225 var progressBar = document.getElementById( progressBarID ); 226 var progressElement = progressBar.querySelector('.dnd-progress-bar'); 227 var detailsElement = progressBar.querySelector('.dnd-upload-details'); 228 var submitButton = form_handler.querySelector('input[type="submit"]'); 229 230 xhr.open(form_handler.getAttribute('method'), options.ajax_url); 231 xhr.onreadystatechange = function() { 232 if (this.readyState === 4) { 233 if (this.status === 200) { 234 var response = JSON.parse(this.responseText); 235 if (response.success) { 236 237 // Complete the progress bar 238 CodeDropz_Object.setProgressBar(progressBarID, 100); 239 240 // Callback on success 241 if (typeof options.on_success === "function") { 242 options.on_success.call(this, input, progressBarID, response); 243 } 244 245 } else { 246 progressElement.remove(); 247 detailsElement.insertAdjacentHTML('beforeend', '<span class="has-error">'+ response.data +'</span>'); 248 submitButton.classList.remove('disabled'); 249 submitButton.removeAttribute('disabled'); 250 progressBar.classList.remove('in-progress'); 251 } 252 } else { 253 progressElement.remove(); 254 detailsElement.insertAdjacentHTML('beforeend', '<span class="has-error">'+ options.server_max_error +'</span>'); 255 submitButton.classList.remove('disabled'); 256 submitButton.removeAttribute('disabled'); 257 progressBar.classList.remove('in-progress'); 258 } 259 } 260 }; 261 xhr.upload.addEventListener("progress", function(event){ 262 if ( event.lengthComputable ) { 263 264 var percentComplete = ( event.loaded / event.total ); 265 var percentage = parseInt( percentComplete * 100 ); 266 267 // Make progress on the loading 268 CodeDropz_Object.setProgressBar( progressBarID, percentage - 1 ); 269 } 270 }, false); 271 272 xhr.send(formData); 273 274 } 275 } 276 277 } 278 // End of Uploader function 279 280 // CodeDropz object and functions 281 var CodeDropz_Object = { 282 283 // Create progress bar 284 createProgressBar : function( file ) { 285 286 // Setup progress bar variable 287 var upload_handler = options_handler.querySelector('.codedropz-upload-handler'); 288 var generated_ID = 'dnd-file-' + Math.random().toString(36).substr(2, 9); 289 290 // Setup progressbar elements 291 var fileDetails = ` 292 <div class="dnd-upload-image">
293 <span class="file"></span> 294 </div> 295 <div class="dnd-upload-details"> 296 <span class="name"><span>${file.name}</span><em>(${CodeDropz_Object.bytesToSize(file.size)})</em></span> 297 <a href="javascript:void(0)" title="${dnd_cf7_uploader.drag_n_drop_upload.delete.title}" class="remove-file" data-storage="${dataStorageName}"> 298 <span class="dnd-icon-remove"></span> 299 </a> 300 <span class="dnd-progress-bar"><span></span></span> 301 </div> 302 `; 303 304 // Create new element and insert after upload_handler 305 var statusElement = document.createElement('div'); 306 statusElement.id = generated_ID; 307 statusElement.className = 'dnd-upload-status'; 308 statusElement.innerHTML = fileDetails; 309 upload_handler.parentNode.insertBefore(statusElement, upload_handler.nextSibling); 310 311 return generated_ID; 312 313 }, 314 315 // Process progressbar ( Animate progress ) 316 setProgressBar : function( progressBarID, percent ) { 317 318 const progressBar = document.getElementById( progressBarID ); 319 const statusBar = progressBar.querySelector('.dnd-progress-bar'); 320 321 //console.log(statusbar); 322 if (statusBar) { 323 324 // Disable submit button 325 CodeDropz_Object.disableBtn(btnOBJ); 326 327 // Compute Progress bar 328 let progress_width = percent * statusBar.offsetWidth / 100; 329 330 // Set status bar in-progress 331 progressBar.classList.add('in-progress'); 332 333 if (percent == 100) { 334 statusBar.querySelector('span').style.width = '100%'; 335 statusBar.querySelector('span').textContent = `${percent}% `; 336 } else { 337 statusBar.querySelector('span').style.width = progress_width + 'px'; 338 statusBar.querySelector('span').textContent = `${percent}% `; 339 } 340 341 if (percent == 100) { 342 progressBar.classList.add('complete'); 343 progressBar.classList.remove('in-progress'); 344 } 345 } 346 return false; 347 348 }, 349 350 // Size Conversion 351 bytesToSize : function( bytes ) { 352 353 if( bytes === 0 ) 354 return '0'; 355 356 kBytes = (bytes / 1024); 357 fileSize = ( kBytes >= 1024 ? ( kBytes / 1024 ).toFixed(2) + 'MB' : kBytes.toFixed(2) + 'KB' ); 358 359 return fileSize; 360 }, 361 362 // Disable button 363 disableBtn : function( BtnOJB ) { 364 if( BtnOJB ) { 365 BtnOJB.classList.add('disable'); 366 BtnOJB.disabled = true; 367 } 368 } 369 }; 370 371 } // end fn.function 372 373 // Remove File 374 document.addEventListener("click", function(e) { 375 if( !e.target.classList.contains("dnd-icon-remove") ) return; 376 377 var _self = e.target, 378 _dnd_status = _self.closest(".dnd-upload-status"), 379 _parent_wrap = _self.closest(".codedropz-upload-wrapper"), 380 removeStorageData = _self.parentElement.getAttribute("data-storage"), 381 storageCount = Number(localStorage.getItem(removeStorageData)); 382 383 // Direct remove the file if there's any error. 384 if (_dnd_status.classList.contains("in-progress") || _dnd_status.querySelector(".has-error")) { 385 _dnd_status.remove(); 386 localStorage.setItem(removeStorageData, storageCount - 1); 387 return false; 388 } 389 390 // Change text Status 391 _self.classList.add("deleting"); 392 _self.textContent = dnd_cf7_uploader.drag_n_drop_upload.delete.text + "..."; 393 394 // Request ajax image delete 395 var xhr = new XMLHttpRequest(); 396 xhr.open("POST", dnd_cf7_uploader.ajax_url); 397 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 398 xhr.onload = function() { 399 if (this.status === 200) { 400 var response = JSON.parse(this.responseText); 401 if (response.success) { 402 403 // Reduce file count and status bar element. 404 _dnd_status.remove(); 405 localStorage.setItem(removeStorageData, storageCount - 1); 406 407 // Remove error msg 408 if ( _parent_wrap.querySelectorAll(".dnd-upload-status").length <= 1 ){ 409 if( _parent_wrap.querySelector(".has-error-msg") ){ 410 _parent_wrap.querySelector(".has-error-msg").remove(); 411 } 412 } 413 414 // Update Counter 415 _parent_wrap.querySelector(".dnd-upload-counter span").textContent = Number(localStorage.getItem(removeStorageData)) - 1; 416 } 417 } 418 }; 419 420 xhr.send(
421 "path=" + _dnd_status.querySelector('input[type="hidden"]').value + 422 "&action=dnd_codedropz_upload_delete" + 423 "&security=" + dnd_cf7_uploader.ajax_nonce 424 ); 425 426 document.querySelectorAll(".has-error-msg").forEach(function(el) { 427 el.remove(); 428 }); 429 430 }); 431 432 // Attach CodeDropz_Uploader to HTMLElement prototype 433 HTMLElement.prototype.CodeDropz_Uploader = CodeDropz_Uploader; 434 435})(); 436// END: CodeDropz Uploader function 437 438// BEGIN: initialize upload 439document.addEventListener('DOMContentLoaded', function() { 440 441 // Fires when an Ajax form submission has completed successfully, and mail has been sent. 442 document.addEventListener( 'wpcf7mailsent', function( event ) { 443 444 // Get form 445 const form = event.target; 446 447 // Get input type file element 448 var inputFile = form.querySelectorAll('.wpcf7-drag-n-drop-file'); 449 var status = form.querySelectorAll('.dnd-upload-status'); 450 var counter = form.querySelector('.dnd-upload-counter span'); 451 var error = form.querySelectorAll('span.has-error-msg'); 452 453 // Reset upload list for multiple fields 454 if ( inputFile.length > 0 ) { 455 inputFile.forEach( function(input) { 456 localStorage.setItem( input.getAttribute('data-name') + '_count_files', 1 ); // Reset file counts 457 }); 458 } 459 460 // Remove status / progress bar 461 if (status) { 462 status.forEach(function(statEl){ 463 statEl.remove(); 464 }); 465 } 466 467 if (counter) { 468 counter.textContent = '0'; 469 } 470 471 if (error) { 472 error.forEach(function(errEl){ 473 errEl.remove(); 474 }); 475 } 476 477 }, false ); 478 479 window.initDragDrop = function () { 480 481 // Get text object options/settings from localize script 482 var TextOJB = dnd_cf7_uploader.drag_n_drop_upload; 483 var fileUpload = document.querySelectorAll('.wpcf7-drag-n-drop-file'); 484 485 fileUpload.forEach(function(Upload) { 486 487 // Support Multiple Fileds 488 Upload.CodeDropz_Uploader({ 489 'color': '#fff', 490 'ajax_url': dnd_cf7_uploader.ajax_url, 491 'text': TextOJB.text, 492 'separator': TextOJB.or_separator, 493 'button_text': TextOJB.browse, 494 'server_max_error': TextOJB.server_max_error, 495 'on_success': function(input, progressBar, response) { 496 497 // Progressbar Object 498 var progressDetails = document.querySelector('.codedropz-upload-wrapper #' + progressBar); 499 var form = input.closest('form'); 500 var span = form.querySelector('.wpcf7-acceptance'); 501 var checkboxInput = ( span ? span.querySelector('input[type="checkbox"]') : '' ); 502 503 // Remove 'required' error message 504 const requiredMessage = input.closest('.codedropz-upload-wrapper').nextElementSibling; 505 if( requiredMessage && requiredMessage.classList.contains('wpcf7-not-valid-tip') ){ 506 requiredMessage.remove(); 507 } 508 509 // If it's complete remove disabled attribute in button 510 if ( ( span && span.classList.contains('optional') ) || ! span || checkboxInput.checked || form.classList.contains('wpcf7-acceptance-as-validation')) { 511 setTimeout(function(){ 512 form.querySelector('input[type="submit"]').removeAttribute('disabled'); 513 }, 1); 514 } 515 516 // Append hidden input field 517 var detailsElement = progressDetails.querySelector('.dnd-upload-details'); 518 var inputHTML = '<span><input type="hidden" name="' + input.dataset.name + '[]" value="' + response.data.path + '/' + response.data.file + '"></span>'; 519 detailsElement.insertAdjacentHTML('beforeend', inputHTML); 520 521 // Update counter 522 var filesCounter = ( Number( localStorage.getItem( input.dataset.name + '_count_files' ) ) - 1); 523 var counterElement = input.closest('.codedropz-upload-wrapper').querySelector('.dnd-upload-counter span'); 524 counterElement.textContent = filesCounter; 525 } 526 }); 527 528 }); 529 530 531 532 } 533 534 window.initDragDrop(); 535 536});
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.