[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / plugins-dist / medias / javascript / jquery.multifile.js
index f14ca9d..4230dfe 100644 (file)
@@ -1,11 +1,9 @@
 /*
- ### jQuery Multiple File Upload Plugin v1.31 - 2009-01-17 ###
+ ### jQuery Multiple File Upload Plugin v1.48 - 2013-02-19 ###
  * Home: http://www.fyneworks.com/jquery/multiple-file-upload/
  * Code: http://code.google.com/p/jquery-multifile-plugin/
  *
- * Dual licensed under the MIT and GPL licenses:
- *   http://www.opensource.org/licenses/mit-license.php
- *   http://www.gnu.org/licenses/gpl.html
+       * Licensed under http://en.wikipedia.org/wiki/MIT_License
  ###
 */
 
 ;if(window.jQuery) (function($){
 /*# AVOID COLLISIONS #*/
  
- // extend jQuery - $.MultiFile hook
- $.extend($, {
-  MultiFile: function( o /* Object */ ){
-   //return $("INPUT[type='file'].multi").MultiFile(o);
-   return $("input:file.multi").MultiFile(o);
-  }
- });
- //===
- // extend $.MultiFile - default options
- $.extend($.MultiFile, {
-  options: {
-   accept: '', max: -1,
-   // error handling function
-   error: function(s){
-    if($.blockUI){
-     $.blockUI({
-      message: s.replace(/\n/gi,'<br/>'),
-      css: { 
-       border:'none', padding:'15px', size:'12.0pt',
-       backgroundColor:'#900', color:'#fff',
-       opacity:'.8','-webkit-border-radius': '10px','-moz-border-radius': '10px'
-      }
-     });
-     window.setTimeout($.unblockUI, 2000);
-    }
-    else{
-     alert(s);
-    }
-   },
-   // namePattern: $name/$id (from master element), $i (slave count), $g (group count)
-   namePattern: '$name',
-   // STRING: collection lets you show messages in different languages
-   STRING: {
-    remove:'x',
-    denied:'You cannot select a $ext file.\nTry again...',
-    file:'$file',
-    selected:'File selected: $file',
-    duplicate:'This file has already been selected:\n$file'
-   }
-  }
- });
- //===
- // extend $.MultiFile - global methods
- $.extend($.MultiFile, {
-  
-  
-  /**
-   * This utility makes it easy to disable all 'empty' file elements in the document before submitting a form.
-   * It marks the affected elements so they can be easily re-enabled after the form submission or validation.
-   *
-   * Returns a jQuery collection of all affected elements.
-   *
-   * @name disableEmpty
-   * @type jQuery
-   * @cat Plugins/Multifile
-   * @author Diego A. (http://www.fyneworks.com/)
-   *
-   * @example $.MultiFile.disableEmpty();
-   * @param String class (optional) A string specifying a class to be applied to all affected elements - Default: 'mfD'.
-   */
-  disableEmpty: function(klass){
-   var o = [];
-   $('input:file').each(function(){ if($(this).val()=='') o[o.length] = this; });
-   return $(o).each(function(){ this.disabled = true }).addClass(klass || 'mfD');
-  },
-  
-  
- /**
-  * This method re-enables 'empty' file elements that were disabled (and marked) with the $.MultiFile.disableEmpty method.
-  *
-  * Returns a jQuery collection of all affected elements.
-  *
-  * @name reEnableEmpty
-  * @type jQuery
-  * @cat Plugins/Multifile
-  * @author Diego A. (http://www.fyneworks.com/)
-  *
-  * @example $.MultiFile.reEnableEmpty();
-  * @param String klass (optional) A string specifying the class that was used to mark affected elements - Default: 'mfD'.
-  */
-  reEnableEmpty: function(klass){
-   klass = klass || 'mfD';
-   return $('input:file.'+klass).removeClass(klass).each(function(){ this.disabled = false });
-  },
-  
-  
- /**
-  * This method will intercept other jQuery plugins and disable empty file input elements prior to form submission
-  *
-  * @name intercept
-  * @cat Plugins/Multifile
-  * @author Diego A. (http://www.fyneworks.com/)
-  *
-  * @example $.MultiFile.intercept();
-  * @param Array methods (optional) Array of method names to be intercepted
-  */
-  autoIntercept: [ 'submit', 'ajaxSubmit', 'validate' /* array of methods to intercept */ ],
-  intercepted: {},
-  intercept: function(methods, context, args){
-   var method, value; args = args || [];
-   if(args.constructor.toString().indexOf("Array")<0) args = [ args ];
-   if(typeof(methods)=='function'){
-    $.MultiFile.disableEmpty();
-    value = methods.apply(context || window, args);
-    $.MultiFile.reEnableEmpty();
-    return value;
-   };
-   if(methods.constructor.toString().indexOf("Array")<0) methods = [methods];
-   for(var i=0;i<methods.length;i++){
-    method = methods[i]+''; // make sure that we have a STRING
-    if(method) (function(method){ // make sure that method is ISOLATED for the interception
-     $.MultiFile.intercepted[method] = $.fn[method] || function(){};
-     $.fn[method] = function(){
-      $.MultiFile.disableEmpty();
-      value = $.MultiFile.intercepted[method].apply(this, arguments);
-      $.MultiFile.reEnableEmpty();
-      return value;
-     }; // interception
-    })(method); // MAKE SURE THAT method IS ISOLATED for the interception
-   };// for each method
-  }
- });
- //===
- // extend jQuery function library
- $.extend($.fn, {
-   
-                       // Use this function to clear values of file inputs
-                       // But this doesn't always work: $(element).val('').attr('value', '')[0].value = '';
-                       reset: function(){ return this.each(function(){ try{ this.reset(); }catch(e){} }); },
-    
-   // MultiFile function
-   MultiFile: function( options /* Object */ ){
-    
-    //### http://plugins.jquery.com/node/1363
-    // utility method to integrate this plugin with others...
-    if($.MultiFile.autoIntercept){
-     $.MultiFile.intercept( $.MultiFile.autoIntercept /* array of methods to intercept */ );
-     $.MultiFile.autoIntercept = null; /* only run this once */
-    };
-    
-    //===
-    
-    // Bind to each element in current jQuery object
-    return $(this).each(function(group_count){
-     if(this._MultiFile) return; this._MultiFile = true;
-     
+       // plugin initialization
+       $.fn.MultiFile = function(options){
+               if(this.length==0) return this; // quick fail
+               
+               // Handle API methods
+               if(typeof arguments[0]=='string'){
+                       // Perform API methods on individual elements
+                       if(this.length>1){
+                               var args = arguments;
+                               return this.each(function(){
+                                       $.fn.MultiFile.apply($(this), args);
+    });
+                       };
+                       // Invoke API method handler
+                       $.fn.MultiFile[arguments[0]].apply(this, $.makeArray(arguments).slice(1) || []);
+                       // Quick exit...
+                       return this;
+               };
+               
+               // Initialize options for this call
+               var options = $.extend(
+                       {}/* new object */,
+                       $.fn.MultiFile.options/* default options */,
+                       options || {} /* just-in-time options */
+               );
+               
+               // Empty Element Fix!!!
+               // this code will automatically intercept native form submissions
+               // and disable empty file elements
+               $('form')
+               .not('MultiFile-intercepted')
+               .addClass('MultiFile-intercepted')
+               .submit($.fn.MultiFile.disableEmpty);
+               
+               //### http://plugins.jquery.com/node/1363
+               // utility method to integrate this plugin with others...
+               if($.fn.MultiFile.options.autoIntercept){
+                       $.fn.MultiFile.intercept( $.fn.MultiFile.options.autoIntercept /* array of methods to intercept */ );
+                       $.fn.MultiFile.options.autoIntercept = null; /* only run this once */
+               };
+               
+               // loop through each matched element
+               this
+                .not('.MultiFile-applied')
+                       .addClass('MultiFile-applied')
+               .each(function(){
+                       //#####################################################################
+                       // MAIN PLUGIN FUNCTIONALITY - START
+                       //#####################################################################
+                       
        // BUG 1251 FIX: http://plugins.jquery.com/project/comments/add/1251
        // variable group_count would repeat itself on multiple calls to the plugin.
        // this would cause a conflict with multiple elements
        // changes scope of variable to global so id will be unique over n calls
        window.MultiFile = (window.MultiFile || 0) + 1;
-       group_count = window.MultiFile;
+       var group_count = window.MultiFile;
        
        // Copy parent attributes - Thanks to Jonas Wagner
        // we will use this one to create new input elements
-       var MF = {e:this, E:$(this), clone:$(this).clone()};
+       var MultiFile = {e:this, E:$(this), clone:$(this).clone()};
        
        //===
        
        //# USE CONFIGURATION
        if(typeof options=='number') options = {max:options};
-       if(typeof options=='string') options = {accept:options};
        var o = $.extend({},
-        $.MultiFile.options,
+        $.fn.MultiFile.options,
         options || {},
-        ($.meta ? MF.E.data()/*NEW metadata plugin*/ :
-        ($.metadata ? MF.E.metadata()/*OLD metadata plugin*/ : 
-        null/*metadata plugin not available*/)) || {}
+                                       ($.metadata? MultiFile.E.metadata(): ($.meta?MultiFile.E.data():null)) || {}, /* metadata options */
+                                                               {} /* internals */
        );
        // limit number of files that can be selected?
-       if(!(o.max>0) /*IsNull(MF.max)*/){
-        o.max = MF.E.attr('maxlength');
-        if(!(o.max>0) /*IsNull(MF.max)*/){
-         o.max = (String(MF.e.className.match(/\b(max|limit)\-([0-9]+)\b/gi) || ['']).match(/[0-9]+/gi) || [''])[0];
-         if(!(o.max>0)) o.max = -1;
-         else           o.max = String(o.max).match(/[0-9]+/gi)[0];
-        }
+       if(!(o.max>0) /*IsNull(MultiFile.max)*/){
+        o.max = MultiFile.E.attr('maxlength');
        };
+                                                       if(!(o.max>0) /*IsNull(MultiFile.max)*/){
+                                                               o.max = (String(MultiFile.e.className.match(/\b(max|limit)\-([0-9]+)\b/gi) || ['']).match(/[0-9]+/gi) || [''])[0];
+                                                               if(!(o.max>0)) o.max = -1;
+                                                               else           o.max = String(o.max).match(/[0-9]+/gi)[0];
+                                                       }
        o.max = new Number(o.max);
        // limit extensions?
-       o.accept = o.accept || MF.E.attr('accept') || '';
+       o.accept = o.accept || MultiFile.E.attr('accept') || '';
        if(!o.accept){
-        o.accept = (MF.e.className.match(/\b(accept\-[\w\|]+)\b/gi)) || '';
+        o.accept = (MultiFile.e.className.match(/\b(accept\-[\w\|]+)\b/gi)) || '';
         o.accept = new String(o.accept).replace(/^(accept|ext)\-/i,'');
        };
        
        //===
        
        // APPLY CONFIGURATION
-       $.extend(MF, o || {});
-       MF.STRING = $.extend({},$.MultiFile.options.STRING,MF.STRING);
+                                                       $.extend(MultiFile, o || {});
+       MultiFile.STRING = $.extend({},$.fn.MultiFile.options.STRING,MultiFile.STRING);
        
        //===
        
        //#########################################
        // PRIVATE PROPERTIES/METHODS
-       $.extend(MF, {
+       $.extend(MultiFile, {
         n: 0, // How many elements are currently selected?
         slaves: [], files: [],
-        instanceKey: MF.e.id || 'MultiFile'+String(group_count), // Instance Key?
-        generateID: function(z){ return MF.instanceKey + (z>0 ?'_F'+String(z):''); },
+        instanceKey: MultiFile.e.id || 'MultiFile'+String(group_count), // Instance Key?
+        generateID: function(z){ return MultiFile.instanceKey + (z>0 ?'_F'+String(z):''); },
         trigger: function(event, element){
-         var handler = MF[event], value = $(element).attr('value');
+         var handler = MultiFile[event], value = $(element).attr('value');
          if(handler){
-          var returnValue = handler(element, value, MF);
+          var returnValue = handler(element, value, MultiFile);
           if( returnValue!=null ) return returnValue;
          }
          return true;
        
        // Setup dynamic regular expression for extension validation
        // - thanks to John-Paul Bader: http://smyck.de/2006/08/11/javascript-dynamic-regular-expresions/
-       if(String(MF.accept).length>1){
-        MF.rxAccept = new RegExp('\\.('+(MF.accept?MF.accept:'')+')$','gi');
+       if(String(MultiFile.accept).length>1){
+                                                               MultiFile.accept = MultiFile.accept.replace(/\W+/g,'|').replace(/^\W|\W$/g,'');
+        MultiFile.rxAccept = new RegExp('\\.('+(MultiFile.accept?MultiFile.accept:'')+')$','gi');
        };
        
        //===
        
        // Create wrapper to hold our file list
-       MF.wrapID = MF.instanceKey+'_wrap'; // Wrapper ID?
-       MF.E.wrap('<div id="'+MF.wrapID+'"></div>');
-       MF.wrapper = $('#'+MF.wrapID+'');
+       MultiFile.wrapID = MultiFile.instanceKey+'_wrap'; // Wrapper ID?
+       MultiFile.E.wrap('<div class="MultiFile-wrap" id="'+MultiFile.wrapID+'"></div>');
+       MultiFile.wrapper = $('#'+MultiFile.wrapID+'');
        
        //===
        
-       // MF MUST have a name - default: file1[], file2[], file3[]
-       MF.e.name = MF.e.name || 'file'+ group_count +'[]';
+       // MultiFile MUST have a name - default: file1[], file2[], file3[]
+       MultiFile.e.name = MultiFile.e.name || 'file'+ group_count +'[]';
        
        //===
        
-                                                       if(!MF.list){
+                                                       if(!MultiFile.list){
                                                                // Create a wrapper for the list
                                                                // * OPERA BUG: NO_MODIFICATION_ALLOWED_ERR ('list' is a read-only property)
                                                                // this change allows us to keep the files in the order they were selected
-                                                               MF.wrapper.append( '<span id="'+MF.wrapID+'_list"></span>' );
-                                                               MF.list = $('#'+MF.wrapID+'_list');
+                                                               MultiFile.wrapper.append( '<div class="MultiFile-list" id="'+MultiFile.wrapID+'_list"></div>' );
+                                                               MultiFile.list = $('#'+MultiFile.wrapID+'_list');
                                                        };
-       MF.list = $(MF.list);
+       MultiFile.list = $(MultiFile.list);
                                                        
        //===
        
        // Bind a new element
-       MF.addSlave = function( slave, slave_count ){
+       MultiFile.addSlave = function( slave, slave_count ){
+                                                               //if(window.console) console.log('MultiFile.addSlave',slave_count);
+                                                               
         // Keep track of how many elements have been displayed
-        MF.n++;
+        MultiFile.n++;
         // Add reference to master element
-        slave.MF = MF;
-        // Count slaves
-        slave.i = slave_count;
-        
-        // BUG FIX: http://plugins.jquery.com/node/1495
-        // Clear identifying properties from clones
-        if(slave.i>0) slave.id = slave.name = null;
-        
+        slave.MultiFile = MultiFile;
+                                                               
+                                                               // BUG FIX: http://plugins.jquery.com/node/1495
+                                                               // Clear identifying properties from clones
+                                                               if(slave_count>0) slave.id = slave.name = '';
+                                                               
         // Define element's ID and name (upload components need this!)
-        slave.id = slave.id || MF.generateID(slave.i);
+        //slave.id = slave.id || MultiFile.generateID(slave_count);
+                                                               if(slave_count>0) slave.id = MultiFile.generateID(slave_count);
+                                                               //FIX for: http://code.google.com/p/jquery-multifile-plugin/issues/detail?id=23
         
-        //slave.name = (slave.name || MF.E.attr('name') || 'file');// + (slave.i>0?slave.i:''); // same name as master element
         // 2008-Apr-29: New customizable naming convention (see url below)
         // http://groups.google.com/group/jquery-dev/browse_frm/thread/765c73e41b34f924#
-        slave.name = String(MF.namePattern
-         /*master name*/.replace(/\$name/gi,MF.E.attr('name'))
-         /*master id  */.replace(/\$id/gi,  MF.E.attr('id'))
-         /*group count*/.replace(/\$g/gi,   (group_count>0?group_count:''))
-         /*slave count*/.replace(/\$i/gi,   (slave_count>0?slave_count:''))
+        slave.name = String(MultiFile.namePattern
+         /*master name*/.replace(/\$name/gi,$(MultiFile.clone).attr('name'))
+         /*master id  */.replace(/\$id/gi,  $(MultiFile.clone).attr('id'))
+         /*group count*/.replace(/\$g/gi,   group_count)//(group_count>0?group_count:''))
+         /*slave count*/.replace(/\$i/gi,   slave_count)//(slave_count>0?slave_count:''))
         );
         
-        // Clear value
-        $(slave).val('').attr('value','')[0].value = '';
-        
         // If we've reached maximum number, disable input slave
-        if( (MF.max > 0) && ((MF.n-1) > (MF.max)) )//{ // MF.n Starts at 1, so subtract 1 to find true count
+        if( (MultiFile.max > 0) && ((MultiFile.n-1) > (MultiFile.max)) )//{ // MultiFile.n Starts at 1, so subtract 1 to find true count
          slave.disabled = true;
         //};
         
         // Remember most recent slave
-        MF.current = MF.slaves[slave.i] = slave;
+        MultiFile.current = MultiFile.slaves[slave_count] = slave;
         
-        // now let's use jQuery
-        slave = $(slave);
+                                                               // We'll use jQuery from now on
+                                                               slave = $(slave);
         
+        // Clear value
+        slave.val('').attr('value','')[0].value = '';
+        
+                                                               // Stop plugin initializing on slaves
+                                                               slave.addClass('MultiFile-applied');
+                                                               
         // Triggered when a file is selected
-        $(slave).change(function(){
-          
+        slave.change(function(){
+          //if(window.console) console.log('MultiFile.slave.change',slave_count);
+                                                                
           // Lose focus to stop IE7 firing onchange again
           $(this).blur();
           
           //# Trigger Event! onFileSelect
-          if(!MF.trigger('onFileSelect', this, MF)) return false;
+          if(!MultiFile.trigger('onFileSelect', this, MultiFile)) return false;
           //# End Event!
           
           //# Retrive value of selected file from element
           var ERROR = '', v = String(this.value || ''/*.attr('value)*/);
           
           // check extension
-          if(MF.accept && v && !v.match(MF.rxAccept))//{
-            ERROR = MF.STRING.denied.replace('$ext', String(v.match(/\.\w{1,4}$/gi)));
+          if(MultiFile.accept && v && !v.match(MultiFile.rxAccept))//{
+            ERROR = MultiFile.STRING.denied.replace('$ext', String(v.match(/\.\w{1,4}$/gi)));
            //}
           //};
           
           // Disallow duplicates
-                                                                               for(var f in MF.slaves)//{
-           if(MF.slaves[f] && MF.slaves[f]!=this)//{
-                                                                               //console.log(MF.slaves[f],MF.slaves[f].value);
-            if(MF.slaves[f].value==v)//{
-             ERROR = MF.STRING.duplicate.replace('$file', v.match(/[^\/\\]+$/gi));
+                                                                               for(var f in MultiFile.slaves)//{
+           if(MultiFile.slaves[f] && MultiFile.slaves[f]!=this)//{
+                                                                               //console.log(MultiFile.slaves[f],MultiFile.slaves[f].value);
+            if(MultiFile.slaves[f].value==v)//{
+             ERROR = MultiFile.STRING.duplicate.replace('$file', v.match(/[^\/\\]+$/gi));
             //};
            //};
           //};
           
           // Create a new file input element
-          //var newEle = $('<input name="'+(MF.E.attr('name') || '')+'" type="file"/>');
-          var newEle = $(MF.clone).clone();// Copy parent attributes - Thanks to Jonas Wagner
+          var newEle = $(MultiFile.clone).clone();// Copy parent attributes - Thanks to Jonas Wagner
           //# Let's remember which input we've generated so
           // we can disable the empty ones before submission
           // See: http://plugins.jquery.com/node/1495
           // Handle error
           if(ERROR!=''){
             // Handle error
-            MF.error(ERROR);
-            
-            // Clear element value (DOES NOT WORK in some browsers)
-            //slave.reset().val('').attr('value', '')[0].value = '';
-            
+            MultiFile.error(ERROR);
+                                                                                               
             // 2007-06-24: BUG FIX - Thanks to Adrian Wróbel <adrian [dot] wrobel [at] gmail.com>
             // Ditch the trouble maker and add a fresh new element
-            MF.n--;
-            MF.addSlave(newEle[0], this.i);
-            MF.list.before(newEle);//slave.parent().prepend(newEle);
+            MultiFile.n--;
+            MultiFile.addSlave(newEle[0], slave_count);
+            slave.parent().prepend(newEle);
             slave.remove();
             return false;
           };
           $(this).css({ position:'absolute', top: '-3000px' });
           
           // Add new element to the form
-          MF.list.before(newEle);//.append(newEle);
-          //MF.wrapper.prepend(newEle);//.append(newEle);
+          slave.after(newEle);
           
           // Update list
-          MF.addToList( this );
+          MultiFile.addToList( this, slave_count );
           
           // Bind functionality
-          MF.addSlave( newEle[0], this.i+1 );
+          MultiFile.addSlave( newEle[0], slave_count+1 );
           
           //# Trigger Event! afterFileSelect
-          if(!MF.trigger('afterFileSelect', this, MF)) return false;
+          if(!MultiFile.trigger('afterFileSelect', this, MultiFile)) return false;
           //# End Event!
           
         }); // slave.change()
-        
-       };// MF.addSlave
+                                                               
+                                                               // Save control to element
+                                                               $(slave).data('MultiFile', MultiFile);
+                                                               
+       };// MultiFile.addSlave
        // Bind a new element
        
        
        
        // Add a new file to the list
-       MF.addToList = function( slave ){
-        
+       MultiFile.addToList = function( slave, slave_count ){
+        //if(window.console) console.log('MultiFile.addToList',slave_count);
+                                                               
         //# Trigger Event! onFileAppend
-        if(!MF.trigger('onFileAppend', slave, MF)) return false;
+        if(!MultiFile.trigger('onFileAppend', slave, MultiFile)) return false;
         //# End Event!
         
         // Create label elements
         var
-         r = $('<div></div>'),
+         r = $('<div class="MultiFile-label"></div>'),
          v = String(slave.value || ''/*.attr('value)*/),
-         a = $('<span class="file" title="'+MF.STRING.selected.replace('$file', v)+'">'+MF.STRING.file.replace('$file', v.match(/[^\/\\]+$/gi)[0])+'</span>'),
-         b = $('<a href="#'+MF.wrapID+'">'+MF.STRING.remove+'</a>');
+         a = $('<span class="MultiFile-title" title="'+MultiFile.STRING.selected.replace('$file', v)+'">'+MultiFile.STRING.file.replace('$file', v.match(/[^\/\\]+$/gi)[0])+'</span>'),
+         b = $('<a class="MultiFile-remove" href="#'+MultiFile.wrapID+'">'+MultiFile.STRING.remove+'</a>');
         
         // Insert label
-        MF.list.append(
-         r.append(b, ' ', a)//.prepend(slave.i+': ')
+        MultiFile.list.append(
+         r.append(b, ' ', a)
         );
         
-        b.click(function(){
+        b
+                                                               .click(function(){
          
           //# Trigger Event! onFileRemove
-          if(!MF.trigger('onFileRemove', slave, MF)) return false;
+          if(!MultiFile.trigger('onFileRemove', slave, MultiFile)) return false;
           //# End Event!
           
-          MF.n--;
-          MF.current.disabled = false;
+          MultiFile.n--;
+          MultiFile.current.disabled = false;
           
           // Remove element, remove label, point to current
-                                                                               MF.slaves[slave.i] = null;
+                                                                               MultiFile.slaves[slave_count] = null;
                                                                                $(slave).remove();
                                                                                $(this).parent().remove();
-          
+                                                                               
           // Show most current element again (move into view) and clear selection
-          $(MF.current).css({ position:'', top: '' });
-                                                                               $(MF.current).reset().val('').attr('value', '')[0].value = '';
+          $(MultiFile.current).css({ position:'', top: '' });
+                                                                               $(MultiFile.current).reset().val('').attr('value', '')[0].value = '';
           
           //# Trigger Event! afterFileRemove
-          if(!MF.trigger('afterFileRemove', slave, MF)) return false;
+          if(!MultiFile.trigger('afterFileRemove', slave, MultiFile)) return false;
           //# End Event!
                                                                                
           return false;
         });
         
         //# Trigger Event! afterFileAppend
-        if(!MF.trigger('afterFileAppend', slave, MF)) return false;
+        if(!MultiFile.trigger('afterFileAppend', slave, MultiFile)) return false;
         //# End Event!
         
-       }; // MF.addToList
+       }; // MultiFile.addToList
        // Add element to selected files list
        
        
        
        // Bind functionality to the first element
-       if(!MF.MF) MF.addSlave(MF.e, 0);
+       if(!MultiFile.MultiFile) MultiFile.addSlave(MultiFile.e, 0);
        
        // Increment control count
-       //MF.I++; // using window.MultiFile
-       MF.n++;
-       
-    });
-    // each element
-   
-   }
-   // MultiFile function
+       //MultiFile.I++; // using window.MultiFile
+       MultiFile.n++;
+                                                       
+                                                       // Save control to element
+                                                       MultiFile.E.data('MultiFile', MultiFile);
+                                                       
+
+                       //#####################################################################
+                       // MAIN PLUGIN FUNCTIONALITY - END
+                       //#####################################################################
+               }); // each element
+       };
+       
+       /*--------------------------------------------------------*/
+       
+       /*
+               ### Core functionality and API ###
+       */
+       $.extend($.fn.MultiFile, {
+  /**
+   * This method removes all selected files
+   *
+   * Returns a jQuery collection of all affected elements.
+   *
+   * @name reset
+   * @type jQuery
+   * @cat Plugins/MultiFile
+   * @author Diego A. (http://www.fyneworks.com/)
+   *
+   * @example $.fn.MultiFile.reset();
+   */
+  reset: function(){
+                       var settings = $(this).data('MultiFile');
+                       //if(settings) settings.wrapper.find('a.MultiFile-remove').click();
+                       if(settings) settings.list.find('a.MultiFile-remove').click();
+   return $(this);
+  },
+  
+  
+  /**
+   * This utility makes it easy to disable all 'empty' file elements in the document before submitting a form.
+   * It marks the affected elements so they can be easily re-enabled after the form submission or validation.
+   *
+   * Returns a jQuery collection of all affected elements.
+   *
+   * @name disableEmpty
+   * @type jQuery
+   * @cat Plugins/MultiFile
+   * @author Diego A. (http://www.fyneworks.com/)
+   *
+   * @example $.fn.MultiFile.disableEmpty();
+   * @param String class (optional) A string specifying a class to be applied to all affected elements - Default: 'mfD'.
+   */
+  disableEmpty: function(klass){ klass = (typeof(klass)=='string'?klass:'')||'mfD';
+   var o = [];
+   $('input:file.MultiFile').each(function(){ if($(this).val()=='') o[o.length] = this; });
+   return $(o).each(function(){ this.disabled = true }).addClass(klass);
+  },
+  
+  
+               /**
+                       * This method re-enables 'empty' file elements that were disabled (and marked) with the $.fn.MultiFile.disableEmpty method.
+                       *
+                       * Returns a jQuery collection of all affected elements.
+                       *
+                       * @name reEnableEmpty
+                       * @type jQuery
+                       * @cat Plugins/MultiFile
+                       * @author Diego A. (http://www.fyneworks.com/)
+                       *
+                       * @example $.fn.MultiFile.reEnableEmpty();
+                       * @param String klass (optional) A string specifying the class that was used to mark affected elements - Default: 'mfD'.
+                       */
+  reEnableEmpty: function(klass){ klass = (typeof(klass)=='string'?klass:'')||'mfD';
+   return $('input:file.'+klass).removeClass(klass).each(function(){ this.disabled = false });
+  },
+  
+  
+               /**
+                       * This method will intercept other jQuery plugins and disable empty file input elements prior to form submission
+                       *
+       
+                       * @name intercept
+                       * @cat Plugins/MultiFile
+                       * @author Diego A. (http://www.fyneworks.com/)
+                       *
+                       * @example $.fn.MultiFile.intercept();
+                       * @param Array methods (optional) Array of method names to be intercepted
+                       */
+  intercepted: {},
+  intercept: function(methods, context, args){
+   var method, value; args = args || [];
+   if(args.constructor.toString().indexOf("Array")<0) args = [ args ];
+   if(typeof(methods)=='function'){
+    $.fn.MultiFile.disableEmpty();
+    value = methods.apply(context || window, args);
+                               //SEE-http://code.google.com/p/jquery-multifile-plugin/issues/detail?id=27
+                               setTimeout(function(){ $.fn.MultiFile.reEnableEmpty() },1000);
+    return value;
+   };
+   if(methods.constructor.toString().indexOf("Array")<0) methods = [methods];
+   for(var i=0;i<methods.length;i++){
+    method = methods[i]+''; // make sure that we have a STRING
+    if(method) (function(method){ // make sure that method is ISOLATED for the interception
+     $.fn.MultiFile.intercepted[method] = $.fn[method] || function(){};
+     $.fn[method] = function(){
+      $.fn.MultiFile.disableEmpty();
+      value = $.fn.MultiFile.intercepted[method].apply(this, arguments);
+                                               //SEE http://code.google.com/p/jquery-multifile-plugin/issues/detail?id=27
+      setTimeout(function(){ $.fn.MultiFile.reEnableEmpty() },1000);
+      return value;
+     }; // interception
+    })(method); // MAKE SURE THAT method IS ISOLATED for the interception
+   };// for each method
+  } // $.fn.MultiFile.intercept
+               
  });
- // extend jQuery function library
- /*
-  ### Default implementation ###
-  The plugin will attach itself to file inputs
-  with the class 'multi' when the page loads
- */
- $(function(){ $.MultiFile() });
+       
+       /*--------------------------------------------------------*/
+       
+       /*
+               ### Default Settings ###
+               eg.: You can override default control like this:
+               $.fn.MultiFile.options.accept = 'gif|jpg';
+       */
+       $.fn.MultiFile.options = { //$.extend($.fn.MultiFile, { options: {
+               accept: '', // accepted file extensions
+               max: -1,    // maximum number of selectable files
+               
+               // name to use for newly created elements
+               namePattern: '$name', // same name by default (which creates an array)
+         /*master name*/ // use $name
+         /*master id  */ // use $id
+         /*group count*/ // use $g
+         /*slave count*/ // use $i
+                                                                       /*other      */ // use any combination of he above, eg.: $name_file$i
+               
+               // STRING: collection lets you show messages in different languages
+               STRING: {
+                       remove:'x',
+                       denied:'You cannot select a $ext file.\nTry again...',
+                       file:'$file',
+                       selected:'File selected: $file',
+                       duplicate:'This file has already been selected:\n$file'
+               },
+               
+               // name of methods that should be automcatically intercepted so the plugin can disable
+               // extra file elements that are empty before execution and automatically re-enable them afterwards
+  autoIntercept: [ 'submit', 'ajaxSubmit', 'ajaxForm', 'validate', 'valid' /* array of methods to intercept */ ],
+               
+               // error handling function
+               error: function(s){
+                       /*
+                       ERROR! blockUI is not currently working in IE
+                       if($.blockUI){
+                               $.blockUI({
+                                       message: s.replace(/\n/gi,'<br/>'),
+                                       css: { 
+                                               border:'none', padding:'15px', size:'12.0pt',
+                                               backgroundColor:'#900', color:'#fff',
+                                               opacity:'.8','-webkit-border-radius': '10px','-moz-border-radius': '10px'
+                                       }
+                               });
+                               window.setTimeout($.unblockUI, 2000);
+                       }
+                       else//{// save a byte!
+                       */
+                        alert(s);
+                       //}// save a byte!
+               }
+ }; //} });
+       
+       /*--------------------------------------------------------*/
+       
+       /*
+               ### Additional Methods ###
+               Required functionality outside the plugin's scope
+       */
+       
+       // Native input reset method - because this alone doesn't always work: $(element).val('').attr('value', '')[0].value = '';
+       $.fn.reset = function(){ return this.each(function(){ try{ this.reset(); }catch(e){} }); };
+       
+       /*--------------------------------------------------------*/
+       
+       /*
+               ### Default implementation ###
+               The plugin will attach itself to file inputs
+               with the class 'multi' when the page loads
+       */
+       $(function(){
+  //$("input:file.multi").MultiFile();
+  $("input[type=file].multi").MultiFile();
+ });
+       
+       
+       
 /*# AVOID COLLISIONS #*/
 })(jQuery);
 /*# AVOID COLLISIONS #*/