Actualización
This commit is contained in:
53
main/inc/lib/javascript/bigupload/README.md
Normal file
53
main/inc/lib/javascript/bigupload/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
BigUpload
|
||||
|
||||
version 1.2
|
||||
Created by: Sean Thielen <sean@p27.us>
|
||||
[BigUpload: Uploading really big files in the browser](http://p27.us/2013/03/bigupload-uploading-really-big-files-in-the-browser/)
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
BigUpload is a tool for handling large file uploads (tested up to 2GB) through the browser.
|
||||
|
||||

|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
It uses the HTML5 FileReader library to split large files into manageable chunks,
|
||||
and then sends these chunks to the server one at a time using an XmlHttpRequest.
|
||||
|
||||
The php script then pieces these chunks together into one large file.
|
||||
|
||||
Because the chunks are all the same size, it is easy to calculate an accurate progress bar
|
||||
and a fairly accurate time remaining variable.
|
||||
|
||||
This tool is capable of handling file uploads of up to 2GB in size, without the need to tweak
|
||||
the max_upload and timeout variables on your httpd.
|
||||
|
||||
This tool only works on Chrome and Firefox, but falls back to a normal file upload form on other browsers.
|
||||
|
||||
If you want to deploy this as-is, the variables you need to worry about are in the top of
|
||||
* js/bigUpload.js
|
||||
* inc/bigUpload.php
|
||||
|
||||
And you need to be sure to make /BigUpload/files and /BigUpload/files/tmp writeable
|
||||
|
||||
|
||||
Please feel free to contribute and use this in your projects!
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
v 1.2
|
||||
* Cleaned up the code quite a lot
|
||||
* Added pause/resume functionality
|
||||
* Added fallback for unsupported browsers
|
||||
|
||||
v 1.0.1
|
||||
* Added time remaining calculator
|
||||
* Response from php script is now a json object, allowing for error processing
|
||||
* Minor script changes and bugfixes
|
||||
* Better comments
|
||||
|
||||
v 1.0.0
|
||||
* Initial version
|
||||
BIN
main/inc/lib/javascript/bigupload/css/import_scorm.png
Normal file
BIN
main/inc/lib/javascript/bigupload/css/import_scorm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
BIN
main/inc/lib/javascript/bigupload/css/load745.gif
Normal file
BIN
main/inc/lib/javascript/bigupload/css/load745.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
299
main/inc/lib/javascript/bigupload/inc/bigUpload.php
Normal file
299
main/inc/lib/javascript/bigupload/inc/bigUpload.php
Normal file
@@ -0,0 +1,299 @@
|
||||
<?php
|
||||
|
||||
require_once '../../../../global.inc.php';
|
||||
require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
|
||||
|
||||
class BigUploadResponse
|
||||
{
|
||||
/**
|
||||
* Max allowed filesize. This is for unsupported browsers and
|
||||
* as an additional security check in case someone bypasses the js filesize check.
|
||||
*/
|
||||
private $maxSize;
|
||||
|
||||
/**
|
||||
* Temporary directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $tempDirectory;
|
||||
|
||||
/**
|
||||
* Name of the temporary file. Used as a reference to make sure chunks get written to the right file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $tempName;
|
||||
|
||||
/**
|
||||
* Constructor function, sets the temporary directory and main directory.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$tempDirectory = api_get_path(SYS_ARCHIVE_PATH);
|
||||
$this->setTempDirectory($tempDirectory);
|
||||
$this->maxSize = getIniMaxFileSizeInBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a random file name for the file to use as it's being uploaded.
|
||||
*
|
||||
* @param string $value Temporary filename
|
||||
*/
|
||||
public function setTempName($value = null)
|
||||
{
|
||||
if ($value) {
|
||||
$this->tempName = $value;
|
||||
} else {
|
||||
if ('learnpath' === $_REQUEST['origin'] && !empty($_REQUEST['name'])) {
|
||||
$this->tempName = disable_dangerous_file(
|
||||
api_replace_dangerous_char($_REQUEST['name'])
|
||||
);
|
||||
} else {
|
||||
$this->tempName = mt_rand().'.tmp';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the temporary file.
|
||||
*
|
||||
* @return string Temporary filename
|
||||
*/
|
||||
public function getTempName()
|
||||
{
|
||||
return $this->tempName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the temporary directory.
|
||||
*
|
||||
* @param string $value Temporary directory
|
||||
*/
|
||||
public function setTempDirectory($value)
|
||||
{
|
||||
$this->tempDirectory = $value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the temporary directory.
|
||||
*
|
||||
* @return string Temporary directory
|
||||
*/
|
||||
public function getTempDirectory()
|
||||
{
|
||||
return $this->tempDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to upload the individual file chunks.
|
||||
*
|
||||
* @return string JSON object with result of upload
|
||||
*/
|
||||
public function uploadFile()
|
||||
{
|
||||
//Make sure the total file we're writing to hasn't surpassed the file size limit
|
||||
if (file_exists($this->getTempDirectory().$this->getTempName())) {
|
||||
if (filesize($this->getTempDirectory().$this->getTempName()) > $this->maxSize) {
|
||||
$this->abortUpload();
|
||||
|
||||
return json_encode([
|
||||
'errorStatus' => 1,
|
||||
'errorText' => get_lang('UplFileTooBig'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
//Open the raw POST data from php://input
|
||||
$fileData = file_get_contents('php://input');
|
||||
|
||||
//Write the actual chunk to the larger file
|
||||
$handle = fopen($this->getTempDirectory().$this->getTempName(), 'a');
|
||||
|
||||
fwrite($handle, $fileData);
|
||||
fclose($handle);
|
||||
|
||||
return json_encode([
|
||||
'key' => $this->getTempName(),
|
||||
'errorStatus' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for cancelling uploads while they're in-progress; deletes the temp file.
|
||||
*
|
||||
* @return string JSON object with result of deletion
|
||||
*/
|
||||
public function abortUpload()
|
||||
{
|
||||
if (unlink($this->getTempDirectory().$this->getTempName())) {
|
||||
return json_encode(['errorStatus' => 0]);
|
||||
} else {
|
||||
return json_encode([
|
||||
'errorStatus' => 1,
|
||||
'errorText' => get_lang('UnableToDeleteTempFile'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to rename and move the finished file.
|
||||
*
|
||||
* @return string JSON object with result of rename
|
||||
*/
|
||||
public function finishUpload()
|
||||
{
|
||||
$tempName = $this->getTempName();
|
||||
|
||||
$sessionBigUpload = ChamiloSession::read('bigupload', []);
|
||||
|
||||
if (!isset($sessionBigUpload[$tempName])) {
|
||||
return json_encode(
|
||||
[
|
||||
'errorStatus' => 1,
|
||||
'errorText' => get_lang('UnableToDeleteTempFile'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/** @var string $finalName Name to rename the finished upload to */
|
||||
$finalName = $sessionBigUpload[$tempName];
|
||||
|
||||
$origin = $_POST['origin'];
|
||||
if ($origin == 'document') {
|
||||
$tmpFile = $this->getTempDirectory().$this->getTempName();
|
||||
chmod($tmpFile, '0777');
|
||||
$file = [
|
||||
'name' => $finalName,
|
||||
'type' => $_POST['type'],
|
||||
'tmp_name' => $tmpFile,
|
||||
'error' => 0,
|
||||
'size' => $_POST['size'],
|
||||
'copy_file' => true,
|
||||
];
|
||||
$files = ['file' => $file];
|
||||
$unzip = isset($_POST['unzip']) ? $_POST['unzip'] : null;
|
||||
$index = isset($_POST['index_document']) ? $_POST['index_document'] : null;
|
||||
DocumentManager::upload_document(
|
||||
$files,
|
||||
$_POST['curdirpath'],
|
||||
$_POST['title'],
|
||||
$_POST['comment'],
|
||||
$unzip,
|
||||
$_POST['if_exists'],
|
||||
$index,
|
||||
true
|
||||
);
|
||||
$redirectUrl = api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq();
|
||||
if (!empty($_POST['id'])) {
|
||||
$redirectUrl .= '&'.http_build_query(
|
||||
[
|
||||
'id' => $_POST['id'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return json_encode(['errorStatus' => 0, 'redirect' => $redirectUrl]);
|
||||
} elseif ($origin == 'learnpath') {
|
||||
unset($_REQUEST['origin']);
|
||||
$redirectUrl = api_get_path(WEB_CODE_PATH).'upload/upload.php?'.api_get_cidreq().'&'
|
||||
.http_build_query(
|
||||
[
|
||||
'from' => 'bigUpload',
|
||||
'name' => $this->getTempName(),
|
||||
'use_max_score' => $_POST['use_max_score'] ?? 0,
|
||||
]
|
||||
);
|
||||
|
||||
return json_encode(['errorStatus' => 0, 'redirect' => $redirectUrl]);
|
||||
} elseif ($origin == 'work') {
|
||||
$tmpFile = $this->getTempDirectory().$this->getTempName();
|
||||
chmod($tmpFile, '0777');
|
||||
$workInfo = get_work_data_by_id($_REQUEST['id']);
|
||||
$values = $_REQUEST;
|
||||
$courseInfo = api_get_course_info();
|
||||
$sessionId = api_get_session_id();
|
||||
$groupId = api_get_group_id();
|
||||
$userId = api_get_user_id();
|
||||
$values['contains_file'] = 1;
|
||||
$values['title'] = $finalName;
|
||||
$file = [
|
||||
'name' => $finalName,
|
||||
'type' => $_POST['type'],
|
||||
'tmp_name' => $tmpFile,
|
||||
'error' => 0,
|
||||
'size' => $_POST['size'],
|
||||
'copy_file' => true,
|
||||
];
|
||||
|
||||
// Process work
|
||||
$result = processWorkForm(
|
||||
$workInfo,
|
||||
$values,
|
||||
$courseInfo,
|
||||
$sessionId,
|
||||
$groupId,
|
||||
$userId,
|
||||
$file,
|
||||
api_get_configuration_value('assignment_prevent_duplicate_upload')
|
||||
);
|
||||
$extraParams = '';
|
||||
if (!empty($_SESSION['oLP'])) {
|
||||
$extraParams .= '&origin=learnpath';
|
||||
}
|
||||
$redirectUrl = api_get_path(WEB_CODE_PATH).'work/work.php?'.api_get_cidreq().$extraParams;
|
||||
|
||||
return json_encode(['errorStatus' => 0, 'redirect' => $redirectUrl]);
|
||||
}
|
||||
|
||||
return json_encode(['errorStatus' => 0]);
|
||||
}
|
||||
}
|
||||
|
||||
$sessionBigUpload = ChamiloSession::read('bigupload', []);
|
||||
|
||||
//Instantiate the class
|
||||
$bigUpload = new BigUploadResponse();
|
||||
|
||||
//Set the temporary filename
|
||||
$tempName = null;
|
||||
if (isset($_GET['key'])) {
|
||||
$tempName = $_GET['key'];
|
||||
}
|
||||
if (isset($_POST['key'])) {
|
||||
$tempName = $_POST['key'];
|
||||
}
|
||||
|
||||
if (!empty($tempName)) {
|
||||
$tempName = api_replace_dangerous_char($tempName);
|
||||
$tempName = disable_dangerous_file($tempName);
|
||||
}
|
||||
|
||||
$bigUpload->setTempName($tempName);
|
||||
|
||||
if (isset($_GET['name'])) {
|
||||
$sessionBigUpload[$bigUpload->getTempName()] = disable_dangerous_file(
|
||||
api_replace_dangerous_char($_GET['name'])
|
||||
);
|
||||
ChamiloSession::write('bigupload', $sessionBigUpload);
|
||||
}
|
||||
|
||||
switch ($_GET['action']) {
|
||||
case 'upload':
|
||||
print $bigUpload->uploadFile();
|
||||
break;
|
||||
case 'abort':
|
||||
print $bigUpload->abortUpload();
|
||||
break;
|
||||
case 'finish':
|
||||
print $bigUpload->finishUpload();
|
||||
|
||||
if (isset($sessionBigUpload[$bigUpload->getTempName()])) {
|
||||
unset($sessionBigUpload[$bigUpload->getTempName()]);
|
||||
|
||||
ChamiloSession::write('bigupload', $sessionBigUpload);
|
||||
}
|
||||
break;
|
||||
}
|
||||
347
main/inc/lib/javascript/bigupload/js/bigUpload.js
Normal file
347
main/inc/lib/javascript/bigupload/js/bigUpload.js
Normal file
@@ -0,0 +1,347 @@
|
||||
function bigUpload () {
|
||||
|
||||
//These are the main config variables and should be able to take care of most of the customization
|
||||
this.settings = {
|
||||
//The id of the file input
|
||||
'inputField': 'bigUploadFile',
|
||||
|
||||
//The id of the form with the file upload.
|
||||
//This should be a valid html form (see index.html) so there is a fallback for unsupported browsers
|
||||
'formId': 'bigUploadForm',
|
||||
|
||||
//The id of the progress bar
|
||||
//Width of this element will change based on progress
|
||||
//Content of this element will display a percentage
|
||||
//See bigUpload.progressUpdate() to change this code
|
||||
'progressBarField': 'bigUploadProgressBarFilled',
|
||||
|
||||
//The id of the time remaining field
|
||||
//Content of this element will display the estimated time remaining for the upload
|
||||
//See bigUpload.progressUpdate() to change this code
|
||||
'timeRemainingField': 'bigUploadTimeRemaining',
|
||||
|
||||
//The id of the text response field
|
||||
//Content of this element will display the response from the server on success or error
|
||||
'responseField': 'bigUploadResponse',
|
||||
|
||||
//The id of the submit button
|
||||
//This is then changed to become the pause/resume button based on the status of the upload
|
||||
'submitButton': 'bigUploadSubmit',
|
||||
|
||||
//Color of the background of the progress bar
|
||||
//This must also be defined in the progressBarField css, but it's used here to reset the color after an error
|
||||
//Default: green
|
||||
'progressBarColor': '#5bb75b',
|
||||
|
||||
//Color of the background of the progress bar when an error is triggered
|
||||
//Default: red
|
||||
'progressBarColorError': '#da4f49',
|
||||
|
||||
//Path to the php script for handling the uploads
|
||||
'scriptPath': 'inc/bigUpload.php',
|
||||
|
||||
//Size of chunks to upload (in bytes)
|
||||
//Default: 1MB
|
||||
'chunkSize': 1000000,
|
||||
|
||||
//Max file size allowed
|
||||
//Default: 2GB
|
||||
'maxFileSize': 2147483648,
|
||||
|
||||
//CidReq
|
||||
'cidReq': '',
|
||||
|
||||
// Message error upload filesize
|
||||
'errMessageFileSize': '',
|
||||
|
||||
};
|
||||
|
||||
//Upload specific variables
|
||||
this.uploadData = {
|
||||
'uploadStarted': false,
|
||||
'file': false,
|
||||
'numberOfChunks': 0,
|
||||
'aborted': false,
|
||||
'paused': false,
|
||||
'pauseChunk': 0,
|
||||
'key': 0,
|
||||
'timeStart': 0,
|
||||
'totalTime': 0
|
||||
};
|
||||
|
||||
parent = this;
|
||||
|
||||
//Quick function for accessing objects
|
||||
this.$ = function(id) {
|
||||
return document.getElementById(id);
|
||||
};
|
||||
|
||||
//Resets all the upload specific data before a new upload
|
||||
this.resetKey = function() {
|
||||
this.uploadData = {
|
||||
'uploadStarted': false,
|
||||
'file': false,
|
||||
'numberOfChunks': 0,
|
||||
'aborted': false,
|
||||
'paused': false,
|
||||
'pauseChunk': 0,
|
||||
'key': 0,
|
||||
'timeStart': 0,
|
||||
'totalTime': 0
|
||||
};
|
||||
};
|
||||
|
||||
//Inital method called
|
||||
//Determines whether to begin/pause/resume an upload based on whether or not one is already in progress
|
||||
this.fire = function() {
|
||||
if(this.uploadData.uploadStarted === true && this.uploadData.paused === false) {
|
||||
this.pauseUpload();
|
||||
}
|
||||
else if(this.uploadData.uploadStarted === true && this.uploadData.paused === true) {
|
||||
this.resumeUpload();
|
||||
}
|
||||
else {
|
||||
this.processFiles();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//Initial upload method
|
||||
//Pulls the size of the file being uploaded and calculated the number of chunks, then calls the recursive upload method
|
||||
this.processFiles = function() {
|
||||
|
||||
//If the user is using an unsupported browser, the form just submits as a regular form
|
||||
if(!Blob.prototype.slice) {
|
||||
this.$(this.settings.formId).submit();
|
||||
return;
|
||||
}
|
||||
|
||||
//Reset the upload-specific variables
|
||||
this.resetKey();
|
||||
this.uploadData.uploadStarted = true;
|
||||
|
||||
//Some HTML tidying
|
||||
//Reset the background color of the progress bar in case it was changed by any earlier errors
|
||||
//Change the Upload button to a Pause button
|
||||
this.$(this.settings.progressBarField).style.backgroundColor = this.settings.progressBarColor;
|
||||
this.$(this.settings.progressBarField).style.width = '0%';
|
||||
this.$(this.settings.progressBarField).textContent = '0%';
|
||||
this.$(this.settings.responseField).textContent = '';
|
||||
this.$(this.settings.submitButton).value = 'Pause';
|
||||
this.$(this.settings.submitButton).disabled = true;
|
||||
|
||||
//Alias the file input object to this.uploadData
|
||||
this.uploadData.file = this.$(this.settings.inputField).files[0];
|
||||
|
||||
//Check the filesize. Obviously this is not very secure, so it has another check in inc/bigUpload.php
|
||||
//But this should be good enough to catch any immediate errors
|
||||
var fileSize = this.uploadData.file.size;
|
||||
if(fileSize > this.settings.maxFileSize) {
|
||||
this.printResponse(this.settings.errMessageFileSize, true);
|
||||
this.$(this.settings.submitButton).disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
//Calculate the total number of file chunks
|
||||
this.uploadData.numberOfChunks = Math.ceil(fileSize / this.settings.chunkSize);
|
||||
|
||||
//Start the upload
|
||||
this.sendFile(0);
|
||||
};
|
||||
|
||||
//Main upload method
|
||||
this.sendFile = function (chunk) {
|
||||
|
||||
//Set the time for the beginning of the upload, used for calculating time remaining
|
||||
this.uploadData.timeStart = new Date().getTime();
|
||||
|
||||
//Check if the upload has been cancelled by the user
|
||||
if(this.uploadData.aborted === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if the upload has been paused by the user
|
||||
if(this.uploadData.paused === true) {
|
||||
this.uploadData.pauseChunk = chunk;
|
||||
this.printResponse('Upload paused.', false);
|
||||
return;
|
||||
}
|
||||
|
||||
//Set the byte to start uploading from and the byte to end uploading at
|
||||
var start = chunk * this.settings.chunkSize;
|
||||
var stop = start + this.settings.chunkSize;
|
||||
|
||||
//Initialize a new FileReader object
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onloadend = function(evt) {
|
||||
|
||||
//Build the AJAX request
|
||||
//
|
||||
//this.uploadData.key is the temporary filename
|
||||
//If the server sees it as 0 it will generate a new filename and pass it back in the JSON object
|
||||
//this.uploadData.key is then populated with the filename to use for subsequent requests
|
||||
//When this method sends a valid filename (i.e. key != 0), the server will just append the data being sent to that file.
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", parent.settings.scriptPath + '?' + parent.settings.cidReq + '&action=upload' + '&key=' + parent.uploadData.key + '&origin=' + parent.settings.origin + (parent.uploadData.key ? '' : '&name=' + parent.uploadData.file.name), true);
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if(xhr.readyState == 4) {
|
||||
var response = JSON.parse(xhr.response);
|
||||
|
||||
//If there's an error, call the error method and break the loop
|
||||
if(response.errorStatus !== 0 || xhr.status != 200) {
|
||||
parent.printResponse(response.errorText, true);
|
||||
return;
|
||||
}
|
||||
|
||||
//If it's the first chunk, set this.uploadData.key to the server response (see above)
|
||||
if(chunk === 0 || parent.uploadData.key === 0) {
|
||||
parent.uploadData.key = response.key;
|
||||
}
|
||||
|
||||
//If the file isn't done uploading, update the progress bar and run this.sendFile again for the next chunk
|
||||
if(chunk < parent.uploadData.numberOfChunks) {
|
||||
parent.progressUpdate(chunk + 1);
|
||||
parent.sendFile(chunk + 1);
|
||||
}
|
||||
//If the file is complete uploaded, instantiate the finalizing method
|
||||
else {
|
||||
parent.sendFileData();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//Send the file chunk
|
||||
xhr.send(blob);
|
||||
};
|
||||
|
||||
//Slice the file into the desired chunk
|
||||
//This is the core of the script. Everything else is just fluff.
|
||||
var blob = this.uploadData.file.slice(start, stop);
|
||||
reader.readAsBinaryString(blob);
|
||||
};
|
||||
|
||||
//This method is for whatever housekeeping work needs to be completed after the file is finished uploading.
|
||||
//As it's setup now, it passes along the original filename to the server and the server renames the file and removes it form the temp directory.
|
||||
//This function could also pass things like this.uploadData.file.type for the mime-type (although it would be more accurate to use php for that)
|
||||
//Or it could pass along user information or something like that, depending on the context of the application.
|
||||
this.sendFileData = function() {
|
||||
var data = 'key=' + this.uploadData.key + '&name=' + this.uploadData.file.name + '&type=' + this.uploadData.file.type + '&size=' + this.uploadData.file.size + '&origin=' + parent.settings.origin + '&' + parent.settings.formParams;
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", parent.settings.scriptPath + '?' + parent.settings.cidReq + '&action=finish', true);
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if(xhr.readyState == 4) {
|
||||
var response = JSON.parse(xhr.response);
|
||||
|
||||
//If there's an error, call the error method
|
||||
if(response.errorStatus !== 0 || xhr.status != 200) {
|
||||
parent.printResponse(response.errorText, true);
|
||||
return;
|
||||
}
|
||||
|
||||
//Reset the upload-specific data so we can process another upload
|
||||
parent.resetKey();
|
||||
|
||||
//Change the submit button text so it's ready for another upload and spit out a sucess message
|
||||
parent.$(parent.settings.submitButton).value = 'Start Upload';
|
||||
parent.printResponse('File uploaded successfully.', false);
|
||||
|
||||
if (response.redirect) {
|
||||
location.href = response.redirect;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
//Send the reques
|
||||
xhr.send(data);
|
||||
};
|
||||
|
||||
//This method cancels the upload of a file.
|
||||
//It sets this.uploadData.aborted to true, which stops the recursive upload script.
|
||||
//The server then removes the incomplete file from the temp directory, and the html displays an error message.
|
||||
this.abortFileUpload = function() {
|
||||
this.uploadData.aborted = true;
|
||||
var data = 'key=' + this.uploadData.key;
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", this.settings.scriptPath + '?' + this.settings.cidReq + '&action=abort', true);
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if(xhr.readyState == 4) {
|
||||
var response = JSON.parse(xhr.response);
|
||||
|
||||
//If there's an error, call the error method.
|
||||
if(response.errorStatus !== 0 || xhr.status != 200) {
|
||||
parent.printResponse(response.errorText, true);
|
||||
return;
|
||||
}
|
||||
parent.printResponse('File upload was cancelled.', true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//Send the request
|
||||
xhr.send(data);
|
||||
};
|
||||
|
||||
//Pause the upload
|
||||
//Sets this.uploadData.paused to true, which breaks the upload loop.
|
||||
//The current chunk is still stored in this.uploadData.pauseChunk, so the upload can later be resumed.
|
||||
//In a production environment, you might want to have a cron job to clean up files that have been paused and never resumed,
|
||||
//because this method won't delete the file from the temp directory if the user pauses and then leaves the page.
|
||||
this.pauseUpload = function() {
|
||||
this.uploadData.paused = true;
|
||||
this.printResponse('', false);
|
||||
this.$(this.settings.submitButton).value = 'Resume';
|
||||
};
|
||||
|
||||
//Resume the upload
|
||||
//Undoes the doings of this.pauseUpload and then re-enters the loop at the last chunk uploaded
|
||||
this.resumeUpload = function() {
|
||||
this.uploadData.paused = false;
|
||||
this.$(this.settings.submitButton).value = 'Pause';
|
||||
this.sendFile(this.uploadData.pauseChunk);
|
||||
};
|
||||
|
||||
//This method updates a simple progress bar by calculating the percentage of chunks uploaded.
|
||||
//Also includes a method to calculate the time remaining by taking the average time to upload individual chunks
|
||||
//and multiplying it by the number of chunks remaining.
|
||||
this.progressUpdate = function(progress) {
|
||||
|
||||
var percent = Math.ceil((progress / this.uploadData.numberOfChunks) * 100);
|
||||
this.$(this.settings.progressBarField).style.width = percent + '%';
|
||||
this.$(this.settings.progressBarField).textContent = percent + '%';
|
||||
|
||||
//Calculate the estimated time remaining
|
||||
//Only run this every five chunks, otherwise the time remaining jumps all over the place (see: http://xkcd.com/612/)
|
||||
if(progress % 5 === 0) {
|
||||
|
||||
//Calculate the total time for all of the chunks uploaded so far
|
||||
this.uploadData.totalTime += (new Date().getTime() - this.uploadData.timeStart);
|
||||
console.log(this.uploadData.totalTime);
|
||||
|
||||
//Estimate the time remaining by finding the average time per chunk upload and
|
||||
//multiplying it by the number of chunks remaining, then convert into seconds
|
||||
var timeLeft = Math.ceil((this.uploadData.totalTime / progress) * (this.uploadData.numberOfChunks - progress) / 100);
|
||||
|
||||
//Update this.settings.timeRemainingField with the estimated time remaining
|
||||
this.$(this.settings.timeRemainingField).textContent = timeLeft + ' seconds remaining';
|
||||
}
|
||||
};
|
||||
|
||||
//Simple response/error handler
|
||||
this.printResponse = function(responseText, error) {
|
||||
this.$(this.settings.responseField).textContent = responseText;
|
||||
this.$(this.settings.timeRemainingField).textContent = '';
|
||||
if(error === true) {
|
||||
this.$(this.settings.progressBarField).style.backgroundColor = this.settings.progressBarColorError;
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user