[RESOLVED] jQuery file access plugin (default = file upload)
Results 1 to 3 of 3

Thread: [RESOLVED] jQuery file access plugin (default = file upload)

  1. #1
    Senior Member
    Join Date
    Jul 2007
    Posts
    3,637

    resolved [RESOLVED] jQuery file access plugin (default = file upload)

    Not a single line of PHP, but perhaps it's still ok to post here. Unless it should be moved to clientside... Just thought I'd get some feedback for this plugin.

    The plugin is supposed to handle dropping files or click + select from file dialog. Can deal with multiple files, but html 5 only, no flash fallback. It uses jQuery.ajax as default method for dealing with dropped/selected files. But it's possible to specify some other handler, if you for example want to use the file data in the browser rather than upload it somewhere.
    Code:
    (function($) {
    	/* ajaxSettings will extend jquery ajax settings object
    			defaults come from form controls and form attributes such as
    			form action and form post
    		uploaderSettings extend settings for the uploader functionality
    		uploaderSettings are merged into the settings object under settings.uploader below
    	*/
    	$.fn.uploader = function(ajaxSettings, uploaderSettings) {
    		return  this.each(function() {
    			 // only invoke the jquery constructor, $(this), once
    			var $this = $(this);
    
    			var settings = $.extend({
    				'action'	: this.action,
    				'method'	: 'post',
    				'uploader'	: $.extend({
    						'name'		: $this.children('#fileinput').attr('name'),
    						'revertText'	: $this.children('#file_multidrop').html(),
    						'uploadText'	: 'Uploading…',
    						'failText'		: 'Upload failed',
    						'uploadClass'	: 'uploading',
    						/* default upload handler: contains call to jQuery.ajax */
    						'uploadHandler'	: sendFiles,
    						'success'		: function(d, t, j) { /* if needed */ },
    						'fail'			: function(j, t, e) { /* if needed */ }
    					},
    					uploaderSettings
    				),
    				/* jquery ajax.done and ajax.fail may be overridden.
    					but generally you'd instead specify handlers in the uploaderSettings
    					object, which will then be called from the default ajax handlers
    				*/
    				'success'	: _success,
    				'fail'		: _fail
    			}, ajaxSettings);
    
    			var that = this;
    			function _success(data, txt, jqx) {
    				$f = $('#file_multidrop');
    				$f.html(settings.uploader.revertText);
    				$f.removeClass(settings.uploader.uploadClass);
    				settings.uploader.success(data, txt, jqx);
    			}
    			function _fail(jqx, txt, err) {
    				$f = $('#file_multidrop');
    				$f.html(settings.uploader.failText);
    				$f.removeClass(settings.uploader.uploadClass);
    				settings.uploader.fail(data, txt, jqx);
    			}
    
    
    			$this.children('#file_multidrop').bind('dragenter.uploader', null, false);
    			$this.children('#file_multidrop').bind('dragexit.uploader', null, false);
    			$this.children('#file_multidrop').bind('dragover.uploader', null, false);
    
    			/*	The user selected files are passed slightly differently from file input and
    				FileReader. We need consistent access to those files and that's what we fix
    				in the next two event handlers (evt.target.files vs evt.originalEvent.dataTransfer) */
    			$this.children('#fileinput').bind('change.uploader', null, function(evt) {
    				evt.stopPropagation();
    				evt.preventDefault();
    				//	The event object for changes to file input contains target.files while (see next comment)...
    				settings.fileholder = evt.target;
    				settings.uploader.uploadHandler(settings, $(evt.target).parent('form'));
    			});
    			$this.children('#file_multidrop').bind('click.uploader', null, function(evt) {
    				$(this).parent('form').children('#fileinput').trigger('click');
    			});
    			$this.children('#file_multidrop').bind('drop.uploader', null, function(evt) {
    				evt.stopPropagation();
    				evt.preventDefault();
    				// ... the event object for a drop event contains originalEvent.dataTransfer
    				settings.fileholder = evt.originalEvent.dataTransfer;
    				settings.uploader.uploadHandler(settings, $(evt.target).parent('form'));
    			});
    		});
    
    		function sendFiles(settings, form) {
    			if (settings.fileholder.files.length)
    			{
    				var fd = new FormData();
    				for (var i = 0; i < settings.fileholder.files.length; ++i) {
    					var f = settings.fileholder.files[i];
    					fd.append(settings.uploader.name+'['+i+']', f);
    				}
    				for (x in settings.data) {
    					fd.append(x, settings.data[x]);
    				}
    
    				/* contentType must be false or the boundary attribute will be overwritten */
    				settings['contentType'] = false;
    				/* processData must be false or fd (FormData) will be transformed to string */
    				settings['processData'] = false;
    
    				var fileHandlerOptions = {
    					'url'	: settings.action,
    					'type'	: settings.method,
    					/* (unverified) I read somewhere that contentType and processData...
    					/* ... must be false or the boundary attribute will be overwritten */
    					'contentType': false,
    					/* ... must be false or fd (FormData) will be transformed to string */
    					'processData': false,
    					'data'	: fd,
    					'cache'	: false,
    					'dataType'	: 'json',
    
    					'beforeSend'	: function() {
    						$('#file_multidrop').html(settings.uploader.uploadText);
    						$('#file_multidrop').addClass(settings.uploader.uploadClass);
    					}
    				}
    				$.ajax(fileHandlerOptions).done(function (data, txt, jqx) {
    						settings.success(data, txt, jqx);
    					}
    				).fail(function (jqx, txt, err) {
    						settings.fail(jqx, txt, err);
    					}
    				);
    			}
    		}
    	};
    })(jQuery);
    Setting it up
    Code:
    /*	The first argument specifies settings used for jQuery.ajax settings which may override
    	stuff specified by form attributes etc, such as form action.
    	Success and failure handlers may be overridden, but it's recommended that you specify
    	them in the second argument instead.
     *	The second argument specifies settings regarding the uploader: texts and css class to use when uploading,
     	success and failure handlers specified here will be called in ajax.done and ajax.fail
     */
    jQuery(document).ready(function($) {
    	$('#uploadform').uploader({},
    		{
    			/* Texts to display after upload / waiting for more files. Only needed if you don't
    				want to use the default text as specified inside the #file_multidrop div */
    			'revertText' : 'Done',
    			/* Text to display when uploading */
    			'uploadText' : 'Uploading…',
    			/* CSS class to add when uploading, for example to highlight button */
    			'uploadClass': 'uploading'
    			/* specify success handler if needed */
    			,'success'	: foo_success
    			/* specify fail handler if needed */
    			,'fail'		: foo_fail
    			/* If you want to use some other handler for files than the default function sendFiles */
    			, 'uploadHandler'	: foo_handlefiles
    		}
    	);
    });
    Used together with
    HTML Code:
    	<!-- form's action attribute: default action for uploads -->
        <form id="uploadform" action="/a_test.php" method="post">
           	<!-- use whatever class you want for styling purposes. it is not used by the plugin -->
           	<div id="file_multidrop" class="file-button">Drop files here or click button</div>
        	<!-- file input name attribute used as default for file uploads ($_FILES['name_attribute_value']) -->
        	<input type="file" name="FileData[]" id="fileinput" multiple style="display:none;">
    	</form>
    And do note that you do not have to upload files at all. You may continue to use them by specifying uploadHandler, such as
    Code:
    function foo_handleFile(opts, frm) {
    	// Only deals with the first file
    	var f = opts.fileholder.files[0];
    	var fr = new FileReader();
    	fr.onload = function() { alert('file loaded'); };
    	fr.readAsBinaryString(f);
    }
    Last edited by johanafm; 03-28-2013 at 09:07 AM.

  2. #2
    Senior Member Derokorian's Avatar
    Join Date
    Apr 2011
    Location
    Denver
    Posts
    1,764
    For what its worth, you should use a blank object as the first parameter to extend, that way if you use this twice, you haven't overwritten your default settings. IE:

    Code:
    var defaults = {
       something: 'value',
       else: 'another'
       // etc
    };
    
    this.options = $.extend({},defaults,input);
    Sadly, nobody codes for anyone on this forum. People taste your dishes and tell you what is missing, but they don't cook for you. ~anoopmail
    I'd rather be a comma, then a full stop.
    User Authentication in PHP with MySQLi - Don't forget to mark threads resolved - MySQL(i) warning

  3. #3
    Senior Member
    Join Date
    Jul 2007
    Posts
    3,637
    Thanks Derokorian. That looks like the kind of misstake that takes a lot of time to find when the problem suddenly comes into play.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •