Monthly Archives: May 2013

Fine Uploader 3.6

UPDATE: June 11, 2013 – 3.6.4 Hotfix Release

This hotfix release addresses the following defect:

  • Client-side error when handling a response that contains an overridden UUID. (#888)

UPDATE: June 4, 2013 – 3.6.3 Hotfix Release

This hotfix release addresses the following defect:

  • Not able to submit/upload files in IE8. (#876)

UPDATE: June 4, 2013 – 3.6.2 Hotfix Release

This hotfix release addresses the following defect:

  • Fine Uploader may freeze or noticeably lag during initialization of the library in IE8 and IE8. (#872)

UPDATE: June 2, 2013 – 3.6.1 Hotfix Release

This hotfix release addresses the following defects:

  • Object detection (qq.isObject(...)) is broken if uploader is initialized and used across different frames/contexts. (#866)
  • File detection is broken if uploader is initialized and used across different frames/contexts. (#870)

Overview

Fine Uploader 3.6 has been released! Two of the new major features are Complete support for uploading via a mobile device’s camera and ability to automatically append newly selected files to the top of the file list (Fine Uploader mode). Please see the downloads page to download the latest released version of the library.

Features & Enhancements

  • Upload directly from a mobile device’s camera. Please read the blog post on this new feature for more details. (#389)
  • Optionally have the most recent selected file batch added to the top of the file list UI (FineUploader mode). (#693)
  • Query a Fine Uploader instance for upload stats and receive a callback when any file changes state. Please read the blog post on this new feature for more details. (#822)
  • Allow promises to be returned from many callbacks to allow for non-blocking work to take place in the callback handler before Fine Uploader processes the handler’s return value. Please read the blog post on this new enhancement. (#805)
  • Make addFiles simple to use in any browser, regardless of File API support. That is, the use of this API function has been normalized. (#749)
  • Ensure it is easy to determine what version of Fine Uploader is in use by looking at log messages or typing qq.version in the javascript console. (#803)
  • More human-readable display of file sizes. (#804)
  • Allow server-side response to override the UUID assigned to a file. (#764)
  • Ensure deleted file’s internal representation is (mostly) purged and expose the isValid method used by the internal upload handler. (#813)

Bugs Fixed

  • Multiple instances in non-File-API browsers (such as IE9 and older) may cause uploads to hang if they are POSTed simultaneously. (#838)
  • Calling reset() in onComplete handler causes an error. (#834)
  • setDeleteFileParams API method is not documented. (#820)
  • New (non-persisted UUID) is returned on getUuid call for a resumable file before the onResume callback returns successfully. (#828)
  • Ensure upload/select files button container does not have an inline style of filter: alpha(NaN) in IE7. (#817)

Changes Planned For 3.7

At the writing of this blog post, planning for 3.7 is still in progress. Cases will be assigned to 3.7 in the next few days or so. Please check the open (to be worked on or in-progress) and closed (completed or removed) cases in the 3.7 milestone. Please pay careful attention to the tags assigned to each case for additional important context. Feel free to comment on any of these cases. Make your opinion heard, before it’s too late! Note that the list of planned features may change at any time during the release. As always, please let me know (in the forums or the issue tracker) if you have any suggestions for improvement, or any killer features you’d like me to add. -Ray Nicholus and the rest of the Fine Uploader team at Widen Enterprises.

Upload directly via a camera (on mobile devices)

This was always possible with Fine Uploader, but I’ve made it a bit simpler starting with 3.6. No changes (just testing) were necessary to ensure this was possible on Android devices, along with the Microsoft Surface Tablet. iOS, however, required a little bit of code.

Previous to 3.6, if you wanted to access the camera for the purposes of uploading from Fine Uploader from iOS devices, you needed to do the following:

  • Set the multiple option to false.
  • Ensure the following value appears in the acceptFiles property of the validation option: “image/*;capture=camera”.

This isn’t particularly difficult to do, but you also need to ensure that the current device is running iOS, since you probably don’t want to disable multiple selection on all browsers.

In 3.6, I added a new camera option. The only property, currently, is ios, which is a boolean (defaulting to false). If you override this value to true, the two items in the above list are handled, but only on iOS devices. I also added a qq.ios() method to the qQuery module, which Fine Uploader uses internally to determine if the current device is running iOS.

So, if you’d like to easily ensure camera access is available in iOS, your Fine Uploader instance would look something like this:

var uploader = new qq.FineUploader({
  element: document.getElementById("myFineUploader"),
  camera: {
    ios: true
  }
});

The downside to setting the ios property of the new camera option to true is that you will not be able to select multiple files at once. This is a limitation of iOS. If you really want to allow users to select multiple files and have camera access, you can create your own <input type="file" accept="image/*;capture=camera"> element, register an onchange handler, and pass the input element to Fine Uploader’s addFiles API method (in your handler). This button will be used exclusively for camera access and the button provided by Fine Uploader would be used for multiple file selection. You would, of course, not set the ios property of the camera option to true in this case. Here’s an example:

<div id="cameraButtonContainer" class="qq-upload-button" style="position: relative; overflow: hidden; direction: ltr; display: none;">
  <div>Camera</div>
  <input id="cameraButton" type="file" name="camera" accept="image/*;capture=camera" style="position: absolute; right: 0px; top: 0px; font-family: Arial; font-size: 118px; margin: 0px; padding: 0px; cursor: pointer; opacity: 0;">
</div>
<div id="myFineUploader"></div>

 

var uploader = new qq.FineUploader({
  element: document.getElementById("myFineUploader");
});

if (qq.ios()) {
  qq(document.getElementById("cameraButtonContainer")).css({display: 'block'});

  qq(document.getElementById("cameraButton")).attach("change", function() {
    uploader.addFiles(this);
  });
}

I am considering support for multiple Fine Uploader buttons (created and managed by Fine Uploader) in a future version. This would make the above example much easier to implement. See case #819 for details or to voice your opinion/show your support.

If you have any suggestions that may improve this or any other feature, please open up a feature request in the issue tracker.

regards,
Ray Nicholus and the rest of the Fine Uploader team @ Widen Enterprises

Callbacks That Permit Asynchronous Returns

Since 3.4, Fine Uploader has been embracing the concept of “promises” which allow for support of asynchronous tasks. Initially, promises were introduced to allow user input for pasted images for the “paste to upload” feature. Then, in 3.5, Fine Uploader began to make more use of promises internally. For example, the drag and drop modules uses promises to handle the complex web of asynchronous callbacks associated with the Filesystem API. Now, starting with version 3.6, Fine Uploader will allow promises to be valid return types for some callbacks (#805).

Supported Callbacks

Starting with version 3.6, the following callbacks can handle promissory return types. All of these callbacks can also prevent an associated action from being executed with a false return value (non-promise) or a call to failure() on a returned promise instance.

  • onSubmit
  • onCancel
  • onResume
  • onValidateBatch
  • onValidate
  • onSubmitDelete
  • onPasteReceived

Examples and Use Cases

Of couse, you don’t have to return a promise – you can simply return “false” (to prevent the associated action inline), or nothing at all (undefined). However, there are some instances where you may want to perform some asynchronous work in your callback handler. A promise can be returned from any of the above callbacks if you need to execute some non-blocking task, such as an ajax request, or asking the user for input via a modal window that does not block the UI thread (such as a Bootstrap modal, or a Bootbox.js dialog box.

For example, let’s say you want to ask the user (on large files) to confirm a request to cancel an in-progress upload. Your onCancel callback handler might look something like this, assuming use of a Bootbox.js Confirm dialog:

$('#myFineuploader')
  .on("cancel", function(event, id, name){

    var promise = new qq.Promise();

    bootbox.confirm("Cancel " + name + "?", function(result) {
      if (result) {
        promise.success(); //proceed with the cancel request
      }
      else {
        promise.failure(); //don't cancel - ignore
      }

    });

    return promise;

  });

Notice that Fine Uploader waits the user to provide input, after which your code will call either failure() on the promise instance (ignoring the cancel request) or success() (confirming the cancel request). Fine Uploader does not block and other files, or any other UI tasks. It simply defers the work required to cancel the in-progress file until the returned promise is “fulfilled”.

The same confirmation concept can be applied to a onSubmitDelete handler, an onSubmit handler, an onResume handler, or even an onPasteReceived callback handler.
Note that the dialog will NOT pause the in-progress upload. There is no way to reliably pause an in-progress upload, especially cross-browser. This is why I suggest that you only prompt the user for “large”/slow-moving file uploads, and probably only when there is a reasonable amount of time left to upload for the associated file. Otherwise, the upload may complete before the user responds to the dialog.

Another example involves the onSubmit handler. Suppose you want to ask the user for some additional information regarding a submitted item. In this example, let’s use a Bootbox.js prompt dialog.

$('#myFineuploader')
  .on("submit", function(event, id, name) {

    var promise = new qq.Promise(),
        self = this;

    bootbox.prompt("Enter a description for this item", function(description) {
      if (description === null) {
        promise.failure(); //the user cancelled the dialog, so, prevent this item from being submitted
      }
      else {
        $(self).fineUploader('setParams', {description: description}, id);
        promise.success(); //proceed with processing of this item
      }

    });

    return promise;
  });

Here, you are asking the user to describe the submitted item. The answers to this prompt will be sent as a parameter along with the item in the associated upload POST request.

Note that this callback will be invoked for each submitted file, so, if you plan on handling multiple submissions at once (via drag and drop or multiple selection in the file chooser), you will want to maintain a queue of promise instances created in your callback handler invocations and present the user with dialogs for each submitted item one at a time. You can add a new promise instance along with appropriate context (file name and ID) with each callback invocation, and continue to solicit the user to input a description for each submitted file until your queue of promise instances is empty. Don’t forget to fulfill each promise after the user provides feedback!

I hope you find this enhancement useful. If you have any other ideas/requests for further enhancements or features, please file a feature request in the project’s issue tracker.

regards,

-Ray Nicholus and the rest of the Fine Uploader team @ Widen Enterprises