/
var
/
www
/
barefootlaw.org
/
wp-content
/
plugins
/
wpforms
/
pro
/
assets
/
js
/
Upload File
HOME
'use strict'; ( function() { /** * All connections are slow by default. * * @since 1.6.2 * * @type {boolean|null} */ var isSlow = null; /** * Default settings for our speed test. * * @since 1.6.2 * * @type {{maxTime: number, payloadSize: number}} */ var speedTestSettings = { maxTime: 3000, // Max time (ms) it should take to be considered a 'fast connection'. payloadSize: 100 * 1024, // Payload size. }; /** * Create a random payload for the speed test. * * @since 1.6.2 * * @returns {string} Random payload. */ function getPayload() { var data = ''; for ( var i = 0; i < speedTestSettings.payloadSize; ++i ) { data += String.fromCharCode( Math.round( Math.random() * 36 + 64 ) ); } return data; } /** * Run speed tests and flag the clients as slow or not. If a connection * is slow it would let the backend know and the backend most likely * would disable parallel uploads and would set smaller chunk sizes. * * @since 1.6.2 * * @param {Function} next Function to call when the speed detection is done. */ function speedTest( next ) { if ( null !== isSlow ) { setTimeout( next ); return; } var data = getPayload(); var start = new Date; wp.ajax.post( { action: 'wpforms_file_upload_speed_test', data: data, } ).then( function() { var delta = new Date - start; isSlow = delta >= speedTestSettings.maxTime; next(); } ).fail( function() { isSlow = true; next(); } ); } /** * Toggle loading message above submit button. * * @since 1.5.6 * * @param {object} $form jQuery form element. * * @returns {Function} event handler function. */ function toggleLoadingMessage( $form ) { return function() { if ( ! $form.find( '.wpforms-uploading-in-progress-alert' ).length ) { $form.find( '.wpforms-submit-container' ).before( '<div class="wpforms-error-alert wpforms-uploading-in-progress-alert">' + window.wpforms_file_upload.loading_message + '</div>' ); } }; } /** * Disable submit button when we are sending files to the server. * * @since 1.5.6 * * @param {object} dz Dropzone object. */ function toggleSubmit( dz ) { // Force dz.loading to be zero if it's below it, to make sure we // don't decrement it below zero. if ( dz.loading < 0 ) { dz.loading = 0; } var $form = jQuery( dz.element ).closest( 'form' ), $btn = $form.find( '.wpforms-submit' ), errors = dz.getFilesWithStatus( 'error' ), handler = toggleLoadingMessage( $form ), disabled = dz.loading > 0 || errors.length > 0; if ( disabled ) { $btn.prop( 'disabled', true ); if ( ! $form.find( '.wpforms-submit-overlay' ).length ) { $btn.parent().addClass( 'wpforms-submit-overlay-container' ); $btn.parent().append( '<div class="wpforms-submit-overlay"></div>' ); $form.find( '.wpforms-submit-overlay' ).css( 'width', $btn.outerWidth() + 'px' ); $form.find( '.wpforms-submit-overlay' ).css( 'height', $btn.parent().outerHeight() + 'px' ); $form.find( '.wpforms-submit-overlay' ).on( 'click', handler ); } } else { $btn.prop( 'disabled', false ); $form.find( '.wpforms-submit-overlay' ).off( 'click', handler ); $form.find( '.wpforms-submit-overlay' ).remove(); $btn.parent().removeClass( 'wpforms-submit-overlay-container' ); if ( $form.find( '.wpforms-uploading-in-progress-alert' ).length ) { $form.find( '.wpforms-uploading-in-progress-alert' ).remove(); } } } /** * Try to parse JSON or return false. * * @since 1.5.6 * * @param {string} str JSON string candidate. * * @returns {*} Parse object or false. */ function parseJSON( str ) { try { return JSON.parse( str ); } catch ( e ) { return false; } } /** * Leave only objects with length. * * @since 1.5.6 * * @param {object} el Any array. * * @returns {bool} Has length more than 0 or no. */ function onlyWithLength( el ) { return el.length > 0; } /** * Leave only positive elements. * * @since 1.5.6 * * @param {*} el Any element. * * @returns {*} Filter only positive. */ function onlyPositive( el ) { return el; } /** * Get xhr. * * @since 1.5.6 * * @param {object} el Object with xhr property. * * @returns {*} Get XHR. */ function getXHR( el ) { return el.chunkResponse || el.xhr; } /** * Get response text. * * @since 1.5.6 * * @param {object} el Xhr object. * * @returns {object} Response text. */ function getResponseText( el ) { return typeof el === 'string' ? el : el.responseText; } /** * Get data. * * @since 1.5.6 * * @param {object} el Object with data property. * * @returns {object} Data. */ function getData( el ) { return el.data; } /** * Get value from files. * * @since 1.5.6 * * @param {object} files Dropzone files. * * @returns {object} Prepared value. */ function getValue( files ) { return files .map( getXHR ) .filter( onlyPositive ) .map( getResponseText ) .filter( onlyWithLength ) .map( parseJSON ) .filter( onlyPositive ) .map( getData ); } /** * Sending event higher order function. * * @since 1.5.6 * @since 1.5.6.1 Added special processing of a file that is larger than server's post_max_size. * * @param {object} dz Dropzone object. * @param {object} data Adding data to request. * * @returns {Function} Handler function. */ function sending( dz, data ) { return function( file, xhr, formData ) { /* * We should not allow sending a file, that exceeds server post_max_size. * With this "hack" we redefine the default send functionality * to prevent only this object from sending a request at all. * The file that generated that error should be marked as rejected, * so Dropzone will silently ignore it. * * If Chunks are enabled the file size will never exceed (by a PHP constraint) the * postMaxSize. This block shouldn't be removed nonetheless until the "modern" upload is completely * deprecated and removed. */ if ( file.size > this.dataTransfer.postMaxSize ) { xhr.send = function() {}; file.accepted = false; file.processing = false; file.status = 'rejected'; file.previewElement.classList.add( 'dz-error' ); file.previewElement.classList.add( 'dz-complete' ); return; } Object.keys( data ).forEach( function( key ) { formData.append( key, data[key] ); } ); }; } /** * Convert files to input value. * * @since 1.5.6 * * @param {object} files Files list. * * @returns {string} Converted value. */ function convertFilesToValue( files ) { return files.length ? JSON.stringify( files ) : ''; } /** * Update value in input. * * @since 1.5.6 * * @param {object} dz Dropzone object. */ function updateInputValue( dz ) { var $input = jQuery( dz.element ).parents( '.wpforms-field-file-upload' ).find( 'input[name=' + dz.dataTransfer.name + ']' ); $input.val( convertFilesToValue( getValue( dz.files ) ) ).trigger( 'input' ); if ( typeof jQuery.fn.valid !== 'undefined' ) { $input.valid(); } } /** * Complete event higher order function. * * @deprecated 1.6.2 * * @since 1.5.6 * * @param {object} dz Dropzone object. * * @returns {Function} Handler function. */ function complete( dz ) { return function() { dz.loading = dz.loading || 0; dz.loading--; toggleSubmit( dz ); updateInputValue( dz ); }; } /** * Add an error message to the current file. * * @since 1.6.2 * * @param {object} file File object. * @param {string} errorMessage Error message */ function addErrorMessage( file, errorMessage ) { if ( file.isErrorNotUploadedDisplayed ) { return; } var span = document.createElement( 'span' ); span.innerText = errorMessage.toString(); span.setAttribute( 'data-dz-errormessage', '' ); file.previewElement.querySelector( '.dz-error-message' ).appendChild( span ); } /** * Confirm the upload to the server. * * The confirmation is needed in order to let PHP know * that all the chunks have been uploaded. * * @since 1.6.2 * * @param {object} dz Dropzone object. * * @returns {Function} Handler function. */ function confirmChunksFinishUpload( dz ) { return function confirm( file ) { if ( ! file.retries ) { file.retries = 0; } if ( 'error' === file.status ) { return; } /** * Retry finalize function. * * @since 1.6.2 */ function retry() { file.retries++; if ( file.retries === 3 ) { addErrorMessage( file, window.wpforms_file_upload.errors.file_not_uploaded ); return; } setTimeout( function() { confirm( file ); }, 5000 * file.retries ); } /** * Fail handler for ajax request. * * @since 1.6.2 * * @param {object} response Response from the server */ function fail( response ) { var hasSpecificError = response.responseJSON && response.responseJSON.success === false && response.responseJSON.data; if ( hasSpecificError ) { addErrorMessage( file, response.responseJSON.data ); } else { retry(); } } /** * Handler for ajax request. * * @since 1.6.2 * * @param {object} response Response from the server */ function complete( response ) { file.chunkResponse = JSON.stringify( { data: response } ); dz.loading = dz.loading || 0; dz.loading--; toggleSubmit( dz ); updateInputValue( dz ); } wp.ajax.post( jQuery.extend( { action: 'wpforms_file_chunks_uploaded', form_id: dz.dataTransfer.formId, field_id: dz.dataTransfer.fieldId, name: file.name, }, dz.options.params.call( dz, null, null, {file: file, index: 0} ) ) ).then( complete ).fail( fail ); // Move to upload the next file, if any. dz.processQueue(); }; } /** * Toggle showing empty message. * * @since 1.5.6 * * @param {object} dz Dropzone object. */ function toggleMessage( dz ) { setTimeout( function() { var validFiles = dz.files.filter( function( file ) { return file.accepted; } ); if ( validFiles.length >= dz.options.maxFiles ) { dz.element.querySelector( '.dz-message' ).classList.add( 'hide' ); } else { dz.element.querySelector( '.dz-message' ).classList.remove( 'hide' ); } }, 0 ); } /** * Toggle error message if total size more than limit. * Runs for each file. * * @since 1.5.6 * * @param {object} file Current file. * @param {object} dz Dropzone object. */ function validatePostMaxSizeError( file, dz ) { setTimeout( function() { if ( file.size >= dz.dataTransfer.postMaxSize ) { var errorMessage = window.wpforms_file_upload.errors.post_max_size; if ( ! file.isErrorNotUploadedDisplayed ) { file.isErrorNotUploadedDisplayed = true; errorMessage = window.wpforms_file_upload.errors.file_not_uploaded + ' ' + errorMessage; addErrorMessage( file, errorMessage ); } } }, 1 ); } /** * Start File Upload. * * This would do the initial request to start a file upload. No chunk * is uploaded at this stage, instead all the information related to the * file are send to the server waiting for an authorization. * * If the server authorizes the client would start uploading the chunks. * * @since 1.6.2 * * @param {object} dz Dropzone object. * @param {object} file Current file. */ function initFileUpload( dz, file ) { wp.ajax.post( jQuery.extend( { action : 'wpforms_upload_chunk_init', form_id: dz.dataTransfer.formId, field_id: dz.dataTransfer.fieldId, name: file.name, slow: isSlow, }, dz.options.params.call( dz, null, null, {file: file, index: 0} ) ) ).then( function( response ) { // File upload has been authorized. for ( var key in response ) { dz.options[ key ] = response[ key ]; } if ( response.dzchunksize ) { dz.options.chunkSize = parseInt( response.dzchunksize, 10 ); file.upload.totalChunkCount = Math.ceil( file.size / dz.options.chunkSize ); } dz.processQueue(); } ).fail( function( response ) { file.status = 'error'; addErrorMessage( file, response ); dz.processQueue(); } ); } /** * Validate the file when it was added in the dropzone. * * @since 1.5.6 * * @param {object} dz Dropzone object. * * @returns {Function} Handler function. */ function addedFile( dz ) { return function( file ) { if ( file.size >= dz.dataTransfer.postMaxSize ) { validatePostMaxSizeError( file, dz ); } else { speedTest( function() { initFileUpload( dz, file ); } ); } dz.loading = dz.loading || 0; dz.loading++; toggleSubmit( dz ); toggleMessage( dz ); }; } /** * Send an AJAX request to remove file from the server. * * @since 1.5.6 * * @param {string} file File name. * @param {object} dz Dropzone object. */ function removeFromServer( file, dz ) { wp.ajax.post( { action: 'wpforms_remove_file', file: file, form_id: dz.dataTransfer.formId, field_id: dz.dataTransfer.fieldId, } ); } /** * Init the file removal on server when user removed it on front-end. * * @since 1.5.6 * * @param {object} dz Dropzone object. * * @returns {Function} Handler function. */ function removedFile( dz ) { return function( file ) { toggleMessage( dz ); var json = file.chunkResponse || ( file.xhr || {} ).responseText; if ( json ) { var object = parseJSON( json ); if ( object && object.data && object.data.file ) { removeFromServer( object.data.file, dz ); } } updateInputValue( dz ); dz.loading = dz.loading || 0; dz.loading--; toggleSubmit( dz ); }; } /** * Process any error that was fired per each file. * There might be several errors per file, in that case - display "not uploaded" text only once. * * @since 1.5.6.1 * * @param {object} dz Dropzone object. * * @returns {Function} Handler function. */ function error( dz ) { return function( file, errorMessage ) { if ( file.isErrorNotUploadedDisplayed ) { return; } file.isErrorNotUploadedDisplayed = true; file.previewElement.querySelectorAll( '[data-dz-errormessage]' )[0].textContent = window.wpforms_file_upload.errors.file_not_uploaded + ' ' + errorMessage; }; } /** * Dropzone.js init for each field. * * @since 1.5.6 * * @param {object} $el WPForms uploader DOM element. * * @returns {object} Dropzone object. */ function dropZoneInit( $el ) { var formId = parseInt( $el.dataset.formId, 10 ); var fieldId = parseInt( $el.dataset.fieldId, 10 ) || 0; var maxFiles = parseInt( $el.dataset.maxFileNumber, 10 ); var acceptedFiles = $el.dataset.extensions.split( ',' ).map( function( el ) { return '.' + el; } ).join( ',' ); // Configure and modify Dropzone library. var dz = new window.Dropzone( $el, { url: window.wpforms_file_upload.url, addRemoveLinks: true, chunking: true, forceChunking: true, retryChunks: true, chunkSize: parseInt( $el.dataset.fileChunkSize, 10 ), paramName: $el.dataset.inputName, parallelChunkUploads: !! ( $el.dataset.parallelUploads || '' ).match( /^true$/i ), parallelUploads: parseInt( $el.dataset.maxParallelUploads, 10 ), autoProcessQueue: false, maxFilesize: ( parseInt( $el.dataset.maxSize, 10 ) / ( 1024 * 1024 ) ).toFixed( 2 ), maxFiles: maxFiles, acceptedFiles: acceptedFiles, dictMaxFilesExceeded: window.wpforms_file_upload.errors.file_limit.replace( '{fileLimit}', maxFiles ), dictInvalidFileType: window.wpforms_file_upload.errors.file_extension, dictFileTooBig: window.wpforms_file_upload.errors.file_size, } ); // Custom variables. dz.dataTransfer = { postMaxSize: $el.dataset.maxSize, name: $el.dataset.inputName, formId: formId, fieldId: fieldId, }; // Process events. dz.on( 'sending', sending( dz, { action: 'wpforms_upload_chunk', form_id: formId, field_id: fieldId, } ) ); dz.on( 'addedfile', addedFile( dz ) ); dz.on( 'removedfile', removedFile( dz ) ); dz.on( 'complete', confirmChunksFinishUpload( dz ) ); dz.on( 'error', error( dz ) ); return dz; } /** * DOMContentLoaded handler. * * @since 1.5.6 */ function ready() { window.wpforms = window.wpforms || {}; window.wpforms.dropzones = [].slice.call( document.querySelectorAll( '.wpforms-uploader' ) ).map( dropZoneInit ); } /** * Moden File Uplaod engine. * * @since 1.6.0 */ var wpformsModernFileUpload = { /** * Start the initialization. * * @since 1.6.0 */ init: function() { if ( document.readyState === 'loading' ) { document.addEventListener( 'DOMContentLoaded', ready ); } else { ready(); } }, }; // Call init and save in global variable. wpformsModernFileUpload.init(); window.wpformsModernFileUpload = wpformsModernFileUpload; }() );