Jump to content

How can I upload large files with FormData by chunking the files using Web/Service Workers in jquery without any plugins


sagnik

Recommended Posts

Hi, I'm developing a plugin which will allow users to upload files to the server as well as send form data to the server. But I need to chunk/slice large files using Web/Service Worker so that it doesn't break PHP's upload_max_filesize & post_max_size and don't halt the UI as well. But the problem is, if the form contains input fields, I need to send them as well. I want know how can I do that?

Link to comment
Share on other sites

  • 2 weeks later...

Okay, I've tried but it's not working that way I've wanted.

Sorry but I don't have access to the Internet for the past 4 days, so I was not able to post the result here.

Here is the code of my plugin:

/****************************************************************************************************************************
******************************************************SGNUPLOAD v1.0.1*******************************************************
*****************************************************************************************************************************
*	DATE: October 15, 2018																									*
*	AUTHOR: Sagnik Ganguly																									*
*	E-MAIL: sagnikganguly2012@rediffmail.com																				*
*	WEBSITE: https://plugins.sgnetworks.cf/jquery/sgnupload																	*
*	DOCUMENTATION: https://docs.plugins.sgnetworks.cf/jquery/sgnupload														*
****************************************************************************************************************************/
if (!window.BlobBuilder) {
	window.BlobBuilder = window.WebKitBlobBuilder || window.MozBlobBuilder;
}

if (!window.URL) {
	window.URL = window.webkitURL || window.mozURL;
}
	
$.worker = function(args) { 
	var def = $.Deferred(function(dfd) {
		var worker;
		if (window.Worker) {
			var url = args.file;

			// If we have found a DOM object related,
			// we need constructo a `BlobBuilder` to
			// inline the web worker.
			if(args.id){
				var dom = document.querySelector('#' + args.id),
					blob = new BlobBuilder();

				blob.append(dom.textContent);
				url = window.URL.createObjectURL(blob.getBlob());
			}

			// Construct the Web Worker
			var worker = new Worker(url); 

			// If the Worker reports success, resolve the Deferred
			worker.onmessage = function(event) {			
				dfd.resolve(event); 
			};

			// If the Worker reports an error, reject the Deferred
			worker.onerror = function(event) {
				dfd.reject(event); 
			};

			// Create a pointer to 'postMessage' on the Deferred
			this.postMessage = function(msg){
				worker.postMessage(msg);
			};

			this.terminate = function(){
				worker.terminate();
			};

			// If args were passed, start the worker with supplied args
			if(args.args){
				worker.postMessage(args.args); 
			}
		} else {
			$.error("Worker is not supported in this browser!");
		}
	});

	return def; 
};
(function ($) {
	var SGNUpload = function (element, options) {
		var _pluginName = "SGNUpload",
		_version = "1.0.1";

		var SPACE_KB = 1024,
		SPACE_MB = 1024 * SPACE_KB;
		SPACE_GB = 1024 * SPACE_MB;
		SPACE_TB = 1024 * SPACE_GB;

		var _defaults = {
			onProgressUpdate: function (progress, loaded, lengthOfFile) {},
			onTaskCompleted: function (e, response) {},
			onTaskCancelled: function () {},
			onTaskFailed: function (e, error) {}
		}
		var _options = {
			url: '',
			formData: '',
			onProgressUpdate: '',
			onTaskCompleted: '',
			onTaskCancelled: '',
			onTaskFailed: ''
		}
		var plugin = this,
		$element = $(element);
		plugin.settings = {}

		function readBlob(opt_startByte, opt_stopByte) {

			var files = document.getElementById('files').files;
			if (!files.length) {
				alert('Please select a file!');
				return;
			}

			var file = files[0];
			var start = parseInt(opt_startByte) || 0;
			var stop = parseInt(opt_stopByte) || file.size - 1;

			var reader = new FileReader();

			// If we use onloadend, we need to check the readyState.
			reader.onloadend = function (evt) {
				if (evt.target.readyState == FileReader.DONE) { // DONE == 2
					/* document.getElementById('byte_content').textContent = evt.target.result;
					document.getElementById('byte_range').textContent =
					['Read bytes: ', start + 1, ' - ', stop + 1,
					' of ', file.size, ' byte file'].join(''); */
				}
			};

			var blob = file.slice(start, stop + 1);
			reader.readAsBinaryString(blob);
		}

		function Bytes2String(sizeInBytes) {
			if (sizeInBytes < SPACE_KB) {
				return sizeInBytes.toString() + " Byte(s)";
			} else if (sizeInBytes < SPACE_MB) {
				return (sizeInBytes / SPACE_KB).toString() + " KB";
			} else if (sizeInBytes < SPACE_GB) {
				return (sizeInBytes / SPACE_MB).toString() + " MB";
			} else if (sizeInBytes < SPACE_TB) {
				return (sizeInBytes / SPACE_GB).toString() + " GB";
			} else {
				return (sizeInBytes / SPACE_TB).toString() + " TB";
			}
		}
		function Bytes2ProgressString(progressInBytes, totalInBytes) {
			if (totalInBytes < SPACE_KB) {
				return progressInBytes.toString() + "/" + totalInBytes.toString() + " Byte(s)";
			} else if (totalInBytes < SPACE_MB) {
				return (progressInBytes / SPACE_KB).toString() + "/" + (totalInBytes / SPACE_KB).toString() + " KB";
			} else if (totalInBytes < SPACE_GB) {
				return (progressInBytes / SPACE_MB).toString() + "/" + (totalInBytes / SPACE_MB).toString() + " MB";
			} else if (totalInBytes < SPACE_TB) {
				return (progressInBytes / SPACE_GB).toString() + "/" + (totalInBytes / SPACE_GB).toString() + " GB";
			} else {
				return (progressInBytes / SPACE_TB).toString() + "/" + (totalInBytes / SPACE_TB).toString() + " TB";
			}
		}
		function percentage(progress, total) {
			return Math.round(total ? progress * 100 / total : 100);
		}
		function publishProgress(e,loaded,total) {
			var t = $.type(e),
			percent = t == "object" && e.lengthComputable ? percentage(e.loaded, e.total) + "%" :
				t == "number" ? e + "%" :
				t == "string" ? e :
				"0%";
			if(t=="object" && e.lengthComputable && loaded===undefine && total===undefined)
				plugin.settings.onProgressUpdate(percent, e.loaded, e.total);
			else if(t=="number" && $.isNumeric(loaded) && $.isNumeric(total))
				plugin.settings.onProgressUpdate(percent, loaded, total);
		}
		function werror(e) {
			console.log(e, 'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message);
		}
		function _create() {
			/* $.ajax({
			url: plugin.settings.url,
			type: 'POST',
			data: plugin.settings.formData,
			cache: false,
			contentType: false,
			processData: false,
			xhr: function(){
			var myXhr = $.ajaxSettings.xhr();
			if(myXhr.upload){
			myXhr.upload.addEventListener('progress', function(e){
			if(e.lengthComputable){
			publishProgress(e);
			}
			}, false);
			myXhr.upload.addEventListener('loadend', function(e){
			publishProgress(e);
			}, false);
			}
			return myXhr;
			},
			success: function(d){
			plugin.settings.onTaskCompleted(d);
			},
			error: function(xhr){
			plugin.settings.onTaskFailed(xhr);
			}
			}); */
			/******* HERE IS THE PROBLEM *******
			*AS MY PLUGIN IS ASSOCIATED ON $ INSTEAD OF $.fn, I DON'T HAVE ACCESS TO DOM ("#fileupload") AS USERS CAN HAVE AN ID OTHER THAN THAT*********
			* SO I NEED A WAY TO SUPPORT CHUNKED FILE UPLOADS WITH $.fn, I NEED A $. OBJECT */
			$("#fileupload").fileupload({
				url: plugin.settings.url,
				//dataType: 'json',
				done: function (e, data) {
					/* $.each(data.result.files, function (index, file) {
						$('<p/>').text(file.name).appendTo('#files');
					}); */
					plugin.settings.onTaskCompleted(e,data);
				},
				progress: function (e, data) {
					var progress = parseInt(data.loaded / data.total * 100, 10);
					/* $('#progress .progress-bar').css(
						'width',
						progress + '%'
					); */
					publishProgress(progress, data.loaded, data.total);
				},
				fail: function(e, data){
					plugin.settings.onTaskFailed(e,data);
				}
			})
		}

		plugin.init = function (args) {
			plugin.settings = $.extend(_defaults, args);
			$.each(plugin.settings, function (k, v) {
				if (typeof v === 'function') {
					if (_options.hasOwnProperty(k)) {
						_checked = true;
					} else {
						_checked = false;
						$.error('Invalid callback for: ' + k + ' in jQuery.' + _pluginName);
					}
				} else if (typeof v === 'string') {
					if ($.inArray(v, _options[k]) !== -1 || _options.hasOwnProperty(k)) {
						_checked = true;
					} else {
						_checked = false;
						$.error('Invalid value: ' + v + ' for option: ' + k + ' in jQuery.' + _pluginName);
					}
				}
			});
			if (_checked) {
				$element.data('options', plugin.settings);
				_create();
			} else {
				$.error('Something went wrong in jQuery.' + _pluginName);
			}
		}
	}
	$.SGNUpload = function (options) {
		var _this = this;
		var _plugin = new SGNUpload(this, options);
		_this.initialize = function (options) {
			_plugin.init(options);
			return this;
		}
		if (typeof options !== 'undefined')
			return this.initialize(options);
		return this;
	}
	return this;
})(jQuery);
And here is the inilization code of the plugin:

submitBtn.click(function(e){
		e.preventDefault();
		var $this=$(this);
		$(this).SGNSpinner({
			showContents: false,
			halign: 'center',
			valign: 'middle'
		});
		if(validationPassed){
			if(tos.prop("checked") && privacy.prop("checked")){
				var data=new FormData($('#sge-upload_gamePlayForm')[0]);
				$.each(files, function(key, value){
					data.append(key, value);
				});
				$.SGNUpload({
					url: '<?=$public_root;?>upload/ajax/gameplay',
					formData: data,
					onProgressUpdate: function(progress, loaded, lengthOfFile){
						console.log(progress, loaded, lengthOfFile);
					},
					onTaskCompleted: function(response){
						console.log(response);
					},
					onTaskCancelled: function(){
						
					},
					onTaskFailed: function(error){
						console.log(error);
					}
				});
			} else {
				$(this).SGNSpinner().hide();
				$this.SGNIMsg("You must be agree to our Terms Of Service & Privacy Policy in order to submit the form. Please read the agreements first then on the I agree buttons then submit the form again.");
			}
		} else {
			$(this).SGNSpinner().hide();
			alert("Please check the details and try again");
		}
	})
});
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...