Category Archives: tutorials

Uploads without any server code

If you just want to simply accept files from users, why should you have to write server-side code? Well, if you are using Fine Uploader S3 version 4.2 or later, you don’t have to worry about server-side languages anymore! This blog post accompanies a live demo of this workflow at https://fineuploader-s3-client-demo.s3.amazonaws.com/index.html.

Summary

Starting with Fine Uploader S3 4.2, the “no server” upload workflow is fully supported. This means that you only need to host your JavaScript and HTML files. Fine Uploader S3, AWS, and your identity providers take care of the heavy-lifting for you.

The workflow is simple:

  1. authenticate your users with the help of an identity provider, such as Google
  2. Use the temporary token from your ID provider to grab temporary access keys from AWS
  3. Pass the keys on to Fine Uploader S3
  4. Your users can now upload to your S3 bucket

Requirements

A client-side workflow such as this one means that you must ensure your users are utilizing a modern browser (not IE9 or older). Some of the SDKs used here (mostly the AWS JavaScript SDK) will not work on older browsers.

Other things you will need to make this happen:

  • Fine Uploader S3 4.2+
  • OAuth/login JavaScript SDK from Google, Facebook, or Amazon
  • A simple web server to host your static content, such as a public-read S3 bucket
  • An AWS account
  • AWS JavaScript SDK

Concepts

You should be familiar, at a high-level, with OAuth 2.0, which is the standard used by Google, Amazon, Facebook, and other similar identity providers. An identity provider here will allow you to request temporary credentials from AWS on behalf of the authenticated user. These credentials are required by Fine Uploader S3 to upload files to your S3 bucket without any server-side intervention on your part. It is important to ensure traffic between your web app and the identity provider be secured via SSL (HTTPS) when using an OAuth 2.0 ID provider.

You must also be familiar with:

  • HTML
  • JavaScript
  • Amazon’s Simple Storage Service (S3)
  • Fine Uploader S3

Setting up your identity providers

The live demo of this workflow allows you to choose between Google, Facebook, and Amazon as identity providers. You will need to register your application with each of these identity providers, record the assigned client ID, and specify the domain(s) of your web application in order to ensure that authentication against your registered application can only occur on your application’s domain(s).

Google

1.) Login to the Google Cloud Console.

2.) Create a new project.
empty google cloud console project list

google cloud console create project

3.) Enable the “Google+ API”
enable Google+ API

4.) Create a new OAuth Client ID in the “Credentials” section of the “APIs & auth” side menu. The application type will be “Web application”. You should include the domain(s) of your web app in the “Authorized Javascript origins” text box. You can leave the “Authorized redirect URI” field blank.
create OAuth client ID

5.) Record the “Client ID for web application” value.
OAuth client ID

Facebook

1.) Visit the Facebook developers page.

2.) Invoke the “Apps” menu, and click “Create a new app”. Fill in the fields as appropriate.
create facebook app

3.) Record the App ID after creating the app.
facebook app ID

4.) Click on the “Settings” option on the right, and then click the “Add Platform” bar.
facebook app add platform

5.) Click “Website”.
facebook app choose app type

6.) Fill out the “Site URL” under the new “Website” section. This should be the domain of your web app. Finally, save your changes.
facebook app details

Amazon

1.) Sign in to Amazon’s App Console. with your AWS account. Click on the “Register new application” button.

2.) Fill out the relevant form fields. Note that all fields other than the logo URL are required.
register AWS app

3.) Record the App ID.
AWS app ID

4.) Expand the “Web Settings” section, and add your app’s domain name(s) in the “Allowed JavaScript Origins” section. Note that this URL must be SSL/HTTPS.
AWS web app settings

Creating and securing your S3 bucket

If you haven’t done so already, you will need to create an S3 bucket to receive your user’s files. This is covered in some detail in the “Configuring your buckets” section of the initial Fine Uploader S3 blog post.

In addition to the AllowedHeader values mentioned in the CORS section of the bucket configuration documentation, you will also need to ensure that the x-amz-security-token header is allowed.

Setting up your IAM roles

You will need to create a separate IAM role for each identity provider. Each role will link an identity provider to specific client-side permissions needed by Fine Uploader S3 to send files to your S3 bucket.

1.) Navigate to the IAM roles section of the AWS console.

2.) Click the “Create New Role” button & fill in a name.
IAM role name

3.) Choose the “Role for Identity Provider Access” option on the next step. Click the “Select” button next to “Grant access to web identity providers”.
IAM role for ID provider

4.) Pick an identity provider. If you are using Facebook or Amazon, paste the client ID you recorded when you registered your app in the “Application Id” field. If you are using Google, paste the application ID you recorded in the “Audience” field instead. Click “Continue”. You will be brought to a “Verify Role Trust” step. Click “Continue” again.
AWS role ID provider
AWS role verify ID provider

5.) Expand the “Policy Generator” section, and click “Select”.
AWS role policy generator

6.) You must now specify permissions for your S3 bucket. Fine Uploader S3 only needs the PutObject permission to upload files. However, if you intend to make all files publically viewable (as we do in the live demo), you will also need to include the PutObjectAcl permission. The Amazon Resource Name includes the name of the S3 bucket that will receive files, in the format “arn:aws:s3:::YOUR_BUCKET_NAME/*”. After you have filled all of this out, click “Add Statement”, then “Continue”.
IAM role S3 permissions
IAM role bucket name

7.) Click “Continue” on the “Set Permissions” page step that appears next, then “Create Role” on the final step.
IAM role set permissions

8.) Click on your new role in the roles list, then the “Summary” tab on the bottom pane, and record the Role ARN ID.
IAM role ARN

The code

There is a live demo with accompanying commented code as well. Note that the live demo is hosted in a public S3 bucket. This is more apparent when looking at the URL.

The live demo contains the following files:

index.html

Entry point for the live demo. It pulls in all other client-side files and resources. Also, it contains HTML for the Google, Facebook, and Amazon login buttons, as well as other elements required by the third-party JavaScript SDKs. A customized version of a Fine Uploader UI template is also present in the head element. Finally, there is some code to ensure the demo is only displayed if a modern browser is in use. We make use of conditional comments here to display & load the demo if a modern browser is in use, or a message explaining why the demo is not functional if IE9 or older is present.

3 JavaScript files to make use of the identity provider SDKs

We have one JavaScript file for each identity provider. These are used to track authentication requests and pass the token received from a successful auth request on to the AWS SDK. Also, they are used to notify the user when the bearer token has expired (asking them to re-authenticate by clicking on the login button). The files are amazon-auth.js, google-auth.js, and facebook-auth.js.

You must ensure the Role ARN and app IDs are filling in appropriately in these files. Note that the app ID for the Google ID provider is attached to the login button element in index.html as a data attribute. Also note that the facebook and aws files include a providerId in the call they make to the assumeRoleWithWebIdentity method. Google’s ID provider does not have such a property though.

aws-sdk-glue.js

Used to obtain temporary credentials (keys) supplied to Fine Uploader. The bearer tokens obtained from the identity providers are used to generate these credentials.

Fine Uploader S3 built source files & resources

We also must include the Fine Uploader UI S3 jQuery JavaScript, CSS, and other resource files (images/placeholders). You can generate your copy at http://fineuploader.com/customize.

custom.css

Some CSS to enhance the style of this demo.

fineuploader-glue.js

Creates an instance of Fine Uploader UI S3 jQuery. The “complete” and “credentialsExpired” events are observed. The former includes a button that links to the uploaded file in S3 next to the file item in the UI after a successful upload. The latter asks the AWS credentials code for new credentials before they expire.

Additional reading

Full-Stack JavaScript Image Uploader Using AngularJS & Node.js

AngularJS has been a very popular client-side web application framework for some time now. As you may know, Fine Uploader is also quite a powerful cross-browser JavaScript file uploader. So, why not use both? Why not indeed. This post will walk you through writing an AngularJS directive for Fine Uploader. CSS and the native web API will also be used for styling and event handling/DOM manipulation (respectively). We’ll also be using the brand new HTML 5.1 <dialog> element for modal dialog support (and a polyfill for browsers that don’t yet support this element. Complete code for client and server side is also provided that includes a node.js backend.

Demonstrated Features

This demo targets all modern browsers (IE10+, Firefox, Chrome, Safari, Opera, etc). The following features will be demonstrated/enabled in the example code

Dependencies

Client-side

Server-side

Getting Started

This example assumes you are already comfortable with AngularJS, node.js, HTML, JavaScript, and CSS.

In order to implement this example in your web application, you must follow these steps:

  1. Install node.js on your server
  2. Download the angularjs-nodejs example code from the fine-uploader-examples GitHub repo. Add the files to your server.
  3. Run npm install in the directory housing the example code you downloaded. This will pull in all server-side  and client-side dependencies needed.
  4. Start up your server by running “npm run server” and begin uploading!

Notable Custom Features Specific to this Example

If you want to play around with all of the features provided by Fine Uploader UI in this example, run the example code in your own environment. Here, we will point out some of the notable custom features specific to our image uploader example.

Dynamic & Scrollable Drag & Drop Zone

Similar to the upload button, it is potentially useful to include a message in the drop zone that provides useful startup instructions to your users. When they first look at the page, it may be confusing for some, as far as options are concerned. The best approach here is to use Fine Uploader UI’s gallery view and include drop-zone text with specific information for users on how to proceed. This is trivial to implement due to Fine Uploader’s advanced UI features.

There are three possible states for the background text for the drop zone. These states correspond to the capabilities of the current browser. Chrome & Opera provide the ability to drop folders AND files. Everything else (except mobile browsers) provide the ability to drop files.

Here’s what the drop zone will look like in Chrome:
drop files or folders

…and Firefox:
drop files

Image Gallery View

Fine Uploader UI comes with a few different templates that you can customize further to suit your application needs. Our full-stack example uses the gallery view, which renders thumbnails as “tiles”, like this:

Screen Shot 2016-01-25 at 4.08.24 PM.png

Note that the gallery is completely responsive and will move tiles as the browser window changes size. Now, we go a bit further in this example, and allow users to see a larger preview, generated on-demand, simply by clicking on the small thumbnail next to the file. The large preview is generated by Fine Uploader’s “drawThumbnail” API method and rendered in a <dialog> element:

Screen Shot 2016-01-25 at 4.00.31 PM

The large preview is generated only when the smaller thumbnail in the gallery view is clicked. The above displayed modal is just a basic example. You can, of course, style this modal however you please using CSS.

Aggregate & Per-File Progress Bars

This image uploader example also provides an “aggregate progress bar”. This is generated and updated entirely by Fine Uploader UI and indicates the total progress of all submitted files. Notice that each in-progress file has its own progress bar as well.

For example:

Screen Shot 2016-01-25 at 4.06.45 PM

Turnkey Traditional Node.js Server

You can simply drop-in the highly customizable node.js server provided by Fine Uploader –fine-uploader-traditional-server – by installing it from npm. It will handle both chunked and non-chunked upload requests, as well as delete file requests.

Wrap-up

If you want to try all of this out yourself and take a closer look at the source? You can access all source code for this image uploader example in the fine-uploader-example GitHub repo.

Alertify Your Notifications and Dialogs

This is the first in a series of planned blog posts which will demonstrate how to integrate Fine Uploader along with various external libraries. If you would like to a specific library featured, then open up a feature request with reasons why you think it’d be awesome.

NOTE: This post assumes you are using Fine Uploader 4.x, as some of the syntax, particularly related to templates, changed (for the better) in 4.0. Please see the documentation site for more information.


Today, I’ll demonstrate how you can add a bit of spiff to Fine Uploader’s default UI by overriding the default dialog windows and adding notifications on certain events. Hopefully after reading this, it’ll be simple for you to get your uploader UI from looking like this:

bad-alert-2

To looking like this:

fine-message

We’ll use the alertify.js library to do most of the work for us. Also, we’ll use the latest version of Bootstrap to show how easy it is integrate and really make the uploader a cynosure.

Page Setup

First thing is first, acquire Fine Uploader, and ensure to include it on your page. The following HTML page should serve as a good starting point:

index.html

<!DOCTYPE html>
<html>
    <head>
        <!-- STYLESHEETS
        ========== -->
        <link rel="stylesheet"
              href="assets/vendor/fineuploader-4.0.0/custom.fineuploader-4.0.0.css">
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs/alertify.js/0.3.10/alertify.core.css">
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs/alertify.js/0.3.10/alertify.default.css">
        <link rel="stylesheet" href="assets/css/style.css">

    <!-- TEMPLATE
    ========== -->
    <script type="text/template" id="qq-template">
        <div class="qq-uploader-selector qq-uploader">
            <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
                <span>Drop files here to upload</span>
            </div>
            <div class="qq-upload-button-selector qq-upload-button">
                <div>Upload a file</div>
            </div>
            <span class="qq-drop-processing-selector qq-drop-processing">
                <span>Processing dropped files...</span>
                <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
            </span>
            <ul class="qq-upload-list-selector qq-upload-list">
                <li>
                    <div class="qq-progress-bar-container-selector">
                        <div class="qq-progress-bar-selector qq-progress-bar"></div>
                    </div>
                    <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                    <span class="qq-edit-filename-icon-selector qq-edit-filename-icon"></span>
                    <span class="qq-upload-file-selector qq-upload-file"></span>
                    <input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
                    <span class="qq-upload-size-selector qq-upload-size"></span>
                    <a class="qq-upload-cancel-selector qq-upload-cancel" href="#">Cancel</a>
                    <a class="qq-upload-retry-selector qq-upload-retry" href="#">Retry</a>
                    <a class="qq-upload-delete-selector qq-upload-delete" href="#">Delete</a>
                    <span class="qq-upload-status-text-selector qq-upload-status-text"></span>
                </li>
            </ul>
        </div>
    </script>
    </head>
    <body>

        <div class="container">
            <div id="uploader">
            </div>
        </div> <!-- /container -->

        <!-- JAVASCRIPTS
        ========== -->
        <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/alertify.js/0.3.10/alertify.min.js"></script>
        <script src="assets/vendor/fineuploader-4.0.0/custom.fineuploader-4.0.0.js"></script>
        <script src="assets/js/main.js"></script>

    </body>
</html>

main.js

var options = {
  element: $("#uploader"),
  request: {
    endpoint: '/upload/receiver'
  },
  showMessage: function(message) {},
    showConfirm: function(message) {},
  showPrompt: function(message, defaultValue) {}
};

$(document).ready(function() {
    alertify.set({ delay: 10000 }); // delay log alerts for 10 seconds

    $("#uploader").fineUploader(options);
  });

Fine Uploader UI mode, by default, displays three kinds of modal dialogs: prompts, messages, and confirms. These dialogs are implemented with window.prompt, window.alert, and window.confirm, respectively. If you have ever seen these dialogs you know their appearance is unprofessional and implemented differently on different browsers. With alertify, Fine Uploader, and a few lines of code we can unify the appearance of dialogs and improve their look and feel.

Notification Station

Users like it when the page responds to their actions with visual cues. Let’s say we would like to show a notification to the user when an upload completes or fails, and if it fails we want the reason to be shown to the user. With Fine Uploader’s events we can hook in almost any logic we want at the moment something happens (whatever that something may be). For this, we’ll need to provide custom callbacks that will display a proper message for the complete and error events.

$("#uploader")
    .on('complete', function (event, fileId, fileName, responseJSON, xhr) {
        if (responseJSON.success === true) {
            alertify.success("Successfully uploaded: " + fileName, "", 0);
        } else {
            alertify.error("Error: " + error);
        }               
    });

Now, when a user successfully uploads a file they’ll get a notification like so:

success-notification

And when the uploader has a problem uploading, there will be a notification message showing exactly what went wrong:

failure-notification

‘Alert!’

Fine Uploader UI will issue a window.alert the moment one of its validators detects some sort of issue with a file that has been submitted.

Before we override this show method, let’s set up a simple validator that will stop the user from uploading more than 3 files. (Note that you can set up all sorts of validators see the docs, but this one is kept trivial for demonstration purposes.

var options = {
  element: $("#uploader"),
  request: {
    endpoint: '/upload/receiver'
  },
  validation: {
      itemLimit: 3 // Disallow >3 submitted files
  },
  showMessage: function(message) {},
  showConfirm: function(message) {},
  showPrompt: function(message, defaultValue) {}
};

Alright, so now when a user drops 4 or more files a window.alert will pop up like so:

bad-alert-2

That’s not pretty, and we want pretty. Provide a new callback to the showMessage option which will instead display our own message via alertify:

showMessage: function (message) {
    return alertify.alert(message);
},

fine-message

Woah, that is hella better. It’s like a breath of fresh air. Onward!

Please confirm …

Sometimes Fine Uploader UI needs confirmation from the user that it is safe to continue with the operation it is about to perform. For example, if the deleteFile.confirmMessage option is true then Fine Uploader will display a confirmation dialog to the user to ensure that it is safe to delete the corresponding file.

First, enable the delete feature in Fine Uploader and on your server:

var options = {
  element: $("#uploader"),
  request: {
    endpoint: '/upload/receiver'
  },
  validation: {
      itemLimit: 3
  },
  deleteFile: {
      enabled: true, // turn the delete file feature on
      forceConfirm: true // enable FU confirming with the user that they want to proceed with delete
  },  
  showMessage: function (message) {
      return alertify.alert(message);
  },
  showConfirm: function(message) {},
  showPrompt: function(message, defaultValue) {}
};

Now, when the user presses ‘Delete’ next to a successfully uploaded file, they’ll see a confirmation dialog:

bad-confirm

We can completely customize this dialog very easily with alertify. All we have to do is provide a promissory function as the value of the showConfirm option.

showConfirm: function (message) {
    var promise;
    promise = new qq.Promise();
    alertify.confirm(message, function(result) {
      if (result) {
        return promise.success(result);
      } else {
        return promise.failure();
      }
    });
    return promise; 
}

And with 10 lines of code, we have a spiffy looking confirmation dialog (well, at least one that’s waaay better than window.confirm).

fine-confirm

PRO-mpting

The last dialog function in Fine Uploader’s repertoire is showPrompt.
A prompt is useful when you want to query the user for some information (e.g., a custom filename). There is only one instance where Fine Uploader makes use of prompts, but it’ s a necessary one. Fine Uploader has support for submitting images via the ClipboardAPI. The ClipboardAPI is young, though, and does not yet have the ability to grab the filename from the submitted file. If paste is enabled in Fine Uploader, and promptForName is true then the user will be prompted for a filename to enter before Fine Uploader begins processing.

So first, enable the paste feature:

var options = {
  element: $("#uploader"),
  request: {
    endpoint: '/upload/receiver'
  },
  validation: {
      itemLimit: 3
  },
  deleteFile: {
      forceConfirm: true,

  },  
  paste: {
      promptForName: true, // enabling prompting for filename on paste received
      targetElement $(document) // set the paste target element to be the entire web page
  },
  showMessage: function (message) {
    return alertify.alert(message);
  },
  showConfirm: function (message) {
    var promise;
    promise = new qq.Promise();
    alertify.confirm(message, function(result) {
      if (result) {
        return promise.success(result);
      } else {
        return promise.failure();
      }
    });
    return promise; 
  },
  showPrompt: function(message, defaultValue) {},
};

bad-prompt

showPrompt: function(message, defaultValue) {
  promise = new qq.Promise()
  alertify.prompt(message, (result, inStr) ->
    if result
      promise.success(inStr)
    else
      promise.failure(inStr)
  , defaultValue)
  return promise
},

fine-prompt

Making Promises

You may have noticed the use of the qq.Promise() throughout this code. When showConfirm or showPrompt return a qq.Promise() Fine Uploader will internally hold of on executing code until immediately after the promise is fulfilled.

For example, showConfirm will be called the moment the user clicks the “delete” button for an uploaded file. If the promise is successful (i.e., promise.success() fulfills the promise), then the delete request is submitted. If the promise is a failure (i.e., promise.failure() fulfills the promise), then the delete request is not submitted.

This is a huge win because the UI thread will continue running while the app is waiting for the user’s confirmation.

This Time With More Style

Why stop now. Let’s keep adding some style tweaks (mostly because they bug me). Throw Bootstrap in there! Hack some CSS! Have some fun! I’ve provided the complete example I used to cook up this tutorial below, hopefully someone finds it useful.

First, add bootstrap to your already set up page:

<link rel="stylesheet"
      href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0-rc2/css/bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/js/bootstrap.min.js"></script>

Include a modified template in your document, based off of the bundled default template:

<script type="text/template" id="qq-template">
    <div class="qq-uploader-selector qq-uploader col-lg-12">
        <pre class="qq-upload-drop-area-selector qq-upload-drop-area col-lg-12" qq-hide-dropzone>
            <span>Drop files here to upload</span>
        </pre>
        <div class="qq-upload-button-selector btn btn-success">
            <div>Upload a file</div>
        </div>
        <span class="qq-drop-processing-selector qq-drop-processing">
            <span>Processing dropped files...</span>
            <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
        </span>
        <ul class="qq-upload-list-selector qq-upload-list list-group">
            <li>
                <div class="qq-progress-bar-container-selector progress">
                    <div class="qq-progress-bar-selector bar"></div>
                </div>
                <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                <span class="qq-upload-file-selector qq-upload-file"></span>
                <span class="qq-upload-size-selector qq-upload-size"></span>
                <a class="qq-upload-delete-selector btn" href="#">Delete</a>
                <span class="qq-upload-status-text-selector qq-upload-status-text"></span>
            </li>
        </ul>
    </div>
</script>

Add some custom styles to your own stylesheet:

style.css

.qq-upload-list {
  margin-top: 7px;
  text-align: left;
}
.qq-upload-list > li {
  margin-top: 3px;
}
.qq-drop-area {
  min-height: 200px;
}
.alert-error .qq-upload-failed-text {
  display: inline;
}

And add the corresponding classes to Fine Uploader’s classes option:

classes: {
    success: 'alert alert-success list-group-item',
    fail: 'alert alert-error list-group-item'
}

We can also modify many of the messages that are used in the prompts we’ve customized. Let’s change the default delete message by changing the confirmMessage property on the delete option we created earlier:

deleteFile: {
  enabled: true,
  confirmMessage: 'Send <code>{filename}</code>; into the abyss?',
  forceConfirm: true
},

The Final Product

This is probably what you’ve been waiting for. Below is the entire HTML, CSS, JS code that I used to create everything above. Happy hacking!

index.html

<!DOCTYPE html>
<html>
    <head>
        <!-- STYLESHEETS
        ========== -->
        <link rel="stylesheet"
              href="assets/vendor/fineuploader-4.0.0/custom.fineuploader-4.0.0.css">
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0-rc2/css/bootstrap.min.css">
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs/alertify.js/0.3.10/alertify.core.css">
        <link rel="stylesheet"
              href="//cdnjs.cloudflare.com/ajax/libs/alertify.js/0.3.10/alertify.default.css">
        <style>
            body {
                padding-top: 60px;
                padding-bottom: 40px;
            }
        </style>
        <link rel="stylesheet" href="assets/css/style.css">

        <script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js"></script>
    <script type="text/template" id="qq-template">
        <div class="qq-uploader-selector qq-uploader col-lg-12">
            <pre class="qq-upload-drop-area-selector qq-upload-drop-area col-lg-12" qq-hide-dropzone>
                <span>Drop files here to upload</span>
            </pre>
            <div class="qq-upload-button-selector btn btn-success">
                <div>Upload</div>
            </div>
            <span class="qq-drop-processing-selector qq-drop-processing">
                <span>Processing dropped files...</span>
                <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
            </span>
            <ul class="qq-upload-list-selector qq-upload-list list-group">
                <li>
                    <div class="qq-progress-bar-container-selector progress">
                        <div class="qq-progress-bar-selector bar"></div>
                    </div>
                    <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                    <span class="qq-upload-file-selector qq-upload-file"></span>
                    <span class="qq-upload-size-selector qq-upload-size"></span>
                    <a class="qq-upload-delete-selector btn" href="#">Delete</a>
                    <span class="qq-upload-status-text-selector qq-upload-status-text"></span>
                </li>
            </ul>
        </div>
    </script>
    </head>
    <body>

        <div class="container">
            <div id="uploader">
            </div>
        </div> <!-- /container -->

        <!-- JAVASCRIPTS
        ========== -->
        <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.0.0/js/bootstrap.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/alertify.js/0.3.10/alertify.min.js"></script>
        <!--
        <script src="assets/vendor/bootbox.min.js"></script>
        -->
        <script src="assets/vendor/fineuploader-4.0.0/custom.fineuploader-4.0.0.js"></script>
        <script src="assets/js/main.js"></script>

    </body>
</html>

style.css

.qq-upload-list {
  margin-top: 7px;
  text-align: left;
}
.qq-upload-list > li {
  margin-top: 3px;
}
.qq-drop-area {
  min-height: 200px;
}
.alert-error .qq-upload-failed-text {
  display: inline;
}

main.js

  var options = {
    debug: true,
    element: $("#uploader"),
    deleteFile: {
      enabled: true,
      confirmMessage: 'Send <code>{filename}</code> into the abyss?',
      forceConfirm: true
    },
    template: template,
    classes: {
      success: 'alert alert-success list-group-item',
      fail: 'alert alert-error list-group-item'
    },
    validation: {
      itemLimit: 3
    },
    paste: {
      promptForName: true,
      targetElement: $(window.document)
    },
    showMessage: function(message) {
      return alertify.alert(message);
    },
    showPrompt: function(message, defaultValue) {
      var promise;
      promise = new qq.Promise();
      alertify.prompt(message, function(result, inStr) {
        if (result) {
          return promise.success(inStr);
        } else {
          return promise.failure(inStr);
        }
      }, defaultValue);
      return promise;
    },
    showConfirm: function(message) {
      var promise;
      promise = new qq.Promise();
      alertify.confirm(message, function(result) {
        if (result) {
          return promise.success(result);
        } else {
          return promise.failure();
        }
      });
      return promise;
    }
  };

  $(document).ready(function() {
    alertify.set({
      delay: 10000
    });
    return $("#uploader").fineUploader(options).on('complete', function(event, fileId, fileName, responseJSON, xhr) {
      if (responseJSON.success != null) {
        return alertify.success("Successfully uploaded: <code>" + fileName + "</code>", "", 0);
      }
    }).on('error', function(event, fileId, fileName, error, xhr) {
      return alertify.error("Error: " + error);
    });
  });

Other Libraries

Of course, we aren’t limited to using alertify, we could hook in any other sort of prompting library we wanted. Other alternatives include Bootbox.js, Bootstrap’s modal.js, and much more.

If you think you’ve created something neat, share it on GitHub and/or send us a screenshot, we’re always looking for ideas and cutting-edge uses of Fine Uploader.