diff options
Diffstat (limited to 'framework/web/js/source/jquery.multifile.js')
| -rw-r--r-- | framework/web/js/source/jquery.multifile.js | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/framework/web/js/source/jquery.multifile.js b/framework/web/js/source/jquery.multifile.js new file mode 100644 index 0000000..d123423 --- /dev/null +++ b/framework/web/js/source/jquery.multifile.js @@ -0,0 +1,536 @@ +/* + ### jQuery Multiple File Upload Plugin v1.47 - 2010-03-26 ### + * 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 + ### +*/ + +/*# AVOID COLLISIONS #*/ +;if(window.jQuery) (function($){ +/*# AVOID COLLISIONS #*/ + + // 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; + var group_count = window.MultiFile; + + // Copy parent attributes - Thanks to Jonas Wagner + // we will use this one to create new input elements + var MultiFile = {e:this, E:$(this), clone:$(this).clone()}; + + //=== + + //# USE CONFIGURATION + if(typeof options=='number') options = {max:options}; + var o = $.extend({}, + $.fn.MultiFile.options, + options || {}, + ($.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(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 || MultiFile.E.attr('accept') || ''; + if(!o.accept){ + o.accept = (MultiFile.e.className.match(/\b(accept\-[\w\|]+)\b/gi)) || ''; + o.accept = new String(o.accept).replace(/^(accept|ext)\-/i,''); + }; + + //=== + + // APPLY CONFIGURATION + $.extend(MultiFile, o || {}); + MultiFile.STRING = $.extend({},$.fn.MultiFile.options.STRING,MultiFile.STRING); + + //=== + + //######################################### + // PRIVATE PROPERTIES/METHODS + $.extend(MultiFile, { + n: 0, // How many elements are currently selected? + slaves: [], files: [], + 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 = MultiFile[event], value = $(element).attr('value'); + if(handler){ + 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(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 + MultiFile.wrapID = MultiFile.instanceKey+'_wrap'; // Wrapper ID? + MultiFile.E.wrap('<div class="MultiFile-wrap" id="'+MultiFile.wrapID+'"></div>'); + MultiFile.wrapper = $('#'+MultiFile.wrapID+''); + + //=== + + // MultiFile MUST have a name - default: file1[], file2[], file3[] + MultiFile.e.name = MultiFile.e.name || 'file'+ group_count +'[]'; + + //=== + + 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 + MultiFile.wrapper.append( '<div class="MultiFile-list" id="'+MultiFile.wrapID+'_list"></div>' ); + MultiFile.list = $('#'+MultiFile.wrapID+'_list'); + }; + MultiFile.list = $(MultiFile.list); + + //=== + + // Bind a new element + MultiFile.addSlave = function( slave, slave_count ){ + //if(window.console) console.log('MultiFile.addSlave',slave_count); + + // Keep track of how many elements have been displayed + MultiFile.n++; + // Add reference to master element + 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 || 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 + + // 2008-Apr-29: New customizable naming convention (see url below) + // http://groups.google.com/group/jquery-dev/browse_frm/thread/765c73e41b34f924# + 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:'')) + ); + + // If we've reached maximum number, disable input slave + 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 + MultiFile.current = MultiFile.slaves[slave_count] = 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(){ + //if(window.console) console.log('MultiFile.slave.change',slave_count); + + // Lose focus to stop IE7 firing onchange again + $(this).blur(); + + //# Trigger Event! onFileSelect + 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(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 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 = $(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 + newEle.addClass('MultiFile'); + + // Handle error + if(ERROR!=''){ + // Handle error + 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 + MultiFile.n--; + MultiFile.addSlave(newEle[0], slave_count); + slave.parent().prepend(newEle); + slave.remove(); + return false; + }; + + // Hide this element (NB: display:none is evil!) + $(this).css({ position:'absolute', top: '-3000px' }); + + // Add new element to the form + slave.after(newEle); + + // Update list + MultiFile.addToList( this, slave_count ); + + // Bind functionality + MultiFile.addSlave( newEle[0], slave_count+1 ); + + //# Trigger Event! afterFileSelect + if(!MultiFile.trigger('afterFileSelect', this, MultiFile)) return false; + //# End Event! + + }); // slave.change() + + // Save control to element + $(slave).data('MultiFile', MultiFile); + + };// MultiFile.addSlave + // Bind a new element + + + + // Add a new file to the list + MultiFile.addToList = function( slave, slave_count ){ + //if(window.console) console.log('MultiFile.addToList',slave_count); + + //# Trigger Event! onFileAppend + if(!MultiFile.trigger('onFileAppend', slave, MultiFile)) return false; + //# End Event! + + // Create label elements + var + r = $('<div class="MultiFile-label"></div>'), + v = String(slave.value || ''/*.attr('value)*/), + 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 + MultiFile.list.append( + r.append(b, ' ', a) + ); + + b + .click(function(){ + + //# Trigger Event! onFileRemove + if(!MultiFile.trigger('onFileRemove', slave, MultiFile)) return false; + //# End Event! + + MultiFile.n--; + MultiFile.current.disabled = false; + + // Remove element, remove label, point to current + MultiFile.slaves[slave_count] = null; + $(slave).remove(); + $(this).parent().remove(); + + // Show most current element again (move into view) and clear selection + $(MultiFile.current).css({ position:'', top: '' }); + $(MultiFile.current).reset().val('').attr('value', '')[0].value = ''; + + //# Trigger Event! afterFileRemove + if(!MultiFile.trigger('afterFileRemove', slave, MultiFile)) return false; + //# End Event! + + return false; + }); + + //# Trigger Event! afterFileAppend + if(!MultiFile.trigger('afterFileAppend', slave, MultiFile)) return false; + //# End Event! + + }; // MultiFile.addToList + // Add element to selected files list + + + + // Bind functionality to the first element + if(!MultiFile.MultiFile) MultiFile.addSlave(MultiFile.e, 0); + + // Increment control count + //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 + + }); + + /*--------------------------------------------------------*/ + + /* + ### 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) + + // 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 #*/ |
