AJAX simple file uploader
A simple javascript powered file uploader with progress and hooks support. Was created as a loose replacement for FineUploader. Currently only works with local uploads Below is the log history from the previous folder: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit 6ea59f91314be8b2b936920d4b0a3f04932c9e73 ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Thu Jun 3 10:31:54 2021 +0900 AJAX file uploader code clean up Add global abort and connected clean up of function calls and element show/hide blocks Add simple progress bar for upload (in connection with percent upload) Move running AFUS object into the config object Added new config object entries for this: - abort: flagged true if global abort is triggered - running: moved from AFUS_running into config, how many uploads are currently running - current: current file_pos running (that is queue position in array) - current_xhr: current XHR upload object, used for abort calls ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit b061008ca0b496f6157b8f073d7ca14abb469ef5 ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Thu May 27 11:51:47 2021 +0900 Update AJAX file uploader to work sequential Rewrite flow in ajax uploader to use promsies to launch a new upload only if the previous upload was finished (in any way) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit a2ec369a8cae65e216fe402ac8b5d106e3db99af ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Thu May 20 11:48:38 2021 +0900 Updated ajax simple file uploader to allow multiple file uploads ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit 66878f89c82fe914031e113e780fd72e9ff09b78 ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Mon May 10 09:13:25 2021 +0900 Excel vendor sub module, ajax delay test, ajax file upload fix, others ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit e4efbbfdf843d8b2e53e4d3c873799b839875721 ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Fri Apr 9 13:44:28 2021 +0900 ajax file upload updates, byte format test fixes, ssh2 test fixes, array append test add, nested array recursive walk test add ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit 88734ebaf7420a704a538f0a923ce6996b0b5237 ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Mon Jan 25 17:15:14 2021 +0900 Add ajax uploader on error external function call Like post success uploaded, this function is called on any "non success" return falue. Passes on the full returned ajax data object ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit 2098fe53d510c03f291eaa5c4b2aefd60c24448e ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Wed Jan 13 06:29:20 2021 +0900 Add additional parameters method parameter Added on init of form, when submitted before additional external form parameters function is called ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit 0c2211e2312abf368c4151dbdf54d4fa96a121dc ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Tue Jan 12 10:09:42 2021 +0900 AJAX File uploader change for external function call. External functions are passed into the uploader as parameters. With this we can have unique functions for each init ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit c1eb15e30df319db1d5104bc5e4ab0cd8bb7cc8c ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Fri Jan 8 09:59:33 2021 +0900 AJAX file uploader target action router value dynamic setting update, other test php files updates and additions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ commit 429af6db892d6968ad87a3db662f3ff1a9d74270 ┃ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━ Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> Date: Thu Nov 5 11:33:30 2020 +0900 AJAX file uploader test code Simple single file AJAX file uploader with backend code sample. Work in progress with open - better, simpler frontend code insert part - multiple file upload - flag auto handling zip files (or tar, etc) - make it not rely on Jquery at all
This commit is contained in:
185
ReadMe.md
Executable file
185
ReadMe.md
Executable file
@@ -0,0 +1,185 @@
|
||||
# AJAX simple file upload
|
||||
|
||||
Upload multiple files with progress. Has hooks for pre/post work
|
||||
|
||||
## How to use
|
||||
|
||||
include `ajaxFileUploadSimeple.js`
|
||||
|
||||
## How to run
|
||||
|
||||
init with `initAjaxUploader(ConfigObject)`
|
||||
|
||||
Where the config object can have the following settings
|
||||
|
||||
## Config Object settiings
|
||||
|
||||
### {String} target_file
|
||||
|
||||
Must be set
|
||||
prefix for the element for the file upload
|
||||
|
||||
### {String} target_form
|
||||
|
||||
Must be set
|
||||
the master form in which this element sits
|
||||
|
||||
### {Number} [max_files=1]
|
||||
|
||||
maximum uploadable files, if 1, multiple will be removed from input file field, if 0, no limit
|
||||
|
||||
### {Number} [max_file_size=0]
|
||||
|
||||
In bytes, maximum file size. If not set unlimited. 0 is also unlimited
|
||||
|
||||
### {Array} [allowed_extensions=[]]
|
||||
|
||||
Allowed file extensions. Without leading '.'. Will be added to the input file accept list
|
||||
|
||||
### {Array} [allowed_file_types=[]]
|
||||
|
||||
Allowed file types in mime format. Will be added to the input file accept list
|
||||
|
||||
### {String} [target_router='']
|
||||
|
||||
value of the action _POST variable, if not set or if empty use "fileUpload"
|
||||
|
||||
### {String} [target_action='']
|
||||
|
||||
override the target_form action field
|
||||
|
||||
### {Object} [form_parameters={}]
|
||||
|
||||
Key/Value list for additional parameters to add to the form submit. Added BEFORE fileBeforeUpload parameters
|
||||
|
||||
### {Object} [translation={}]
|
||||
|
||||
Translated strings pushed into the AFUS_strings object
|
||||
|
||||
### {Boolean} [auto_submit=false]
|
||||
|
||||
if we override the submit button and directly upload
|
||||
|
||||
### {Function} [fileChange='']
|
||||
|
||||
Function run on change of -file element entry. Parameters are target_file, file_pos, target_router
|
||||
|
||||
### {Function} [fileChangeAll='']
|
||||
|
||||
Function run on change of -file element entry after all file changes for each entry are run. Parameters are target_file, target_router
|
||||
|
||||
### {Function} [fileRemove='']
|
||||
|
||||
Called when an upload file is removed from the queue before upload. Parameters are target_file, file_pos
|
||||
|
||||
### {Functuon} [fileClear='']
|
||||
|
||||
called when clear button is pressed. Parameters are target_file
|
||||
|
||||
### {Function} [fileBeforeUploadAll='']
|
||||
|
||||
Function called before uploads start. Parameters are target_file, target_router
|
||||
|
||||
### {Function} [fileBeforeUpload='']
|
||||
|
||||
Function called before upload starts. Parameters are target_file, file_pos, target_router
|
||||
|
||||
### {Function} [fileUploaded='']
|
||||
|
||||
Function called after upload has successfully finished. Parameters are target_file, file_pos, target_router, data (object returned from upload function call)
|
||||
|
||||
### {Function} [fileUploadedAll='']
|
||||
|
||||
After all uploads have been done, this one will be called. Parameters are target_file, target_router
|
||||
|
||||
### {Function} [fileUploadError='']
|
||||
|
||||
Function called after upload has failed. Parameters are target_file, file_pos, target_router, data (object returned from upload function call)
|
||||
|
||||
## Method call flow
|
||||
|
||||
```txt
|
||||
[**1**] initAjaxUploader
|
||||
[1 run 2] check if browser is capable for uploader
|
||||
[1 run 1-A] run config check
|
||||
[1 listen 8-C] cancel upload output
|
||||
[1 run 3] afusPassThroughEvent
|
||||
[1 run 4] run main file uploader function attachment
|
||||
```
|
||||
|
||||
```txt
|
||||
[1-A] afusUploaderConfigCheck check and clean config
|
||||
```
|
||||
|
||||
```txt
|
||||
[**2**] afusSupportAjaxUploadWithProgress
|
||||
```
|
||||
|
||||
```txt
|
||||
[**3**] afusPassThroughEvent
|
||||
[3 set 1] change event on input file
|
||||
[3 call 3-A] file extension check
|
||||
[3 call 3-B] file type check
|
||||
[3 set 2] sets upload queue delete in fileChange function
|
||||
[3 ext 2-1] fileRemove function
|
||||
[3 ext] fileChange function
|
||||
[3 ext] fileChangeAll
|
||||
[3 set 3] call click submit if auto submit
|
||||
```
|
||||
|
||||
```txt
|
||||
[3-A] afusHasExtension
|
||||
[3-B] afusHasFileType
|
||||
```
|
||||
|
||||
```txt
|
||||
[**4**] afusInitFullFormAjaxUpload
|
||||
[4 set 1] on submit function
|
||||
[4 ext] fileBeforeUploadAll function
|
||||
[4 run 6] afusSendFile main file send (promise)
|
||||
[4 run 5] call class for async submitter iterator
|
||||
[4 on finally call 8-C] finally promise: afusFinalPostUpload
|
||||
[4 on finally ext] finally promise: call fileUploadedAll external
|
||||
```
|
||||
|
||||
```txt
|
||||
[**5**] class afusAsyncUploader
|
||||
[5-A] class constructor for init
|
||||
[5-B] iterator internal loop method for processing files
|
||||
```
|
||||
|
||||
```txt
|
||||
[**6**] afusSendFile
|
||||
[6 ext] fileBeforeUpload function
|
||||
[6] main xhr uploader start
|
||||
[6 set 7-A] loadstart event afusOnloadStartHandler
|
||||
[6 set 7-C] progress event afusOnProgressHandler
|
||||
[6 set 7-B] load event afusOnloadHandler
|
||||
[6 set 7-D] readystatechange event afusOnReadyStateChangeHandler
|
||||
```
|
||||
|
||||
```txt
|
||||
[7-A] afusOnloadStartHandler
|
||||
[7-A call 9-A] add +1 to running
|
||||
[7-B] afusOnloadHandler
|
||||
[7-C] afusOnProgressHandler
|
||||
[7-D] afusOnReadyStateChangeHandler
|
||||
[7-D call 9-B] -1 for running queue count
|
||||
[7-D call 8-B] afusUploadError
|
||||
[7-D call 8-A] if success afusPostUpload
|
||||
[7-D ext] if error fileUploadError function
|
||||
```
|
||||
|
||||
```txt
|
||||
[8-A] afusPostUpload
|
||||
[8-B] afusUploadError
|
||||
[8-C] afusCancelUploadOutput
|
||||
[8-D] afusFinalPostUpload
|
||||
[8-E] afusResetInternalVariables
|
||||
```
|
||||
|
||||
```txt
|
||||
[9-A] afusRunningStart
|
||||
[9-B] afusRunningStop
|
||||
[9-C] afusRunningGet
|
||||
```
|
||||
532
src/ajaxFileUploadSimple.OLD.js
Executable file
532
src/ajaxFileUploadSimple.OLD.js
Executable file
@@ -0,0 +1,532 @@
|
||||
/* AJAX File upload simple */
|
||||
|
||||
/* jshint esversion: 6 */
|
||||
|
||||
/* global errorCatch */
|
||||
|
||||
/**
|
||||
* CUSTOM SUB CALL FUNCTIONS as passsd on in init call
|
||||
* fileChange(target_file, target_router)
|
||||
* fileBeforeUpload(target_file, target_router)
|
||||
* fileUploaded(target_file, target_router, control_data)
|
||||
* fileUploadError(target_file, target_router, control_data)
|
||||
*/
|
||||
|
||||
var AFUS_strings = {};
|
||||
|
||||
/**
|
||||
* [5-A] show progress circle
|
||||
* Hides the submit button
|
||||
* If a "confirm" button is present hides this one too
|
||||
* !TODO! call external function for additional checks
|
||||
* and move eg confirm buttons check there
|
||||
* @param {String} target_file prefix for elements
|
||||
*/
|
||||
function showProgress(target_file)
|
||||
{
|
||||
// console.log('Show progress circle');
|
||||
// hide the upload button itself so we don't press twice
|
||||
$('#' + target_file + '-submit').hide();
|
||||
if ($('#mask-' + target_file).length > 0) {
|
||||
$('#mask-' + target_file).hide();
|
||||
} else {
|
||||
$('#' + target_file + '-file').hide();
|
||||
}
|
||||
// check if we have button "confirm" and disable it
|
||||
if ($('#confirm').length > 0) {
|
||||
$('#confirm').prop('disabled', true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [7-C] hide progress circle
|
||||
* Show submit button again
|
||||
* If a "confirm" button is present show this one too
|
||||
* !TODO! call external function for additional checks
|
||||
* and move eg confirm buttons check there
|
||||
* @param {String} target_file prefix for elements
|
||||
*/
|
||||
function hideProgress(target_file)
|
||||
{
|
||||
// console.log('Hide progress circle');
|
||||
// show the upload button again after upload
|
||||
$('#' + target_file + '-submit').show();
|
||||
if ($('#' + target_file + '-submit-div').length > 0) {
|
||||
$('#' + target_file + '-submit-div').show();
|
||||
}
|
||||
if ($('#mask-' + target_file).length > 0) {
|
||||
$('#mask-' + target_file).show();
|
||||
// on mask hide button after upload
|
||||
$('#' + target_file + '-submit').hide();
|
||||
if ($('#' + target_file + '-submit-div').length > 0) {
|
||||
$('#' + target_file + '-submit-div').hide();
|
||||
}
|
||||
} else {
|
||||
$('#' + target_file + '-file').show();
|
||||
}
|
||||
// check if we have button "confirm" and disable it
|
||||
if ($('#confirm').length > 0) {
|
||||
$('#confirm').prop('disabled', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [7-B] upload error
|
||||
* prints upload error messages into the status field
|
||||
* @param {String} target_file prefix for elements
|
||||
* @param {Array} error_message error message, if not set standard error is shown
|
||||
* @param {Boolean} is_error if set true, then add error message class
|
||||
*/
|
||||
function uploadError(target_file, error_message, is_error)
|
||||
{
|
||||
// set if empty
|
||||
if (error_message.length == 0) {
|
||||
error_message.push('[JS Upload Lib] Upload Error');
|
||||
}
|
||||
// write error message
|
||||
document.getElementById(target_file + '-upload-status').innerHTML = error_message.join('<br>');
|
||||
// add error style to upload status
|
||||
if (is_error === true) {
|
||||
$('#' + target_file + '-upload-status').addClass('SubError');
|
||||
} else {
|
||||
$('#' + target_file + '-upload-status').removeClass('SubError');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [3] pass through event
|
||||
* Checks if a mask- element is present and then attaches
|
||||
* the passthrough event to the internal files button
|
||||
* checks if fileChange variable is a function and calls it
|
||||
* @param {String} target_file Prefix for elements
|
||||
* @param {String} target_router Router target name
|
||||
* @param {Boolean} auto_submit If set true will pass by submit button click
|
||||
* and automatically upload
|
||||
* @param {Function} fileChange A function with two string parameters
|
||||
* target_file, target_router
|
||||
* Is called on change of -file entry
|
||||
*/
|
||||
function passThroughEvent(target_file, target_router, auto_submit, fileChange)
|
||||
{
|
||||
console.log('[AJAX Uploader: %s] Element exists: %s',target_file, $('#mask-' + target_file + '-file').length);
|
||||
if ($('#mask-' + target_file + '-file').length > 0) {
|
||||
// hide the other elements
|
||||
// hide submit button until file is selected
|
||||
$('#' + target_file + '-file, #mask-' + target_file + '-file, #' + target_file + '-submit, #' + target_file + '-submit-div').hide();
|
||||
// init wipe upload status
|
||||
$('#' + target_file + '-upload-status').html('');
|
||||
// write file name to upload status
|
||||
// show submit button
|
||||
$('#' + target_file + '-file').change(function() {
|
||||
$('#mask-' + target_file + '-file').val($('#' + target_file + '-file').val());
|
||||
$('#' + target_file + '-upload-status').html(document.getElementById(target_file + '-file').files[0].name);
|
||||
$('#' + target_file + '-upload-status').show();
|
||||
if (auto_submit === false) {
|
||||
$('#' + target_file + '-submit').show();
|
||||
if ($('#' + target_file + '-submit-div').length > 0) {
|
||||
$('#' + target_file + '-submit-div').show();
|
||||
}
|
||||
}
|
||||
// file upload changed function
|
||||
if (typeof fileChange === 'function') {
|
||||
fileChange(target_file, target_router);
|
||||
}
|
||||
// if auto submit flaged
|
||||
console.log('AUTO SUBMIT: %s', auto_submit);
|
||||
if (auto_submit === true) {
|
||||
document.getElementById(target_file + '-submit').click();
|
||||
}
|
||||
});
|
||||
$('#mask-' + target_file + '-file').click(function() {
|
||||
var $elm = $('#' + target_file + '-file');
|
||||
if (document.createEvent) {
|
||||
var e = document.createEvent('MouseEvents');
|
||||
e.initEvent('click', true, true );
|
||||
$elm.get(0).dispatchEvent(e);
|
||||
} else {
|
||||
$elm.trigger('click');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [7-A] final step after upload
|
||||
* The last action to be called, fills all the hidden values
|
||||
* - uid
|
||||
* - file_name
|
||||
* - file_size
|
||||
* Inserts thumbnail if url exists
|
||||
* Adds uploaded file name and file size if flags show_name/show_size are set
|
||||
* The function checks for "fileUploaded" and if it exists
|
||||
* it will be called with the "other_data" object
|
||||
* @param {String} target_file Prefix for elements
|
||||
* @param {String} target_router Target router name
|
||||
* @param {Object} file_info Object with all the additional data returned from AJAX
|
||||
* @param {Object} data Full Object set (including file_info)
|
||||
* @param {Function} fileUploaded A function with two string and one object parameters
|
||||
* target_file, target_router, data
|
||||
* Is called after the upload has finished successfully
|
||||
*/
|
||||
function postUpload(target_file, target_router, file_info, data, fileUploaded)
|
||||
{
|
||||
console.log('[AJAX Uploader: %s] Post upload: File: %s, URL: %s, Name: %s, Size: %s', target_file, file_info.file_uid, file_info.file_url, file_info.file_name, file_info.file_size);
|
||||
// reset upload file, etc
|
||||
document.getElementById(target_file + '-file').value = '';
|
||||
// safari issues?
|
||||
document.getElementById(target_file + '-file').type = '';
|
||||
document.getElementById(target_file + '-file').type = 'file';
|
||||
// set internal uid
|
||||
document.getElementById(target_file + '-uid').value = file_info.file_uid;
|
||||
// name & size
|
||||
document.getElementById(target_file + '-file_name').value = file_info.file_name;
|
||||
document.getElementById(target_file + '-file_size').value = file_info.file_size_raw;
|
||||
// set thumb here, if we haveone
|
||||
// file_info also holds the output flags show_name, show_size if we want to show additional info
|
||||
// add remove file from here too (submits with uid to remove tmp uploaded file)
|
||||
// clear any previous content
|
||||
document.getElementById(target_file + '-uploaded').innerHTML = '';
|
||||
var element;
|
||||
// set base CSS prefix if set or use standard one
|
||||
var base_css = file_info.css ? file_info.css : 'image-upload';
|
||||
if (file_info.file_url) {
|
||||
element = document.createElement('img');
|
||||
element.src = file_info.file_url;
|
||||
element.id = target_file + '-input-thumbnail';
|
||||
element.className = base_css + '-img';
|
||||
document.getElementById(target_file + '-uploaded').appendChild(element);
|
||||
$('#' + target_file + '-uploaded').show();
|
||||
}
|
||||
// if we have name/size addition
|
||||
if (file_info.show_name || file_info.show_size) {
|
||||
element = document.createElement('div');
|
||||
element.className = base_css + '-text';
|
||||
if (file_info.show_name) {
|
||||
element.innerHTML = file_info.file_name;
|
||||
}
|
||||
if (file_info.show_size) {
|
||||
element.innerHTML += ' (' + file_info.file_size + ')';
|
||||
}
|
||||
document.getElementById(target_file + '-uploaded').appendChild(element);
|
||||
$('#' + target_file + '-uploaded').show();
|
||||
}
|
||||
if (typeof fileUploaded === 'function') {
|
||||
fileUploaded(target_file, target_router, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [2] Function that will allow us to know if Ajax uploads are supported
|
||||
* @return {Boolean} true on "ajax file uploaded supported", false on not possible
|
||||
*/
|
||||
function supportAjaxUploadWithProgress()
|
||||
{
|
||||
return supportFileAPI() && supportAjaxUploadProgressEvents() && supportFormData();
|
||||
// Is the File API supported?
|
||||
function supportFileAPI()
|
||||
{
|
||||
var fi = document.createElement('INPUT');
|
||||
fi.type = 'file';
|
||||
return 'files' in fi;
|
||||
}
|
||||
// Are progress events supported?
|
||||
function supportAjaxUploadProgressEvents()
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
return !! (xhr && ('upload' in xhr) && ('onprogress' in xhr.upload));
|
||||
}
|
||||
// Is FormData supported?
|
||||
function supportFormData()
|
||||
{
|
||||
return !! window.FormData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [1] this has to be called to start the uploader
|
||||
* checks if ajax upload is supported and if yes
|
||||
* checks if we need to set the pass through click event
|
||||
* then calls the final init that loads the form.submit catcher
|
||||
* @param {String} target_file prefix for the element for the file upload
|
||||
* @param {String} target_form the master form in which this element sits
|
||||
* @param {String} [target_router=''] value of the action _POST variable, if not set or
|
||||
* if empty use "fileUpload"
|
||||
* NOTE: default = '' has been removed to work with IE11
|
||||
* @param {String} [target_action=''] override the target_form action field
|
||||
* NOTE: default = '' has been removed to work with IE11
|
||||
* @param {Object} [form_parameters={}] Key/Value list for additional parameters to add to the form submit.
|
||||
* Added BEFORE fileBeforeUpload parameters
|
||||
* @param {Boolean} [auto_submit=false] if we override the submit button
|
||||
* and directly upload
|
||||
* NOTE: default = false has been removed to work with IE11
|
||||
* @param {Function} [fileChange=''] Function run on change of -file element entry
|
||||
* Parameters are target_file, target_router
|
||||
* NOTE: default = false has been removed to work with IE11
|
||||
* @param {Function} [fileBeforeUpload=''] Function called before upload starts
|
||||
* Parameters are target_file, target_router
|
||||
* NOTE: default = false has been removed to work with IE11
|
||||
* @param {Function} [fileUploaded=''] Function called after upload has successfully finished
|
||||
* Parameters are target_file, target_router, data (object returned from upload function call)
|
||||
* NOTE: default = false has been removed to work with IE11
|
||||
* @param {Function} [fileUploadError=''] Function called after upload has failed
|
||||
* Parameters are target_file, target_router, data (object returned from upload function call)
|
||||
* NOTE: default = false has been removed to work with IE11
|
||||
*/
|
||||
function initAjaxUploader(target_file, target_form, target_router, target_action, form_parameters, auto_submit, fileChange, fileBeforeUpload, fileUploaded, fileUploadError)
|
||||
{
|
||||
// Actually confirm support
|
||||
if (supportAjaxUploadWithProgress()) {
|
||||
console.log('[AJAX Uploader: %s] init [%s]', target_file, target_router);
|
||||
if (document.getElementById(target_file + '-submit') !== null) {
|
||||
// add click event for the submit buttons to set which one submitted the file
|
||||
document.getElementById(target_file + '-submit').addEventListener('click', function() {
|
||||
this.form.submitted = this.id;
|
||||
});
|
||||
// set pass through events
|
||||
passThroughEvent(target_file, target_router, auto_submit, fileChange);
|
||||
// Ajax uploads are supported!
|
||||
// Init the Ajax form submission
|
||||
// pass on the target_file and the master form name
|
||||
initFullFormAjaxUpload(target_file, target_form, target_router, target_action, form_parameters, fileBeforeUpload, fileUploaded, fileUploadError);
|
||||
} else {
|
||||
console.log('[AJAX Uploader: %s] Element not found for init', target_file);
|
||||
}
|
||||
} else {
|
||||
console.log('[AJAX Uploader: %s] failed', target_file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [4] MAIN CALL for upload
|
||||
* Creates the main ajax send request if a submit on the main form is detected
|
||||
* all the parameters are passed on from the init function
|
||||
* The function will throw an error of not action (target) can be found
|
||||
* @param {String} target_file prefix for the element for the file upload
|
||||
* @param {String} target_form the master form in which this element sits
|
||||
* @param {String} target_router value of the action _POST variable
|
||||
* @param {String} target_action override the target_form action field (target file)
|
||||
* @param {Object} form_parameters additional parameters added to the form submit
|
||||
* @param {Function} fileBeforeUpload Function with two string parameters
|
||||
* target_file, target_router
|
||||
* Is called on submit before upload starts
|
||||
* @param {Function} fileUploaded Is passed through to sendXHRequest
|
||||
* @param {Function} fileUploadError Is passed through to sendXHRequest
|
||||
* @return {Boolean} false to not trigger normal form submit
|
||||
*/
|
||||
function initFullFormAjaxUpload(target_file, target_form, target_router, target_action, form_parameters, fileBeforeUpload, fileUploaded, fileUploadError)
|
||||
{
|
||||
// should check that form exists
|
||||
// + '-form'
|
||||
var form = document.getElementById(target_form);
|
||||
if (!form.getAttribute('action') && !target_action) {
|
||||
console.log('!!!!! MISSING FORM ACTION ENTRY');
|
||||
throw new Error('!!!!! MISSING FORM ACTION ENTRY');
|
||||
}
|
||||
form.onsubmit = function()
|
||||
{
|
||||
var path = window.location.pathname;
|
||||
// do we end in .php, we need to remove the name then, we just want the path
|
||||
if (path.indexOf('.php') != -1) {
|
||||
// remove trailing filename (all past last / )
|
||||
path = path.replace(/\w+\.php/, '');
|
||||
}
|
||||
if (path.substr(-1) != '/') {
|
||||
path += '/';
|
||||
}
|
||||
// get the form.submitted text (remove -submit) and compare to target_file,
|
||||
// if different overwrite the target file
|
||||
var _target_file = form.submitted.split('-')[0];
|
||||
console.log('[AJAX Uploader: %s] Wanted: %s, Submitted: %s', target_file, _target_file, form.submitted);
|
||||
if (target_file != _target_file) {
|
||||
target_file = _target_file;
|
||||
}
|
||||
// remove previous highlight if set
|
||||
$('#' + target_file + '-upload-status').removeClass('SubError');
|
||||
$('#' + target_file + '-upload-status').show();
|
||||
// progress highlight
|
||||
showProgress(target_file);
|
||||
// console.log('[AJAX Uploader: %s] Start upload', target_file);
|
||||
// create new form
|
||||
var formData = new FormData();
|
||||
// We send the data where the form wanted
|
||||
var action = form.getAttribute('action');
|
||||
// in case we have a target action set, we overwirde
|
||||
if (target_action) {
|
||||
action = target_action;
|
||||
}
|
||||
console.log('[AJAX Uploader: %s] ACTION: %s, PATH: %s', target_file, action, path);
|
||||
// add action
|
||||
if (!target_router) {
|
||||
target_router = 'fileUpload';
|
||||
}
|
||||
formData.append('action', target_router);
|
||||
formData.append('uploadName', target_file + '-file');
|
||||
// add file only (first file found) with target file name
|
||||
formData.append(target_file + '-file', document.getElementById(target_file + '-file').files[0]);
|
||||
// append file uid if exists
|
||||
formData.append(target_file + '-uid', $('#' + target_file + '-uid').val());
|
||||
// add additional ones
|
||||
for (const [key, value] of Object.entries(form_parameters)) {
|
||||
formData.append(key, value);
|
||||
}
|
||||
// external data gets added
|
||||
if (typeof fileBeforeUpload === 'function') {
|
||||
for (const [key, value] of Object.entries(fileBeforeUpload(target_file, target_router))) {
|
||||
formData.append(key, value);
|
||||
}
|
||||
}
|
||||
console.log('[AJAX Uploader: %s] Send data to: %s, with path: %s', target_file, action, path);
|
||||
// run translation check, must have at least two basic strings set
|
||||
// if they are not set, set default values here
|
||||
/*if (!Object.prototype.hasOwnProperty.call(AFUS_strings, 'upload_start')) {
|
||||
AFUS_strings.upload_start = 'Upload start';
|
||||
}
|
||||
if (!Object.prototype.hasOwnProperty.call(AFUS_strings, 'upload_finished')) {
|
||||
AFUS_strings.upload_finished = 'Upload finished';
|
||||
}*/
|
||||
// debugger;
|
||||
// Code common to both variants
|
||||
sendXHRequest(target_file, target_router, formData, path + action, fileUploaded, fileUploadError);
|
||||
console.log('[AJAX Uploader: %s] Data sent to: %s', target_file, action);
|
||||
// Avoid normal form submission
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* [5-B]
|
||||
* Once the FormData instance is ready and we know
|
||||
* where to send the data, the data gets submitted
|
||||
* it adds event listeners for start/progress/load and general ready state change
|
||||
* then it sends the data
|
||||
* each event listener is called during the stages
|
||||
* - start: onloadstartHandler
|
||||
* - progress: onprogressHandler
|
||||
* - end: onloadHandler
|
||||
* - finish: onreadystatechangeHandler
|
||||
* Note: on xhr.onerror function is called if an error happens
|
||||
* and just calls the xhr.send again
|
||||
* there are some issues on firefox that can trigger this
|
||||
* @param {String} target_file Element name prefix
|
||||
* @param {String} target_router Target router name
|
||||
* @param {Object} formData The form data created in the init full function
|
||||
* @param {String} uri The target uri to where the data should be sent
|
||||
* @param {Function} fileUploaded Is passed through to onreadystatechangeHandler
|
||||
* @param {Function} fileUploadError Is passed through to onreadystatechangeHandler
|
||||
*/
|
||||
function sendXHRequest(target_file, target_router, formData, uri, fileUploaded, fileUploadError)
|
||||
{
|
||||
// Get an XMLHttpRequest instance
|
||||
var xhr = new XMLHttpRequest();
|
||||
// Set up events
|
||||
xhr.upload.addEventListener('loadstart', onloadstartHandler.bind(null, target_file), false);
|
||||
xhr.upload.addEventListener('progress', onprogressHandler.bind(null, target_file), false);
|
||||
xhr.upload.addEventListener('load', onloadHandler.bind(null, target_file), false);
|
||||
xhr.addEventListener('readystatechange', onreadystatechangeHandler.bind(null, target_file, target_router, fileUploaded, fileUploadError), false);
|
||||
// alternative pass on via target file
|
||||
// xhr.targetFile = target_file;
|
||||
// Set up request
|
||||
xhr.open('POST', uri, true);
|
||||
// Fire!
|
||||
xhr.send(formData);
|
||||
// on error log & try again
|
||||
xhr.onerror = function() {
|
||||
console.log('[AJAX Uploader: %s] upload ERROR', target_file);
|
||||
// try again
|
||||
xhr.open('POST', uri, true);
|
||||
xhr.send(formData);
|
||||
};
|
||||
console.log('[AJAX Uploader: %s] SEND DATA: %o', target_file, formData);
|
||||
}
|
||||
|
||||
/**
|
||||
* [6-A] Handle the start of the transmission
|
||||
* @param {String} target_file element name prefix
|
||||
*/
|
||||
function onloadstartHandler(target_file)
|
||||
{
|
||||
// console.log('[AJAX Uploader: %s] start uploading', target_file);
|
||||
// must set dynamic
|
||||
var div = document.getElementById(target_file + '-upload-status');
|
||||
div.innerHTML = AFUS_strings.upload_start || 'Upload start';
|
||||
}
|
||||
|
||||
/**
|
||||
* [6-B] Handle the end of the transmission
|
||||
* @param {String} target_file element name prefix
|
||||
*/
|
||||
function onloadHandler(target_file)
|
||||
{
|
||||
// console.log('[AJAX Uploader: %s] finished uploading', target_file);
|
||||
// must set dynamic
|
||||
var div = document.getElementById(target_file + '-upload-status');
|
||||
div.innerHTML = AFUS_strings.upload_finished || 'Upload finished';
|
||||
}
|
||||
|
||||
/**
|
||||
* [6-C] Handle the progress
|
||||
* calculates percent and show that in the upload status element
|
||||
* @param {String} target_file element name prefix
|
||||
* @param {Event} evt event data for upload progress
|
||||
* holds file size and bytes transmitted
|
||||
*/
|
||||
function onprogressHandler(target_file, evt)
|
||||
{
|
||||
// must set dynamic
|
||||
var div = document.getElementById(target_file + '-upload-status');
|
||||
var percent = evt.loaded / evt.total * 100;
|
||||
// console.log('[AJAX Uploader: %s] Uploading: %s', target_file, Math.round(percent));
|
||||
div.innerHTML = Math.round(percent) + '%';
|
||||
}
|
||||
|
||||
/**
|
||||
* [6-D] Handle the response from the server
|
||||
* If ready state is 4 it will call the final post upload function on status success
|
||||
* if status is other it will call the upload error function
|
||||
* on all other statii it currently only prints a debug log message
|
||||
* @param {String} target_file Element name prefix
|
||||
* @param {String} target_router Target router name
|
||||
* @param {Function} fileUploaded Is passed through to postUpload
|
||||
* @param {Function} fileUploadError Is called on error
|
||||
* @param {Event} evt event data for return data and ready state info
|
||||
*/
|
||||
function onreadystatechangeHandler(target_file, target_router, fileUploaded, fileUploadError, evt)
|
||||
{
|
||||
var status, readyState, responseText, responseData;
|
||||
try {
|
||||
readyState = evt.target.readyState;
|
||||
responseText = evt.target.responseText;
|
||||
status = evt.target.status;
|
||||
} catch(e) {
|
||||
errorCatch(e);
|
||||
return;
|
||||
}
|
||||
if (readyState == 4 && status == '200' && responseText) {
|
||||
responseData = JSON.parse(responseText);
|
||||
// must set dynamic
|
||||
console.log('[AJAX Uploader: %s] Uploader response: %s -> %o', target_file, responseData.status, responseData);
|
||||
uploadError(target_file, responseData.content.msg, false);
|
||||
// run post uploader
|
||||
if (responseData.status == 'success') {
|
||||
postUpload(target_file, target_router, {
|
||||
file_uid: responseData.content.file_uid,
|
||||
file_url: responseData.content.file_url,
|
||||
file_size: responseData.content.file_size,
|
||||
file_size_raw: responseData.content.file_size_raw,
|
||||
file_name: responseData.content.file_name,
|
||||
show_name: responseData.content.show_name,
|
||||
show_size: responseData.content.show_size,
|
||||
css: responseData.content.css
|
||||
}, responseData.content, fileUploaded);
|
||||
} else {
|
||||
// uploadError(target_file, responseData.content.msg, true);
|
||||
if (typeof fileUploadError === 'function') {
|
||||
fileUploadError(target_file, target_router, responseData.content);
|
||||
}
|
||||
}
|
||||
hideProgress(target_file);
|
||||
} else {
|
||||
console.log('[AJAX Uploader: %s] ReadyState: %s, status: %s, Text: %o', target_file, readyState, status, responseText);
|
||||
}
|
||||
}
|
||||
1222
src/ajaxFileUploadSimple.js
Executable file
1222
src/ajaxFileUploadSimple.js
Executable file
File diff suppressed because it is too large
Load Diff
336
test/backend.php
Normal file
336
test/backend.php
Normal file
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
|
||||
header("Content-Type: application/json; charset=UTF-8");
|
||||
session_start();
|
||||
define('DS', DIRECTORY_SEPARATOR);
|
||||
define('DIR', __DIR__ . DS);
|
||||
define('LOG', 'log' . DS);
|
||||
// run id
|
||||
DEFINE('RUNUID', session_id());
|
||||
|
||||
function logWrite($message)
|
||||
{
|
||||
global $fh;
|
||||
if (!$fh) {
|
||||
$fh = fopen(DIR . LOG . 'backend.' . date("Y-m-d") . '.log', 'a');
|
||||
}
|
||||
fwrite($fh, '{' . RUNUID . '} [' . printTime() . '] ' . $message . "\n");
|
||||
}
|
||||
|
||||
function logHandleClose()
|
||||
{
|
||||
global $fh;
|
||||
if ($fh) {
|
||||
fclose($fh);
|
||||
}
|
||||
}
|
||||
|
||||
function printTime()
|
||||
{
|
||||
$set_microtime = 4;
|
||||
list($microtime, $timestamp) = explode(' ', microtime());
|
||||
$string = date("Y-m-d H:i:s", $timestamp);
|
||||
// if microtime flag is -1 no round, if 0, no microtime, if >= 1, round that size
|
||||
$string .= substr(number_format(round($microtime, $set_microtime), $set_microtime), 1);
|
||||
return $string;
|
||||
}
|
||||
|
||||
function errMsg(string $level, string $message): void
|
||||
{
|
||||
global $error_string;
|
||||
|
||||
$error_string[] = [
|
||||
'level' => $level,
|
||||
'str' => $message
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* [printAr description]
|
||||
* @param array $array [description]
|
||||
* @return string [description]
|
||||
*/
|
||||
function printAr(array $array): string
|
||||
{
|
||||
return "<pre>" . print_r($array, true) . "</pre>";
|
||||
}
|
||||
|
||||
/**
|
||||
* helper function for PHP file upload error messgaes to messge string
|
||||
* @param int $error_code integer _FILE upload error code
|
||||
* @return string message string, translated
|
||||
*/
|
||||
function fileUploadErrorMessage(int $error_code): string
|
||||
{
|
||||
switch ($error_code) {
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
$message = 'The uploaded file exceeds the upload_max_filesize directive in php.ini';
|
||||
break;
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
$message = 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form';
|
||||
break;
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
$message = 'The uploaded file was only partially uploaded';
|
||||
break;
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
$message = 'No file was uploaded';
|
||||
break;
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
$message = 'Missing a temporary folder';
|
||||
break;
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
$message = 'Failed to write file to disk';
|
||||
break;
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
$message = 'File upload stopped by extension';
|
||||
break;
|
||||
default:
|
||||
$message = 'Unknown upload error';
|
||||
break;
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates psuedo random uuid v4
|
||||
* Code take from class here:
|
||||
* https://www.php.net/manual/en/function.uniqid.php#94959
|
||||
* @return string pseudo random uuid v4
|
||||
*/
|
||||
function uuidv4(): string
|
||||
{
|
||||
return sprintf(
|
||||
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
// 32 bits for "time_low"
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
// 16 bits for "time_mid"
|
||||
mt_rand(0, 0xffff),
|
||||
// 16 bits for "time_hi_and_version",
|
||||
// four most significant bits holds version number 4
|
||||
mt_rand(0, 0x0fff) | 0x4000,
|
||||
// 16 bits, 8 bits for "clk_seq_hi_res",
|
||||
// 8 bits for "clk_seq_low",
|
||||
// two most significant bits holds zero and one for variant DCE1.1
|
||||
mt_rand(0, 0x3fff) | 0x8000,
|
||||
// 48 bits for "node"
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int|float $bytes bytes as string int or pure int
|
||||
* @return string converted byte number (float) with suffix
|
||||
*/
|
||||
function humanReadableByteFormat($bytes): string
|
||||
{
|
||||
// if not numeric, return as is
|
||||
if (is_numeric($bytes)) {
|
||||
// space before name
|
||||
$space = true;
|
||||
// use sprintf instead of round
|
||||
$adjust = true;
|
||||
// use SI 1000 mod and not 1024 mod
|
||||
$si = false;
|
||||
|
||||
// si or normal
|
||||
$unit = $si ? 1000 : 1024;
|
||||
// always positive
|
||||
$abs_bytes = $bytes == PHP_INT_MIN ? PHP_INT_MAX : abs($bytes);
|
||||
// smaller than unit is always B
|
||||
if ($abs_bytes < $unit) {
|
||||
return $bytes . 'B';
|
||||
}
|
||||
// labels in order of size [Y, Z]
|
||||
$labels = array('', 'K', 'M', 'G', 'T', 'P', 'E');
|
||||
// exp position calculation
|
||||
$exp = floor(log($abs_bytes, $unit));
|
||||
// avoid printing out anything larger than max labels
|
||||
if ($exp >= count($labels)) {
|
||||
$exp = count($labels) - 1;
|
||||
}
|
||||
// deviation calculation
|
||||
$dev = pow($unit, $exp) * ($unit - 0.05);
|
||||
// shift the exp +1 for on the border units
|
||||
if (
|
||||
$exp < 6 &&
|
||||
$abs_bytes > ($dev - (((int)$dev & 0xfff) == 0xd00 ? 52 : 0))
|
||||
) {
|
||||
$exp++;
|
||||
}
|
||||
// label name, including leading space if flagged
|
||||
$pre = ($space ? ' ' : '') . ($labels[$exp] ?? '>E') . ($si ? 'i' : '') . 'B';
|
||||
$bytes_calc = $abs_bytes / pow($unit, $exp);
|
||||
if ($adjust) {
|
||||
return sprintf("%.2f%s", $bytes_calc, $pre);
|
||||
} else {
|
||||
return round($bytes_calc, 2) . $pre;
|
||||
}
|
||||
} else {
|
||||
// if anything other return as string
|
||||
return (string)$bytes;
|
||||
}
|
||||
}
|
||||
|
||||
$error = false;
|
||||
$status = 'error';
|
||||
$error_string = [];
|
||||
$ajax_data = [];
|
||||
$folder = DIR . 'uploaded' . DS;
|
||||
|
||||
logWrite(print_r($_POST, true));
|
||||
|
||||
// backend receiver calls
|
||||
if (isset($_POST['action'])) {
|
||||
// action switch statement
|
||||
switch ($_POST['action']) {
|
||||
case 'chainAction':
|
||||
$ajax_data['chain'] = 'Just A chain action: ' . ($_POST['chain'] ?? '-');
|
||||
$status = 'ok';
|
||||
errMsg($status, 'Successful chained action');
|
||||
break;
|
||||
// list current files
|
||||
case 'fileList':
|
||||
$ajax_data['reference_id'] = uniqid();
|
||||
if (is_dir($folder)) {
|
||||
$file_array = [];
|
||||
// sorted by date
|
||||
$files = glob($folder . DIRECTORY_SEPARATOR . '*');
|
||||
// oldest top
|
||||
usort($files, function ($x, $y) {
|
||||
return filemtime($x) > filemtime($y) ? 1 : -1;
|
||||
});
|
||||
foreach ($files as $file) {
|
||||
$file_array[] = [
|
||||
'name' => basename($file),
|
||||
'create_date' => date("Y-m-d H:i:s", filemtime($file)),
|
||||
'size' => humanReadableByteFormat((int)filesize($file))
|
||||
];
|
||||
}
|
||||
$ajax_data['file_list'] = $file_array;
|
||||
$status = 'ok';
|
||||
if (!count($file_array)) {
|
||||
$status = 'warn';
|
||||
$ajax_data['info'] = 'No files uploaded yet';
|
||||
}
|
||||
} else {
|
||||
$error = true;
|
||||
errMsg($status, 'Uploaded folder not found');
|
||||
}
|
||||
break;
|
||||
// for simple single file upload
|
||||
case 'fileUpload':
|
||||
// has a target name (file prefix flag)
|
||||
$upload_name = $_POST['uploadName'];
|
||||
// $this->debug('FILE UPLOAD', 'ALL FILES: '.$this->printAr($_FILES));
|
||||
// errMsg('debug', 'Called for: ' . $upload_name . ' with data: '
|
||||
// . (isset($_FILES[$upload_name]) ? printAr($_FILES[$upload_name]) : 'NOT FOUND'));
|
||||
// return string & array init
|
||||
$file_upload_message = [];
|
||||
// do we have an upload actually
|
||||
if (
|
||||
isset($_FILES[$upload_name]['error']) &&
|
||||
$_FILES[$upload_name]['error'] == UPLOAD_ERR_OK
|
||||
) {
|
||||
// set status to success post all checks
|
||||
$status = 'success';
|
||||
// strip out -file from upload name for search
|
||||
$_upload_name = str_replace('-file', '', $upload_name);
|
||||
$mime_type = null;
|
||||
|
||||
$ajax_data = [
|
||||
'msg' => [],
|
||||
'file_uid' => null,
|
||||
'file_url' => null,
|
||||
'file_name' => null,
|
||||
'file_size' => null,
|
||||
'file_size_raw' => null,
|
||||
'file_type' => null,
|
||||
];
|
||||
// check mime type for file and do check if we have a "valid_files" settings
|
||||
$finfo = new \finfo(FILEINFO_MIME_TYPE);
|
||||
$mime_type = $finfo->file($_FILES[$upload_name]['tmp_name']);
|
||||
if (!in_array($mime_type, ['text/csv', 'text/plain', 'text/x-php'])) {
|
||||
$file_upload_message[] = 'File type must be CSV or PHP: ' . $mime_type;
|
||||
$ajax_data['msg'] = $file_upload_message;
|
||||
$ajax_data['error'] = 'File type must be CSV or PHP: ' . $mime_type;
|
||||
$status = 'error';
|
||||
}
|
||||
// ON ERROR set status = 'error';
|
||||
// file type ok and file size ok, we commence actualy upload
|
||||
if ($status == 'success') {
|
||||
// basic file id data
|
||||
$file_uid = null;
|
||||
$file_url = null;
|
||||
$file_name = null;
|
||||
$file_size = null;
|
||||
$file_size_raw = null;
|
||||
|
||||
$file_upload_message[] = 'File upload successful';
|
||||
// internal file id
|
||||
$file_uid = uuidv4();
|
||||
// move file to tmp location and return new name
|
||||
move_uploaded_file(
|
||||
$_FILES[$upload_name]['tmp_name'],
|
||||
$folder . $file_uid
|
||||
);
|
||||
$file_name = $_FILES[$upload_name]['name'];
|
||||
$file_size = humanReadableByteFormat($_FILES[$upload_name]['size']);
|
||||
$file_size_raw = $_FILES[$upload_name]['size'];
|
||||
// correct the image rotation
|
||||
// $this->correctImageOrientation(BASE.TMP.$file_uid);
|
||||
// make a copy to layout/cache/images for file url
|
||||
// as a thumbnail in defined size
|
||||
// $file_url = $this->form_base_path
|
||||
// . $this->createThumbnailSimple(BASE.TMP.$file_uid, THUMB_WIDTH, THUMB_HEIGHT);
|
||||
// write back data for frontend processing
|
||||
$ajax_data = [
|
||||
'msg' => $file_upload_message,
|
||||
'file_uid' => $file_uid,
|
||||
'file_url' => $file_url,
|
||||
'file_name' => $file_name,
|
||||
'file_size' => $file_size,
|
||||
'file_size_raw' => $file_size_raw,
|
||||
'file_type' => $mime_type,
|
||||
];
|
||||
} else {
|
||||
$info_msg = 'File uploaded and check failed';
|
||||
errMsg($status, $info_msg);
|
||||
$ajax_data['msg'][] = $info_msg;
|
||||
}
|
||||
} else {
|
||||
$info_msg = isset($_FILES[$upload_name]) ?
|
||||
'File upload filed: ' . fileUploadErrorMessage($_FILES[$upload_name]['error']) :
|
||||
'General file upload error';
|
||||
errMsg($status, $info_msg);
|
||||
$ajax_data = [
|
||||
'msg' => [
|
||||
$info_msg
|
||||
]
|
||||
];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$error = true;
|
||||
errMsg($status, 'Abnormal action');
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$error = true;
|
||||
errMsg($status, 'No action set');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'status' => $status,
|
||||
'msg' => $error_string,
|
||||
'action' => $_POST['action'] ?? null,
|
||||
'content' => $ajax_data
|
||||
];
|
||||
|
||||
// print the JSON data out to the browsers
|
||||
$output = json_encode($data);
|
||||
print $output;
|
||||
|
||||
// __END__
|
||||
1376
test/edit.jq.js
Normal file
1376
test/edit.jq.js
Normal file
File diff suppressed because it is too large
Load Diff
1
test/edit.js
Symbolic link
1
test/edit.js
Symbolic link
@@ -0,0 +1 @@
|
||||
edit.jq.js
|
||||
108
test/index.html
Normal file
108
test/index.html
Normal file
@@ -0,0 +1,108 @@
|
||||
<!doctype html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>AJAX File upload TEST</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<script src="jquery.min.js" type="text/javascript"></script>
|
||||
<script defer src="edit.js" type="text/javascript"></script>
|
||||
<script defer src="other.js" type="text/javascript"></script>
|
||||
<script defer src="../src/ajaxFileUploadSimple.js" type="text/javascript"></script>
|
||||
<link rel=stylesheet type="text/css" href="other.css">
|
||||
</head>
|
||||
<body>
|
||||
<form method="post" name="formdata" id="formdata" enctype="multipart/form-data" action="backend.php">
|
||||
<div id="alerts-div" class="hide"></div>
|
||||
<div id="container">
|
||||
<!-- uploader block: START -->
|
||||
<div id="first_upload-input">
|
||||
<!--
|
||||
The following element must be present
|
||||
<name>-input: MASTER DIV, holds all below
|
||||
<name>-file-div: upload button
|
||||
maks-<name>: nested in above div, hold -info and -file (inside <name>-file-div)
|
||||
<name>-info: Button name + layout block (inside <name>-file-div > mask-<name>)
|
||||
<name>-file: file upload input (inside <name>-file-div > mask-<name>)
|
||||
<name>-submit-div: submit input element for submit call
|
||||
<name>-submit: submit button (inside <name>-submit-div)
|
||||
<name>-upload-status: div field for progress of upload/info
|
||||
<name>-clear-div: reset/clear the upload-status list
|
||||
<name>-clear: button for clear upload queue (inside <name>-clear-div)
|
||||
-->
|
||||
<!-- main upload file pointer -->
|
||||
<div id="first_upload-file-div" class="file-upload mg-30">
|
||||
<!-- upload label must be present -->
|
||||
<label id="mask-first_upload" for="first_upload-file">
|
||||
<div id="first_upload-info">ファイル選ぶ</div>
|
||||
<!-- main file control container -->
|
||||
<input id="first_upload-file" name="first_upload-file" type="file" class="file-upload-input" style="display:none;" multiple>
|
||||
</label>
|
||||
</div>
|
||||
<div id="first_upload-submit-div" class="mg-30" style="display:none;">
|
||||
<!-- the actual upload, must have id set -->
|
||||
<button type="submit" value="アップロード" id="first_upload-submit" name="first_upload-submit" class="submitBtn">アップロード</button>
|
||||
</div>
|
||||
<!-- all status blocks go here -->
|
||||
<div id="first_upload-upload-status" style="display:none;"></div>
|
||||
<!-- clear entries from the upload-status list -->
|
||||
<div id="first_upload-clear-div" class="mg-10" style="display:none;">
|
||||
<button type="button" value="クリア" id="first_upload-clear" name="first_upload-clear">クリア</button>
|
||||
</div>
|
||||
<div id="first_upload-abort-all-div" class="mg-10" style="display:none;">
|
||||
<button type="button" value="クリア" id="first_upload-abort-all" name="first_upload-abort-all">全部キャンセル</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- uploader block: END -->
|
||||
|
||||
<!-- OTHER UPLOAD BLOCK single -->
|
||||
<div id="second_upload-input">
|
||||
<div id="second_upload-file-div" class="mg-30">
|
||||
<label id="mask-second_upload" for="second_upload-file">
|
||||
<div id="second_upload-info" style="border: 2px solid red; font-size: 20px; width: 10%; margin: 10px; padding: 10px; text-align: center;">Choose A</div>
|
||||
<input id="second_upload-file" name="second_upload-file" type="file" style="display:none;" multiple>
|
||||
</label>
|
||||
</div>
|
||||
<div id="second_upload-submit-div" class="mg-30" style="display:none;">
|
||||
<button type="submit" value="Upload A" id="second_upload-submit" name="second_upload-submit" class="">Upload A</button>
|
||||
</div>
|
||||
<div id="second_upload-upload-status" style="display:none;"></div>
|
||||
<div id="second_upload-clear-div" class="mg-10" style="display:none;">
|
||||
<button type="button" value="Clear A" id="second_upload-clear" name="second_upload-clear">Clear A</button>
|
||||
</div>
|
||||
<div id="second_upload-abort-all-div" class="mg-10" style="display:none;">
|
||||
<button type="button" value="クリア" id="second_upload-abort-all" name="second_upload-abort-all">Abort all</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- OTHER UPLOAD BLOCK unlimited -->
|
||||
<div id="third_upload-input">
|
||||
<div id="third_upload-file-div" class="mg-30">
|
||||
<label id="mask-third_upload" for="third_upload-file">
|
||||
<div id="third_upload-info" style="border: 2px solid red; font-size: 20px; width: 10%; margin: 10px; padding: 10px; text-align: center;">Choose B</div>
|
||||
<input id="third_upload-file" name="third_upload-file" type="file" style="display:none;" multiple>
|
||||
</label>
|
||||
</div>
|
||||
<div id="third_upload-submit-div" class="mg-30" style="display:none;">
|
||||
<button type="submit" value="Upload B" id="third_upload-submit" name="third_upload-submit" class="">Upload B</button>
|
||||
</div>
|
||||
<div id="third_upload-upload-status" style="display:none;"></div>
|
||||
<div id="third_upload-clear-div" class="mg-10" style="display:none;">
|
||||
<button type="button" value="Clear B" id="third_upload-clear" name="third_upload-clear">Clear B</button>
|
||||
</div>
|
||||
<div id="third_upload-abort-all-div" class="mg-10" style="display:none;">
|
||||
<button type="button" value="クリア" id="third_upload-abort-all" name="third_upload-abort-all">Abort all</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- previously uploaded list -->
|
||||
<div id="uploaded" class="uploaded">
|
||||
<div class="title">Previous uploaded</div>
|
||||
<div id="file-info"></div>
|
||||
<div id="file-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="reference-id" id="reference-id" value="">
|
||||
<div id="indicator" class="hide"></div>
|
||||
<div id="overlayBox" class="overlayBoxElement hide"></div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
2
test/jquery-3.6.0.min.js
vendored
Normal file
2
test/jquery-3.6.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
test/jquery.min.js
vendored
Symbolic link
1
test/jquery.min.js
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
jquery-3.6.0.min.js
|
||||
2
test/log/.gitignore
vendored
Normal file
2
test/log/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
66
test/multiple_files_test.html
Executable file
66
test/multiple_files_test.html
Executable file
@@ -0,0 +1,66 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>AJAX File multiple upload TEST</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<script src="jquery.min.js" type="text/javascript"></script>
|
||||
<script defer src="edit.js" type="text/javascript"></script>
|
||||
<!-- <script defer src="other.js" type="text/javascript"></script> -->
|
||||
<!-- <script defer src="../src/ajaxFileUploadSimple.js" type="text/javascript"></script> -->
|
||||
<!-- <link rel=stylesheet type="text/css" href="other.css"> -->
|
||||
<script type="text/Javascript">
|
||||
$(document).ready(function () {
|
||||
var fileInput = document.getElementById('file-input');
|
||||
var fileCatcher = document.getElementById('file-catcher');
|
||||
var fileListDisplay = document.getElementById('file-list-display');
|
||||
var fileList = [];
|
||||
var renderFileList, sendFile;
|
||||
|
||||
fileInput.addEventListener('change', function (ev) {
|
||||
fileList = [];
|
||||
console.log('Selected files: %s', fileInput.files.length);
|
||||
for (var i = 0; i < fileInput.files.length; i ++) {
|
||||
console.log('Push file: %s with %o', i, fileInput.files[i]);
|
||||
fileList.push(fileInput.files[i]);
|
||||
}
|
||||
renderFileList();
|
||||
});
|
||||
|
||||
|
||||
fileCatcher.addEventListener('submit', function (ev) {
|
||||
ev.preventDefault();
|
||||
fileList.forEach(function (file) {
|
||||
console.log('Send file: %o', file);
|
||||
sendFile(file);
|
||||
});
|
||||
});
|
||||
|
||||
renderFileList = function () {
|
||||
fileListDisplay.innerHTML = '';
|
||||
fileList.forEach(function (file, index) {
|
||||
var fileDisplayEl = document.createElement('p');
|
||||
fileDisplayEl.innerHTML = (index + 1) + ': ' + file.name;
|
||||
fileListDisplay.appendChild(fileDisplayEl);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
sendFile = function (file) {
|
||||
var formData = new FormData();
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
formData.set('file', file);
|
||||
request.open('POST', 'backend.php');
|
||||
request.send(formData);
|
||||
};
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form name="file-catcher" id="file-catcher">
|
||||
<input id="file-input" type="file" multiple/>
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
<div id='file-list-display'></div>
|
||||
</body>
|
||||
</html>
|
||||
140
test/other.css
Normal file
140
test/other.css
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
CSS Other
|
||||
*/
|
||||
|
||||
/* the overlay background black cover */
|
||||
.overlayBoxElement {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
height: 100%;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 98;
|
||||
}
|
||||
|
||||
/* the progress guruguru */
|
||||
.progress {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border: 20px solid rgba(255, 255, 255, 0.25);
|
||||
border-left-color: rgba(3, 155, 229 ,1);
|
||||
border-top-color: rgba(3, 155, 229 ,1);
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
animation: rotate 600ms infinite linear;
|
||||
/* align */
|
||||
left: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
z-index: 120;
|
||||
}
|
||||
/* Animation for above progress */
|
||||
@keyframes rotate {
|
||||
to {
|
||||
transform: rotate(1turn)
|
||||
}
|
||||
}
|
||||
|
||||
.tac { text-align: center; }
|
||||
.mg-30 { margin: 30px; }
|
||||
.mg-5 { margin: 5px; }
|
||||
.flx-ss { display: flex; }
|
||||
.hide { display: none; }
|
||||
.uploaded { margin-top: 20px; }
|
||||
.title { font-size: 1.5em; font-weight: bold; margin-bottom: 10px; }
|
||||
|
||||
.file-upload label div {
|
||||
text-align: center;
|
||||
color: #e60012;
|
||||
background: #eee;
|
||||
width: 240px;
|
||||
height: 60px;
|
||||
margin: 10px 5px 5px;
|
||||
line-height: 60px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 3px 2px rgba(0,0,0,.2);
|
||||
font-size: 137.5%;
|
||||
font-weight: 600;
|
||||
transition: .7s;
|
||||
cursor: pointer;
|
||||
}
|
||||
.file-upload label div:hover {
|
||||
opacity: .7;
|
||||
}
|
||||
/* .file-upload-input {
|
||||
|
||||
} */
|
||||
.submitBtn {
|
||||
text-align: center;
|
||||
color: #e60012;
|
||||
background: #eee;
|
||||
width: 240px;
|
||||
height: 60px;
|
||||
margin: 10px 5px 5px;
|
||||
/* line-height: 60px; */
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 3px 2px rgba(0,0,0,.2);
|
||||
font-size: 137.5%;
|
||||
font-weight: 600;
|
||||
transition: .7s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.SubError {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* all error messages */
|
||||
.error-warn {
|
||||
text-align: center;
|
||||
color: orange;
|
||||
font-size: 1.1em;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
.error-error {
|
||||
text-align: center;
|
||||
color: red;
|
||||
font-size: 1.1em;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
.error-abort {
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
background-color: #ff0000;
|
||||
font-weight: bold;
|
||||
font-size: 1.4em;
|
||||
line-height: 1.5em;
|
||||
padding: 2px;
|
||||
margin: 2px 0 2px 0;
|
||||
}
|
||||
.error-crash {
|
||||
text-align: center;
|
||||
color: #fbffe0;
|
||||
background-color: #a00000;
|
||||
font-weight: bold;
|
||||
font-size: 1.6em;
|
||||
line-height: 1.7em;
|
||||
border: 2px solid #000000;
|
||||
padding: 2px;
|
||||
margin: 2px 0 2px 0;
|
||||
}
|
||||
.error-info, .error-ok {
|
||||
text-align: center;
|
||||
color: green;
|
||||
font-size: 1.1em;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
/* special debug */
|
||||
.error-debug {
|
||||
text-align: left;
|
||||
color: gray;
|
||||
font-size: 0.9em;
|
||||
line-height: 1.0em;
|
||||
}
|
||||
|
||||
.afus-uploaded {
|
||||
margin-top: 10px;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
382
test/other.js
Normal file
382
test/other.js
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* JAVASCRIPT other
|
||||
*/
|
||||
|
||||
/* jshint esversion: 6 */
|
||||
|
||||
/* global initAjaxUploader, keyInObject, errorCatch, showActionIndicator, hideActionIndicator, exists, phfo, aelx, cel */
|
||||
|
||||
/**
|
||||
* clear the alert div and hide it
|
||||
*/
|
||||
function clearAlerts() {
|
||||
$('#alerts-div').html('').hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* prints a single message line
|
||||
* @param {String} msg message text
|
||||
* @param {String} level level as style sheet name for highlight
|
||||
*/
|
||||
function printMsgStr(msg, level) {
|
||||
printMsg([{ level: level, str: msg }]);
|
||||
}
|
||||
|
||||
/**
|
||||
* prints master error message in case of master error
|
||||
* @param {Object} msg messages as hash object
|
||||
*/
|
||||
function printMsg(msg) {
|
||||
var content = [];
|
||||
for (const t of msg) {
|
||||
// console.log('v: %s, t: %o', v, t);
|
||||
if (keyInObject('code', t) && t.code != null && t.code.length > 0) {
|
||||
t.str = '[' + t.code + '] ' + t.str;
|
||||
}
|
||||
content.push(phfo(cel('div', '', t.str, ['error-' + t.level])));
|
||||
}
|
||||
$('#alerts-div')
|
||||
.html(content.join(''))
|
||||
.show();
|
||||
// calcHeightTopHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapper for ajax calls
|
||||
* This will do a beforeSend call
|
||||
* Success generall call (before .done)
|
||||
* error call for general error catch (can be outside extended with .fail)
|
||||
* complete call to hide the action indicator
|
||||
* note: if pre-function is small we might want to put indicator call in this function
|
||||
* @param {String} call_id Caller id for debug and action indicator debug
|
||||
* @param {Object} queryString Query string to pass on, default empty
|
||||
* @param {Object} control Control for action indicator and others
|
||||
* no_action_indicator: true/false/empty, if true do not use action indicator
|
||||
* @param {String} url Target url, defaults to generalBackend.php
|
||||
* @return {jqXHR} JQuery XJR Object for .done, .fail, etc connection calls
|
||||
*/
|
||||
function ajaxWrapper(call_id, queryString = {}, control = {}, url = 'backend.php') {
|
||||
var no_action_indicator = false;
|
||||
if (keyInObject('no_action_indicator', control)) {
|
||||
no_action_indicator = control.no_action_indicator ? true : false;
|
||||
}
|
||||
// if inidicator not visible, show before
|
||||
if (!no_action_indicator) {
|
||||
showActionIndicator(call_id);
|
||||
}
|
||||
// general ajax wrapper
|
||||
// AJAX call
|
||||
return $.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
data: queryString,
|
||||
// genera; before Sending
|
||||
beforeSend: function () {
|
||||
console.log('MAIN RUN: ' + call_id);
|
||||
},
|
||||
success: function (data, status, xhr) {
|
||||
// additional success call
|
||||
console.log('[' + call_id + '] Return with [%s] as status: %s, xhr: %s, action: %s', status, data.status, xhr.status, data.action);
|
||||
},
|
||||
// general error
|
||||
error: function (xhr) {
|
||||
console.log('[' + call_id + '] An error occured: %s %s', xhr.status, xhr.statusText);
|
||||
// critical error
|
||||
printMsgStr(call_id + ' Error', 'crash');
|
||||
},
|
||||
complete: function () {
|
||||
console.log('[' + call_id + '] Complete');
|
||||
if (!no_action_indicator) {
|
||||
hideActionIndicator(call_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* FILE CHANGE:
|
||||
* helper call for ajax file upload on file selected
|
||||
* @param {Number} file_pos Position in upload queue
|
||||
* @param {String} target_file The file upload target prefix id
|
||||
*/
|
||||
function fileChangeFunction(target_file, file_pos, target_router)
|
||||
{
|
||||
console.log('{FILE} CHANGE [%s/%s] FUNCTION CALL [%s]', target_file, file_pos, target_router);
|
||||
clearAlerts();
|
||||
// console.log('Upload Status: %s', $('#' + target_file + '-upload-status').outerHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* [fileChangeFunctionAll description]
|
||||
* @param {String} target_file [description]
|
||||
* @param {String} target_router [description]
|
||||
*/
|
||||
function fileChangeFunctionAll(target_file, target_router)
|
||||
{
|
||||
console.log('{FILE} CHANGE ALL [%s] FUNCTION CALL [%s]', target_file, target_router);
|
||||
clearAlerts();
|
||||
// console.log('Upload Status: %s', $('#' + target_file + '-upload-status').outerHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* [fileRemoveFunction description]
|
||||
* @param {string} target_file [description]
|
||||
* @param {Number} file_pos [description]
|
||||
* @param {String} target_router [description]
|
||||
*c
|
||||
*/
|
||||
function fileRemoveFunction(target_file, file_pos, target_router)
|
||||
{
|
||||
console.log('{FILE} REMOVE [%s/%s] FUNCTION CALL [%s]', target_file, file_pos, target_router);
|
||||
// console.log('Upload Status: %s', $('#' + target_file + '-upload-status').outerHeight());
|
||||
// clearAlerts();
|
||||
}
|
||||
|
||||
/**
|
||||
* [fileClearFunction description]
|
||||
* @param {String} target_file [description]
|
||||
* @param {String} target_router [description]
|
||||
*/
|
||||
function fileClearFunction(target_file, target_router)
|
||||
{
|
||||
console.log('{FILE} CLEAR [%s] FUNCTION CALL [%s]', target_file, target_router);
|
||||
// console.log('Upload Status: %s', $('#' + target_file + '-upload-status').outerHeight());
|
||||
// clearAlerts();
|
||||
}
|
||||
|
||||
/**
|
||||
* [fileAppendBeforeUploadFunctionAllFunction description]
|
||||
* @param {String} target_file [description]
|
||||
* @param {String} target_router [description]
|
||||
* @return {Object} [description]
|
||||
*/
|
||||
function fileAppendBeforeUploadFunctionAllFunction(target_file, target_router)
|
||||
{
|
||||
console.log('{FILE} BEFORE UPLOAD ALL [%s] FUNCTION CALL [%s]', target_file, target_router);
|
||||
return {
|
||||
'primary_key': $('#reference-id').val(),
|
||||
'same-entry': 'A',
|
||||
'target-files': target_file,
|
||||
'target-router': target_router
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* FILE BEFORE UPLOAD:
|
||||
* attach additional data to be sent to the server
|
||||
* This is called before the data is submitted to the server
|
||||
* @param {String} target_file The file upload target prefix id
|
||||
* @param {Number} file_pos Position in upload queue
|
||||
* @param {String} target_router
|
||||
* @return {Object} key -> value object to be attached to the form
|
||||
*/
|
||||
function fileAppendBeforeUploadFunction(target_file, file_pos, target_router)
|
||||
{
|
||||
console.log('{FILE} BEFORE UPLOAD [%s/%s] FUNCTION CALL [%s]', target_file, file_pos, target_router);
|
||||
return {
|
||||
'file_data_count': $('#file-list').children().length,
|
||||
'same-entry': 'B',
|
||||
'target-files': target_file,
|
||||
'file-pos': file_pos,
|
||||
'target-router': target_router
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* FILE ULOAD FINISHED:
|
||||
* helper call for ajax file upload on upload completed
|
||||
* set the uploaded file list (hidden & visible), shows import button,
|
||||
* adjusts hight of action box
|
||||
* @param {String} target_file The file upload target prefix id
|
||||
* @param {Object} control_data The data returned from the ajax call after upload
|
||||
*/
|
||||
function fileUploadedFunction(target_file, file_pos, target_router, control_data)
|
||||
{
|
||||
console.log('{FILE} UPLAODED [%s/%s] FUNCTION CALL [%s]: %o', target_file, file_pos, target_router, control_data);
|
||||
var file_id = target_file;
|
||||
var file_entry_exists = false;
|
||||
// add new uploaded file entry to the push list
|
||||
// first find if there is an entry for this file yet (-file-name)
|
||||
try {
|
||||
console.log('Uploaded file UID: %s', $('#' + file_id + '-uid-' + file_pos).val());
|
||||
if (exists(file_id + '-uid-' + file_pos) && $('#' + file_id + '-uid-' + file_pos).val()) {
|
||||
// hide file info first
|
||||
$('#file-info').html('').hide();
|
||||
// add new uplaoded files
|
||||
$('#file-list').append(phfo(
|
||||
aelx(cel('div', '', '', ['flx-ss']),
|
||||
cel('div', '', control_data.file_name, ['mg-5']),
|
||||
cel('div', '', '(NOW)', ['mg-5']),
|
||||
cel('div', '', control_data.file_size, ['mg-5']),
|
||||
cel('input', file_id + '-uploaded-' + file_pos, '', [], {type: 'hidden', value: control_data.file_uid})
|
||||
)
|
||||
));
|
||||
// DOUBLE entry checker used in FormControl control file upload
|
||||
// console.log('MAP: %o', $('#file-list :input'));
|
||||
file_entry_exists = Object.values($('#file-list :input').map(function() {
|
||||
// console.log('Matching: %s - %s', control_data.file_uid, $(this).val());
|
||||
return control_data.file_uid == $(this).val() ? true : false;
|
||||
})).find(value => value === true);
|
||||
console.log('Matched: %s', file_entry_exists);
|
||||
if (!file_entry_exists) {
|
||||
// add hidden and visible elment
|
||||
// addControlFileElement(file_id, $('#' + file_id + '-file_name').val(), control_data.other_data.status_text);
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
errorCatch(err);
|
||||
}
|
||||
// chain action test
|
||||
var call_id = 'chainAction';
|
||||
var queryString = {
|
||||
action: call_id,
|
||||
chain: control_data.file_uid
|
||||
};
|
||||
ajaxWrapper(call_id, queryString).done(function (data) {
|
||||
console.log('Data: %o', data);
|
||||
try {
|
||||
if (data.status == 'error') {
|
||||
//
|
||||
} else {
|
||||
// list files
|
||||
if (data.status == 'warn') {
|
||||
//
|
||||
} else {
|
||||
//
|
||||
}
|
||||
}
|
||||
// top message
|
||||
printMsg(data.msg);
|
||||
} catch (err) {
|
||||
errorCatch(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* [fileUploadedAllFunction description]
|
||||
* @param {String} target_file [description]
|
||||
* @param {Number} target_router [description]
|
||||
* @param {Boolean} all_success If true all files where accepted by the servers
|
||||
*/
|
||||
function fileUploadedAllFunction(target_file, target_router, all_success)
|
||||
{
|
||||
console.log('{FILE} UPLAODED ALL [%s] FUNCTION CALL [%s]: %o', target_file, target_router, all_success);
|
||||
}
|
||||
|
||||
/**
|
||||
* [fileUploadErrorFunction description]
|
||||
* @param {String} target_file [description]
|
||||
* @param {Number} file_pos [description]
|
||||
* @param {String} target_router [description]
|
||||
* @param {Object} control_data [description]
|
||||
*/
|
||||
function fileUploadErrorFunction(target_file, file_pos, target_router, control_data)
|
||||
{
|
||||
console.log('{FILE} UPLOAD ERROR [%s/%s] FUNCTION CALL [%s]: %o', target_file, file_pos, target_router, control_data);
|
||||
// eg print special error data from control
|
||||
}
|
||||
|
||||
// ** init here **/file-list
|
||||
$(document).ready(function () {
|
||||
// run and fill uploaded
|
||||
var call_id = 'fileList';
|
||||
var queryString = {
|
||||
action: call_id
|
||||
};
|
||||
ajaxWrapper(call_id, queryString).done(function (data) {
|
||||
console.log('Data: %o', data);
|
||||
try {
|
||||
if (data.status == 'error') {
|
||||
//
|
||||
} else {
|
||||
$('#reference-id').val(data.content.reference_id);
|
||||
// list files
|
||||
if (data.status == 'warn') {
|
||||
$('#file-info')
|
||||
.addClass('error-warn')
|
||||
.html(data.content.info);
|
||||
} else {
|
||||
$('#file-info').html('');
|
||||
for (const files of data.content.file_list) {
|
||||
// console.log('F: %o', files);
|
||||
$('#file-list').append(phfo(
|
||||
aelx(cel('div', '', '', ['flx-ss']),
|
||||
cel('div', '', files.name, ['mg-5']),
|
||||
cel('div', '', files.create_date, ['mg-5']),
|
||||
cel('div', '', files.size, ['mg-5']),
|
||||
cel('input', 'uploaded-' + files.name, '', [], {type: 'hidden', value: files.name})
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
// top message
|
||||
printMsg(data.msg);
|
||||
} catch (err) {
|
||||
errorCatch(err);
|
||||
}
|
||||
});
|
||||
|
||||
// check that html elements needed are there
|
||||
// fill the file upload part
|
||||
initAjaxUploader({
|
||||
target_file: 'first_upload',
|
||||
target_form: 'formdata',
|
||||
max_files: 5,
|
||||
target_router: 'fileUpload',
|
||||
target_action: '',
|
||||
form_parameters: {'parameter_a': 'Value 123'},
|
||||
auto_submit: false,
|
||||
fileChange: fileChangeFunction,
|
||||
fileChangeAll: fileChangeFunctionAll,
|
||||
fileRemove: fileRemoveFunction,
|
||||
fileClear: fileClearFunction,
|
||||
fileBeforeUploadAll: fileAppendBeforeUploadFunctionAllFunction,
|
||||
fileBeforeUpload: fileAppendBeforeUploadFunction,
|
||||
fileUploaded: fileUploadedFunction,
|
||||
fileUploadedAll: fileUploadedAllFunction,
|
||||
fileUploadError: fileUploadErrorFunction
|
||||
});
|
||||
// for second test
|
||||
initAjaxUploader({
|
||||
target_file: 'second_upload',
|
||||
target_form: 'formdata',
|
||||
max_files: 1,
|
||||
max_file_size: 500000, // ~500KB
|
||||
// allowed_extensions: ['txt', 'csv'],
|
||||
allowed_file_types: ['text/plain', 'text/csv'],
|
||||
target_router: 'fileUpload',
|
||||
target_action: '',
|
||||
form_parameters: {'parameter_b': 'Value 456'},
|
||||
auto_submit: false,
|
||||
fileChange: fileChangeFunction,
|
||||
fileChangeAll: fileChangeFunctionAll,
|
||||
fileRemove: fileRemoveFunction,
|
||||
fileClear: fileClearFunction,
|
||||
fileBeforeUploadAll: fileAppendBeforeUploadFunctionAllFunction,
|
||||
fileBeforeUpload: fileAppendBeforeUploadFunction,
|
||||
fileUploaded: fileUploadedFunction,
|
||||
fileUploadedAll: fileUploadedAllFunction,
|
||||
fileUploadError: fileUploadErrorFunction
|
||||
});
|
||||
// for third test
|
||||
initAjaxUploader({
|
||||
target_file: 'third_upload',
|
||||
target_form: 'formdata',
|
||||
max_files: 0,
|
||||
target_router: 'fileUpload',
|
||||
target_action: '',
|
||||
form_parameters: {'parameter_c': 'Value 789'},
|
||||
auto_submit: false,
|
||||
fileChange: fileChangeFunction,
|
||||
fileChangeAll: fileChangeFunctionAll,
|
||||
fileRemove: fileRemoveFunction,
|
||||
fileClear: fileClearFunction,
|
||||
fileBeforeUploadAll: fileAppendBeforeUploadFunctionAllFunction,
|
||||
fileBeforeUpload: fileAppendBeforeUploadFunction,
|
||||
fileUploaded: fileUploadedFunction,
|
||||
fileUploadedAll: fileUploadedAllFunction,
|
||||
fileUploadError: fileUploadErrorFunction
|
||||
});
|
||||
});
|
||||
2
test/uploaded/.gitignore
vendored
Normal file
2
test/uploaded/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Reference in New Issue
Block a user