├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── _config.yml ├── bower.json ├── docs ├── CNAME ├── analytics.html ├── btn-oss.png ├── docs-core.html ├── docs.css ├── docs.jade ├── docs.js ├── docs.scss ├── inc │ ├── footer.jade │ └── header.jade ├── index.html ├── jquery.MetaData.js ├── jquery.MultiFile.min.js ├── jquery.form.js └── layout.jade ├── gruntfile.js ├── jquery.MultiFile.js ├── jquery.MultiFile.min.js ├── package-lock.json ├── package.json └── test ├── index.html ├── maxfile.html ├── maxsize.html ├── nocomma.html ├── preview.html ├── test.php ├── test1.js └── test2.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Testing files 2 | jquery.MultiFile.testing.js 3 | 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # Deployed apps should consider commenting this line out: 27 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 28 | node_modules 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6.11.3" 4 | before_script: 5 | - npm install -g grunt-cli 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2008, 2014 https://www.fyneworks.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [jQuery Multiple File Upload](https://multifile.fyneworks.com/) 2 | 3 | ## Overview 4 | 5 | [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=fyneworks&url=https://github.com/fyneworks/multifile&title=Multiple+File+Upload&language=&tags=github&category=software) 6 | 7 | MultiFile ($.MultiFile) is a non-obtrusive and crucially **non-opinionated** plugin for jQuery that helps your users easily select multiple files for upload. 8 | 9 | It helps you implement a basic interface to improve the file selection experience of your users whilst providing you, the developer, with 3 simple methods of validation: accepted extensions, maximum number of files and total size. 10 | 11 | --- 12 | 13 | ## Server-Side Implementation 14 | 15 | This plugin will never deal with the server-side implementation of your upload solution. This plugin will not upload your files. If that's what you want, we recommend you check them out one of the 16 | [many](http://www.uploadify.com/), 17 | [many](http://www.plupload.com/) 18 | [many](http://blueimp.github.io/jQuery-File-Upload/") great tools out there which provide a full solution - with image previews, progress bars and extensive support for many environments (`.NET`, `PHP`, `Java`, etc...). 19 | 20 | And remember..... **server-side validation is always required**. 21 | 22 | --- 23 | 24 | ## Installation 25 | 26 | First, get the package 27 | 28 | Install with bower: `bower install multifile` or download zip from GitHub multifile.zip 29 | 30 | Then, invoke the required javascript files to your document, just before the `` tag. 31 | 32 | Add [jQuery](https://developers.google.com/speed/libraries/devguide#jquery) to your page. We strongly recommend you make use of Google's Hosted Libraries service. 33 | ```html 34 | 35 | ``` 36 | 37 | Then add the plugin (after jQuery) 38 | ```html 39 | 40 | ``` 41 | 42 | **Note** that, before v2.2.2, the file was called `jQuery.MultiFile.min.js` instead (jQuery recommended to use a lowercase ‘q’ in package names). 43 | 44 | --- 45 | 46 | ## Recommended Usage (HTML5) 47 | 48 | Just add `multiple="multiple"` and `class="multi"` attributes to your ``, like this: 49 | 50 | ```html 51 | 52 | ``` 53 | 54 | Use the `maxlength` property if you want to limit the number of files selected. 55 | Server-side validation is always required 56 | ```html 57 | 58 | ``` 59 | 60 | Use the `accept` if you only want files of a certain extension to be selected Separate valid extensions with a "|", like this: "jpg|gif|png". 61 | Server-side validation is always required. 62 | ```html 63 | 64 | ``` 65 | 66 | --- 67 | 68 | ## Legacy Usage (pre HTML5) 69 | 70 | Versions of HTML and xHTML prior to HTML 5 do not support the `multiple="multiple"` attribute. The plugin will still work in almost the same way, but your users will only be able to **one file at a time**. 71 | 72 | ```html 73 | 74 | ``` 75 | 76 | Use the `maxlength` property if you want to limit the number of files selected. 77 | Server-side validation is always required 78 | ```html 79 | 80 | ``` 81 | 82 | Use the `accept` if you only want files of a certain extension to be selected Separate valid extensions with a "|", like this: "jpg|gif|png". 83 | Server-side validation is always required. 84 | ```html 85 | 86 | ``` 87 | 88 | --- 89 | 90 | ## Full Documentation and Demos 91 | 92 | For more examples, documentation and a full list of features available, please [visit the plugin's official website](https://multifile.fyneworks.com/). 93 | 94 | --- 95 | 96 | ## Continous Integration with Travis CI 97 | 98 | [![Master Status](https://travis-ci.org/fyneworks/multifile.svg?branch=master)](https://travis-ci.org/fyneworks/multifile): full build history on [Travis CI]((https://travis-ci.org/fyneworks/multifile)) 99 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-hacker -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "multifile", 3 | "version": "2.2.2", 4 | "homepage": "https://github.com/fyneworks/multifile", 5 | "authors": [ 6 | "Fyneworks.com" 7 | ], 8 | "description": "jQuery multiple file upload plugin", 9 | "main": "jquery.MultiFile.js", 10 | "keywords": [ 11 | "jquery", 12 | "file", 13 | "upload" 14 | ], 15 | "license": "MIT", 16 | "ignore": [ 17 | "**/.*", 18 | "node_modules", 19 | "bower_components", 20 | "bower.json", 21 | "package.json", 22 | "docs", 23 | "test", 24 | "tests" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | multifile.fyneworks.com -------------------------------------------------------------------------------- /docs/analytics.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /docs/btn-oss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fyneworks/multifile/d93a0616f5d88b605dcadded4b0bc5f124a1356f/docs/btn-oss.png -------------------------------------------------------------------------------- /docs/docs-core.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |
7 |

What 8 | this is 9 |

10 |

11 | This 12 | jQuery Multiple File Selection Plugin 13 | ($.MultiFile) is a non-obtrusive plugin for jQuery 14 | that helps users easily 15 | select multiple files for upload. It lets you apply some basic restrictions/validation so you can easily 16 | reject files before they're uploaded based on their extension or size 17 | before they're uploaded. 18 |

19 |
20 |
21 |

What this isn't

22 |

23 | This is not a file upload tool. Uploading files require 24 | server-side integration and 25 | security considerations 26 | this project will never support. We can recommend 27 | many, 28 | many, 29 | many 30 | 31 | great tools if you're looking for a complete upload solution. But if you don't already manage your own server-side integration, or if you have no idea what I'm talking about, then this plugin is not for you. 32 |

33 |
34 |
35 |

What's new?

36 |

37 | A fresh start... ish 38 | : This project started a a very long time ago... and it's been dormant since 2009! Support has been shockingly bad, we admit, but we would like to engage more actively with our users and the jQuery community from now on. So as of April 2014, we've left Google Code behind and will be starting a fresh project on GitHub. Our other projects (Star Rating & CKEditor will follow shortly). We very much encourage and would love you all to report issues, contribue and discuss this project on GitHub. 39 |

40 |
41 |
42 | 43 | 44 |

Getting started

45 |
46 |
47 |

48 | Just add the 49 | multi class to your file input element. 50 |

51 |
<input type="file" class="multi"/>
52 |
53 |
54 | 55 |
56 |
57 |
58 |
59 |

60 | Use the 61 | maxlength property if you want to limit the number of files selected. 62 |

63 |
<input type="file" class="multi" maxlength="2"/>
64 |
65 |
66 | 67 |
68 |
69 |
70 |
71 |

72 | Use the 73 | accept property if you only want files of a certain extension to be selected. 74 |
75 | Separate valid extensions with a "|", like this: "jpg|gif|png". 76 |

77 |
<input type="file" class="multi" accept="gif|jpg"/>
78 |
79 |
80 | 81 |
82 |
83 |
84 |
85 | NB.: server-side validation is always required 86 |
87 |
88 |
89 | 90 | 91 |
92 | 93 |

Usage Examples

94 | 95 |
96 |

Using Attributes

97 | 98 |
99 |
100 |

The easiest way to get started is to add class="multi" and modify the attributes of your element

101 |
102 |
103 |
104 | 105 |
106 |
107 | 108 | Example 1 109 | 110 |

Use maxlength to limit the number of files selected

111 |
<input
 112 |   class="multi"
 113 |   maxlength="2"
 114 | />
115 |
116 | Limit: 2 files. 117 |
Allowed extensions: any. 118 |
119 |
120 | 121 |
122 |
123 |
124 |
125 |
126 | 127 | Example 2 128 | 129 |

Use accept to limit the extensions allowed

130 |
<input
 131 |   class="multi"
 132 |   accept="gif|jpg"
 133 | />
134 |
135 | Limit: no limit. 136 |
Allowed extensions: gif and jpg. 137 |
138 |
139 | 140 |
141 |
142 |
143 |
144 |
145 | 146 | Example 3 147 | 148 |

Use maxlength and accept combined

149 |
<input
 150 |   class="multi"
 151 |   accept="gif|jpg"
 152 |   maxlength="3"
 153 | />
154 |
155 | Limit: 3 files 156 |
Allowed extensions: gif, jpg. 157 |
158 |
159 | 160 |
161 |
162 | Note that server-side validation is always required 163 |
164 |
165 |
166 | 167 |
168 | 169 |
170 |
171 | 172 |

Using the class property

173 | 174 |
175 |
176 |

There is a way to configure the plugin via the class property, without any knowledge of javascript

177 |
178 |
179 | 180 |
181 |
182 |
183 | 184 | Example 4 185 | 186 |
<input class="
 187 |   multi max-3
 188 | "/>
189 |
190 | Limit: 3 files. 191 |
Allowed extensions: any. 192 |
193 |
194 | 195 |
196 |
197 |
198 |
199 |
200 | 201 | Example 5 202 | 203 |
<input class="
 204 |   multi accept-gif|jpg
 205 | "/>
206 |
207 | Limit: no limit. 208 |
Allowed extensions: gif, jpg. 209 |
210 |
211 | 212 |
213 |
214 |
215 |
216 |
217 | 218 | Example 6 219 | 220 |
<input class="
 221 |   multi
 222 |   max-3
 223 |   accept-gif|jpg
 224 |   maxsize-1024
 225 | "/>
226 |
227 | Limit: 3 files 228 |
Allowed extensions: gif, jpg. 229 |
Max payload: 1MB (1024 bytes) 230 |
231 |
232 | 233 |
234 |
235 | Note that server-side validation is always required 236 |
237 |
238 |
239 |
240 | 241 |
242 |
243 | 244 |

Selecting many files at once (HTML5)

245 | 246 |
247 |
248 |

So far, each of the example above has only enabled you to select one file at a time. To select multiple files at once, just use HTML5's multiple attribute (1, 2)

249 |
250 |
251 | 252 |
253 |
254 |
255 | 256 | Example 7 257 | 258 |
<input
 259 |   multiple
 260 |   class="multi"
 261 |   maxlength="10"
 262 | />
263 |
264 | Limit: 10 files. 265 |
Allowed extensions: any. 266 |
267 |
268 | 269 |
270 |
271 |
272 |
273 |
274 | 275 | Example 8 276 | 277 |
<input
 278 |   multiple
 279 |   class="multi"
 280 |   accept="gif|jpg|png"
 281 | />
282 |
283 | Limit: no limit. 284 |
Allowed extensions: gif, jpg. 285 |
286 |
287 | 288 |
289 |
290 |
291 |
292 |
293 | 294 | Example 9 295 | 296 |
<input
 297 |   multiple
 298 |   class="multi"
 299 |   maxlength="10"
 300 |   accept="gif|jpg|png"
 301 | />
302 |
303 | Limit: 10 files 304 |
Allowed extensions: gif, jpg, png. 305 |
306 |
307 | 308 |
309 |
310 | Note that server-side validation is always required 311 |
312 |
313 |
314 |
315 | 316 |
317 |
318 | 319 |

Validating Sizes

320 | 321 |
322 |
323 |

It's common to validate the size of the files being selected prior to upload.

324 |
325 |
326 | 327 |
328 |
329 |
330 | 331 | Example 10a 332 | 333 |

Using class maxsize-* (* = max size in kb)

334 |
<input
 335 |   multiple
 336 |   class="multi maxsize-5120"
 337 | />
338 |
339 | Limit: any number of files 340 |
Allowed extensions: any. 341 |
Max payload: 5MB 342 |
343 |
344 | 345 |
346 |
347 |
348 |
349 |
350 | 351 | Example 10b 352 | 353 |

Using data-maxsize attribute (max size in kb)

354 |
<input
 355 |   multiple
 356 |   class="multi"
 357 |   maxlength="3"
 358 |   data-maxsize="1024"
 359 | />
360 |
361 | Limit: 3 files (under <1MB in total) 362 |
363 |
364 | 365 |
366 |
367 |
368 |
369 |
370 | 371 | Example 10c 372 | 373 |

Use data-maxfile to validate individual files

374 |
<input
 375 |   multiple
 376 |   class="multi"
 377 |   maxlength="3"
 378 |   data-maxfile="1024"
 379 | />
380 |
381 | Limit: 3 files (under <1MB each) 382 |
383 |
384 | 385 |
386 |
387 | Note that server-side validation is always required 388 |
389 |
390 |
391 |
392 | 393 |
394 | 395 |

With an Image Preview

396 | 397 |
398 |
399 |

There's an easy way to add a preview of the image being uploaded

400 |
401 |
402 | 403 |
404 |
405 |
406 | 407 | Example 11a 408 | 409 |

Using class with-preview

410 |
<input
 411 |   multiple
 412 |   class="multi with-preview"
 413 | />
414 |
415 | 416 |
417 |
418 |
419 |
420 | 421 |
422 |
423 | 424 | 425 |

Advanced Examples

426 |
427 |
428 |
429 | IMPORTANT: Don't use class="multi" if you use any of the examples below this point. 430 |
431 |
432 |
433 |

434 | If you use class="multi" the plugin will be initialised automatically 435 | (taking precedence over your code). 436 |

437 |

438 | You must invoke the plugin with your own selector when you use any of the examples below. 439 |

440 |
441 |
442 | Something like 443 |
<input type="file" class="this-is-your-class" />
. 444 |
445 |
446 | Followed by 447 |
// this is your code
 448 | $(function(){ // wait for page to load
 449 | 
 450 |   // this is your selector
 451 |   $('input.this-is-your-class').MultiFile({
 452 |     // your options go here
 453 |     max: 2,
 454 |     accept: 'jpg|png|gif'
 455 |   });
 456 | 
 457 | });
458 |

459 |
460 |
461 | 462 |
463 |
464 |
465 |

Setting limit via script

466 |
<input multiple type="file" id="UpTo3Files"/>
467 |
// wait for document to load
 468 | $(function(){
 469 | 
 470 |   // up to 3 files can be selected
 471 | 
 472 |   // invoke plugin
 473 |   $('#UpTo3Files').MultiFile(5);
 474 | 
 475 |   // if you send in a number the plugin
 476 |   // will treat it as the file limit
 477 | 
 478 | });
479 |
480 | Try it: 481 | 482 | 493 |
494 |
495 |
496 |

Limit and Extension Filter

497 |
<input multiple type="file" id="UpTo3Images"/>
498 |
// wait for document to load
 499 | $(function(){
 500 | 
 501 |   // up to 3 files can be selected
 502 |   // only images are allowed
 503 | 
 504 |   // invoke plugin
 505 |   $('#UpTo3Images').MultiFile({
 506 |     max: 3,
 507 |     accept: 'gif|jpg|png'
 508 |   });
 509 | 
 510 | });
511 |
512 | Try it: 513 | 514 | 526 |
527 |
528 |
529 |

Multi-lingual support

530 |
<input multiple type="file" id="EmPortugues"/>
531 |
// wait for document to load
 532 | $(function(){
 533 | 
 534 |   // use a different language
 535 |   // $file prints the file name
 536 |   // $ext prints the file extension
 537 | 
 538 |   // invoke plugin
 539 |   $('#EmPortugues').MultiFile({
 540 |     max: 3,
 541 |     accept: 'gif|jpg|png'
 542 |     STRING: {
 543 |       remove:'Remover',
 544 |       selected:'Selecionado: $file',
 545 |       denied:'Invalido arquivo de tipo $ext!'
 546 |     }
 547 |   });
 548 | 
 549 | });
550 |
551 | Try it: 552 | 553 | 571 |
572 |
573 | 574 |
575 |
576 | 577 |
578 |

Moving the file list

579 |
580 |
581 |
582 | 587 |

This example populates the file list in a custom element

588 |
$(function() { // wait for document to load
 589 |   $('#T7').MultiFile({
 590 |     list: '#T7-list'
 591 |   });
 592 | });
593 | 600 |
601 |
602 |
603 |
604 | 605 |
606 |
607 | This is div#T7-list - selected files will be populated here... 608 |
609 |
610 |
611 |
612 |
613 |
614 | 615 |
616 |

Customising the file list

617 |
618 | 619 |
620 | 621 | 622 |
623 | 628 |

Use a custom 'remove' image in the file list

629 |
$(function() { // wait for document to load
 630 |   $('#T8A').MultiFile({
 631 |     STRING: {
 632 |       remove: '<img src="/i/bin.gif" height="16" width="16" alt="x"/>'
 633 |     }
 634 |   });
 635 | });
636 | 645 |
646 |
647 |
648 |
649 | 650 |
651 |
652 | 653 |
654 |
655 | 656 |
657 |
658 |
659 |
660 | 665 |

Customising all list content

666 |
$(function() { // wait for document to load
 667 |   $('#T8B').MultiFile({
 668 |     STRING: {
 669 |       file: '<em title="Click to remove" onclick="$(this).parent().prev().click()">$file</em>',
 670 |       remove: '<img src="/i/bin.gif" height="16" width="16" alt="x"/>'
 671 |     }
 672 |   });
 673 | });
674 | 684 |
685 |
686 |
687 |
688 | 689 |
690 |
691 |
692 |
693 | 694 |
695 |

Using events

696 |
697 |
698 |
699 |

700 | The arguments passed on to each event handler are: 701 |
element: file element which triggered the event 702 |
value: the value of the element in question 703 |
master_element: the original element containing all relevant settings 704 |

705 |
706 |
707 |

708 | Selection events: 709 |

    710 |
  • onFileAppend
  • 711 |
  • afterFileAppend
  • 712 |
  • onFileSelect
  • 713 |
  • afterFileSelect
  • 714 |
  • onFileRemove
  • 715 |
  • afterFileRemove
  • 716 |
717 |

718 |
719 |
720 |

721 | Validation events: 722 |

    723 |
  • onFileDuplicate
  • 724 |
  • onFileInvalid
  • 725 |
  • onFileTooMany
  • 726 |
  • onFileTooBig
  • 727 |
  • onFileTooMuch
  • 728 |
729 |

730 |
731 |
732 |
733 |
734 |
735 | 740 |
<input multiple type="file" id="WithEvents"/>
741 |
// wait for document to load
 742 | $(function(){
 743 | 
 744 |   // 2 jpgs under 100kb only
 745 | 
 746 |   $('#WithEvents').MultiFile({
 747 |     max: 2,
 748 |     max_size: 100,
 749 |     accept: 'jpg|png|gif',
 750 |     onFileRemove: function(element, value, master_element) {
 751 |       $('#F9-Log').append('<li>onFileRemove - ' + value + '</li>')
 752 |     },
 753 |     afterFileRemove: function(element, value, master_element) {
 754 |       $('#F9-Log').append('<li>afterFileRemove - ' + value + '</li>')
 755 |     },
 756 |     onFileAppend: function(element, value, master_element) {
 757 |       $('#F9-Log').append('<li>onFileAppend - ' + value + '</li>')
 758 |     },
 759 |     afterFileAppend: function(element, value, master_element) {
 760 |       $('#F9-Log').append('<li>afterFileAppend - ' + value + '</li>')
 761 |     },
 762 |     onFileSelect: function(element, value, master_element) {
 763 |       $('#F9-Log').append('<li>onFileSelect - ' + value + '</li>')
 764 |     },
 765 |     afterFileSelect: function(element, value, master_element) {
 766 |       $('#F9-Log').append('<li>afterFileSelect - ' + value + '</li>')
 767 |     },
 768 |     onFileInvalid: function(element, value, master_element) {
 769 |       $('#F9-Log').append('<li>onFileInvalid - ' + value + '</li>')
 770 |     },
 771 |     onFileDuplicate: function(element, value, master_element) {
 772 |       $('#F9-Log').append('<li>onFileDuplicate - ' + value + '</li>')
 773 |     },
 774 |     onFileTooMany: function(element, value, master_element) {
 775 |       $('#F9-Log').append('<li>onFileTooMany - ' + value + '</li>')
 776 |     },
 777 |     onFileTooBig: function(element, value, master_element) {
 778 |       $('#F9-Log').append('<li>onFileTooBig - ' + value + '</li>')
 779 |     },
 780 |     onFileTooMuch: function(element, value, master_element) {
 781 |       $('#F9-Log').append('<li>onFileTooMuch - ' + value + '</li>')
 782 |     }
 783 |   });
 784 | });
785 | 824 |
825 |
826 |
827 |
828 | 829 |
830 |
831 | This is div#F9-Log - selected files will be populated here... 832 |
833 |
    834 | 835 |
836 |
837 |
838 |
839 |
840 |
841 | 842 | 843 |
844 |
845 | 846 |
847 | 848 | 849 |
850 |

Multi-lingual support

851 |

852 | The plugin doesn't have any additional languages built-in, but it's very easy to customise the messages to any language of your choosing. See the examples below... 853 |

854 |

855 | NB.: This example has been configured to accept gif/pg files only in order to demonstrate the error messages. 856 |

857 |
858 | 859 |
860 | 861 |

Method 1: Using class property (requires the MetaData plugin)

862 |
<input type="file"
 863 |   class="multi {
 864 |     accept:'gif|jpg',
 865 |     max:3,
 866 |     STRING:{
 867 |       remove:'Remover',
 868 |       selected:'Selecionado: $file',
 869 |       denied:'Invalido arquivo de tipo $ext!',
 870 |       duplicate:'Arquivo ja selecionado:\n$file!'
 871 |     }
 872 |   }"
 873 | />
874 | 875 |

Method 2: Programatically by ID (ONE element only, does not require MetaData plugin)

876 |
<input type="file" id="PortugueseFileUpload" />
877 |
$(function(){
 878 |   $('#PortugueseFileUpload').MultiFile({
 879 |     accept:'gif|jpg',
 880 |     max:3,
 881 |     STRING: {
 882 |       remove:'Remover',
 883 |       selected:'Selecionado: $file',
 884 |       denied:'Invalido arquivo de tipo $ext!',
 885 |       duplicate:'Arquivo ja selecionado:\n$file!'
 886 |     }
 887 |   });
 888 | });
889 | 890 |

Method 3: Programatically ( 891 | n emlements, does not require MetaData plugin)

892 | See this feature request for details 893 |
894 |
<input type="file" class="multi-pt" />
 895 | <input type="file" class="multi-pt" />
 896 | <input type="file" class="multi-pt" />
897 |
$(function(){
 898 |   $('.multi-pt').MultiFile({
 899 |     accept:'gif|jpg',
 900 |     max:3,
 901 |     STRING: {
 902 |       remove:'Remover',
 903 |       selected:'Selecionado: $file',
 904 |       denied:'Invalido arquivo de tipo $ext!',
 905 |       duplicate:'Arquivo ja selecionado:\n$file!'
 906 |     }
 907 |   });
 908 | });
909 | 910 |
911 | 912 | 913 |
914 |

Installation

915 | 916 |

Requirements

917 |

You'll need jQuery, we recommend using Google Hosted Libraries.

918 |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js" type="text/javascript" language="javascript"></script>
919 | 920 |

The plugin

921 |

922 | Either download the latest version and host it on your own server 923 |

924 |
<script src="path/to/your/jquery.MultiFile.js" type="text/javascript" language="javascript"></script>
925 | 926 |

927 | OR if you like living on the edge, hotlink the latest release directly from GitHub 928 |

929 |
<script src="//github.com/fyneworks/multifile/blob/master/jquery.MultiFile.min.js" type="text/javascript" language="javascript"></script>
930 | 931 |
932 | 933 | 934 |
935 |

Support

936 |
937 |
938 | 939 |

940 | We very much encourage and would love you all to report issues, contribue and discuss this project on GitHub. 941 |

942 |

943 | There's also a README.md for quick reference, if you're that way inclined. 944 |

945 |

946 | This project started a a very long time ago... and it's been dormant since 2009! Support has been shockingly bad, we admit, 947 | but we would like to engage more actively with our users and the jQuery community from now on. So as of April 2014, 948 | we've left Google Code behind and 949 | will be starting a fresh project on GitHub. 950 | Our other projects (Star Rating & CKEditor will follow shortly). 951 |

952 |
953 |
954 |
955 | 956 | 957 |
958 |

Credit where it's due!

959 |
960 |
961 |
    962 |
  • Fyneworks.com professional web design and google SEO experts 963 |
  • 964 |
  • Dean Edwards - Author of JS Packer used to compress the plugin
  • 965 |
  • Adrian Wróbel - Fixed a nasty bug so the script could work perfectly in Opera
  • 966 |
  • Jonas Wagner - Modified plugin so newly created elements are an exact copy of the original element (ie.: persists attributes)
  • 967 |
  • Mike Alsup - Author of several jQuery Plugins... 968 |
      969 |
    • Suggested solution to element naming convention / server-side handling
    • 970 |
    • Form plugin - Used to submit forms via ajax
    • 971 |
    • blockUI plugin - Used to show pretty error messages
    • 972 |
    973 |
  • 974 |
  • Julien Phalip - Identified conflict with variable name 'class' in several methods
  • 975 |
976 |
977 |
978 |
979 | 980 | 981 |
982 |

License Info

983 |
984 |
985 |
986 | 987 | 988 | 995 | 1001 | 1002 | 1003 | 1027 | 1028 |
989 | Multiple File Selection Plugin 990 | by Fyneworks.com 991 | is licensed, 992 | as jQuery is, under the 993 | MIT License. 994 | 996 | OSI Certified
Open Source™
Software 1000 |
1004 | 1026 |
1029 |
1030 |
1031 |
1032 | 1033 |
1034 | 1035 |
1036 | 1037 | 1038 | 1039 | 1040 | 1065 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | -------------------------------------------------------------------------------- /docs/docs.css: -------------------------------------------------------------------------------- 1 | .jumbotron,h2{margin-top:80px}h3{margin-top:40px}h4{margin-top:20px}div.example{margin-top:30px;border-top:#ccc dotted 1px;padding-top:30px}legend{font-size:inherit} -------------------------------------------------------------------------------- /docs/docs.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | div.container 5 | div.jumbotron 6 | h1 jQuery MultiFile 7 | p The unopinionated way to implement file selection. 8 | 9 | div.container 10 | include docs-core.html 11 | include analytics.html 12 | -------------------------------------------------------------------------------- /docs/docs.js: -------------------------------------------------------------------------------- 1 | if(false){ 2 | $(function(){ 3 | $('.tabs').addClass('Clear').tabs(); 4 | }); 5 | }; 6 | 7 | if(false){ 8 | hljs.configure({tabReplace: '\t'}); 9 | $(function(){ 10 | $('pre code').each(function(i, e){ 11 | hljs.highlightBlock(e); 12 | }) 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /docs/docs.scss: -------------------------------------------------------------------------------- 1 | .jumbotron{margin-top: 80px;} 2 | h2{ margin-top:80px;} 3 | h3{ margin-top:40px;} 4 | h4{ margin-top:20px;} 5 | div.example{ margin-top:30px; border-top:#ccc dotted 1px; padding-top:30px; } 6 | legend{ font-size: inherit; } 7 | -------------------------------------------------------------------------------- /docs/inc/footer.jade: -------------------------------------------------------------------------------- 1 | footer#footer 2 | p © Fyneworks 3 | -------------------------------------------------------------------------------- /docs/inc/header.jade: -------------------------------------------------------------------------------- 1 | .navbar.navbar-default.navbar-fixed-top.navbar-static-top(role='navigation') 2 | .container 3 | .navbar-header 4 | button.navbar-toggle(type='button', data-toggle='collapse', data-target='.navbar-collapse') 5 | span.sr-only Toggle navigation 6 | span.icon-bar 7 | span.icon-bar 8 | span.icon-bar 9 | a.navbar-brand(href='./')= pkg.title 10 | .navbar-collapse.collapse 11 | ul.nav.navbar-nav 12 | //li 13 | a(href='#') Intro 14 | - var obj = { 'Usage':'Usage', 'Advanced':'Advanced', 'Customize':'Customize', 'Events':'Events', 'Locale':'Locale', 'Install':'Install', 'Support':'Support','Credit':'Credit' } 15 | - each val, key in obj 16 | li 17 | a(href='##{key}',id='#btn-#{key}') #{val} 18 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | jQuery MultiFile v2.2.2

jQuery MultiFile

The unopinionated way to implement file selection.

2 | 3 |
4 | 5 |
6 |
7 |

What 8 | this is 9 |

10 |

11 | This 12 | jQuery Multiple File Selection Plugin 13 | ($.MultiFile) is a non-obtrusive plugin for jQuery 14 | that helps users easily 15 | select multiple files for upload. It lets you apply some basic restrictions/validation so you can easily 16 | reject files before they're uploaded based on their extension or size 17 | before they're uploaded. 18 |

19 |
20 |
21 |

What this isn't

22 |

23 | This is not a file upload tool. Uploading files require 24 | server-side integration and 25 | security considerations 26 | this project will never support. We can recommend 27 | many, 28 | many, 29 | many 30 | 31 | great tools if you're looking for a complete upload solution. But if you don't already manage your own server-side integration, or if you have no idea what I'm talking about, then this plugin is not for you. 32 |

33 |
34 |
35 |

What's new?

36 |

37 | A fresh start... ish 38 | : This project started a a very long time ago... and it's been dormant since 2009! Support has been shockingly bad, we admit, but we would like to engage more actively with our users and the jQuery community from now on. So as of April 2014, we've left Google Code behind and will be starting a fresh project on GitHub. Our other projects (Star Rating & CKEditor will follow shortly). We very much encourage and would love you all to report issues, contribue and discuss this project on GitHub. 39 |

40 |
41 |
42 | 43 | 44 |

Getting started

45 |
46 |
47 |

48 | Just add the 49 | multi class to your file input element. 50 |

51 |
<input type="file" class="multi"/>
52 |
53 |
54 | 55 |
56 |
57 |
58 |
59 |

60 | Use the 61 | maxlength property if you want to limit the number of files selected. 62 |

63 |
<input type="file" class="multi" maxlength="2"/>
64 |
65 |
66 | 67 |
68 |
69 |
70 |
71 |

72 | Use the 73 | accept property if you only want files of a certain extension to be selected. 74 |
75 | Separate valid extensions with a "|", like this: "jpg|gif|png". 76 |

77 |
<input type="file" class="multi" accept="gif|jpg"/>
78 |
79 |
80 | 81 |
82 |
83 |
84 |
85 | NB.: server-side validation is always required 86 |
87 |
88 |
89 | 90 | 91 |
92 | 93 |

Usage Examples

94 | 95 |
96 |

Using Attributes

97 | 98 |
99 |
100 |

The easiest way to get started is to add class="multi" and modify the attributes of your element

101 |
102 |
103 |
104 | 105 |
106 |
107 | 108 | Example 1 109 | 110 |

Use maxlength to limit the number of files selected

111 |
<input
 112 |   class="multi"
 113 |   maxlength="2"
 114 | />
115 |
116 | Limit: 2 files. 117 |
Allowed extensions: any. 118 |
119 |
120 | 121 |
122 |
123 |
124 |
125 |
126 | 127 | Example 2 128 | 129 |

Use accept to limit the extensions allowed

130 |
<input
 131 |   class="multi"
 132 |   accept="gif|jpg"
 133 | />
134 |
135 | Limit: no limit. 136 |
Allowed extensions: gif and jpg. 137 |
138 |
139 | 140 |
141 |
142 |
143 |
144 |
145 | 146 | Example 3 147 | 148 |

Use maxlength and accept combined

149 |
<input
 150 |   class="multi"
 151 |   accept="gif|jpg"
 152 |   maxlength="3"
 153 | />
154 |
155 | Limit: 3 files 156 |
Allowed extensions: gif, jpg. 157 |
158 |
159 | 160 |
161 |
162 | Note that server-side validation is always required 163 |
164 |
165 |
166 | 167 |
168 | 169 |
170 |
171 | 172 |

Using the class property

173 | 174 |
175 |
176 |

There is a way to configure the plugin via the class property, without any knowledge of javascript

177 |
178 |
179 | 180 |
181 |
182 |
183 | 184 | Example 4 185 | 186 |
<input class="
 187 |   multi max-3
 188 | "/>
189 |
190 | Limit: 3 files. 191 |
Allowed extensions: any. 192 |
193 |
194 | 195 |
196 |
197 |
198 |
199 |
200 | 201 | Example 5 202 | 203 |
<input class="
 204 |   multi accept-gif|jpg
 205 | "/>
206 |
207 | Limit: no limit. 208 |
Allowed extensions: gif, jpg. 209 |
210 |
211 | 212 |
213 |
214 |
215 |
216 |
217 | 218 | Example 6 219 | 220 |
<input class="
 221 |   multi
 222 |   max-3
 223 |   accept-gif|jpg
 224 |   maxsize-1024
 225 | "/>
226 |
227 | Limit: 3 files 228 |
Allowed extensions: gif, jpg. 229 |
Max payload: 1MB (1024 bytes) 230 |
231 |
232 | 233 |
234 |
235 | Note that server-side validation is always required 236 |
237 |
238 |
239 |
240 | 241 |
242 |
243 | 244 |

Selecting many files at once (HTML5)

245 | 246 |
247 |
248 |

So far, each of the example above has only enabled you to select one file at a time. To select multiple files at once, just use HTML5's multiple attribute (1, 2)

249 |
250 |
251 | 252 |
253 |
254 |
255 | 256 | Example 7 257 | 258 |
<input
 259 |   multiple
 260 |   class="multi"
 261 |   maxlength="10"
 262 | />
263 |
264 | Limit: 10 files. 265 |
Allowed extensions: any. 266 |
267 |
268 | 269 |
270 |
271 |
272 |
273 |
274 | 275 | Example 8 276 | 277 |
<input
 278 |   multiple
 279 |   class="multi"
 280 |   accept="gif|jpg|png"
 281 | />
282 |
283 | Limit: no limit. 284 |
Allowed extensions: gif, jpg. 285 |
286 |
287 | 288 |
289 |
290 |
291 |
292 |
293 | 294 | Example 9 295 | 296 |
<input
 297 |   multiple
 298 |   class="multi"
 299 |   maxlength="10"
 300 |   accept="gif|jpg|png"
 301 | />
302 |
303 | Limit: 10 files 304 |
Allowed extensions: gif, jpg, png. 305 |
306 |
307 | 308 |
309 |
310 | Note that server-side validation is always required 311 |
312 |
313 |
314 |
315 | 316 |
317 |
318 | 319 |

Validating Sizes

320 | 321 |
322 |
323 |

It's common to validate the size of the files being selected prior to upload.

324 |
325 |
326 | 327 |
328 |
329 |
330 | 331 | Example 10a 332 | 333 |

Using class maxsize-* (* = max size in kb)

334 |
<input
 335 |   multiple
 336 |   class="multi maxsize-5120"
 337 | />
338 |
339 | Limit: any number of files 340 |
Allowed extensions: any. 341 |
Max payload: 5MB 342 |
343 |
344 | 345 |
346 |
347 |
348 |
349 |
350 | 351 | Example 10b 352 | 353 |

Using data-maxsize attribute (max size in kb)

354 |
<input
 355 |   multiple
 356 |   class="multi"
 357 |   maxlength="3"
 358 |   data-maxsize="1024"
 359 | />
360 |
361 | Limit: 3 files (under <1MB in total) 362 |
363 |
364 | 365 |
366 |
367 |
368 |
369 |
370 | 371 | Example 10c 372 | 373 |

Use data-maxfile to validate individual files

374 |
<input
 375 |   multiple
 376 |   class="multi"
 377 |   maxlength="3"
 378 |   data-maxfile="1024"
 379 | />
380 |
381 | Limit: 3 files (under <1MB each) 382 |
383 |
384 | 385 |
386 |
387 | Note that server-side validation is always required 388 |
389 |
390 |
391 |
392 | 393 |
394 | 395 |

With an Image Preview

396 | 397 |
398 |
399 |

There's an easy way to add a preview of the image being uploaded

400 |
401 |
402 | 403 |
404 |
405 |
406 | 407 | Example 11a 408 | 409 |

Using class with-preview

410 |
<input
 411 |   multiple
 412 |   class="multi with-preview"
 413 | />
414 |
415 | 416 |
417 |
418 |
419 |
420 | 421 |
422 |
423 | 424 | 425 |

Advanced Examples

426 |
427 |
428 |
429 | IMPORTANT: Don't use class="multi" if you use any of the examples below this point. 430 |
431 |
432 |
433 |

434 | If you use class="multi" the plugin will be initialised automatically 435 | (taking precedence over your code). 436 |

437 |

438 | You must invoke the plugin with your own selector when you use any of the examples below. 439 |

440 |
441 |
442 | Something like 443 |
<input type="file" class="this-is-your-class" />
. 444 |
445 |
446 | Followed by 447 |
// this is your code
 448 | $(function(){ // wait for page to load
 449 | 
 450 |   // this is your selector
 451 |   $('input.this-is-your-class').MultiFile({
 452 |     // your options go here
 453 |     max: 2,
 454 |     accept: 'jpg|png|gif'
 455 |   });
 456 | 
 457 | });
458 |

459 |
460 |
461 | 462 |
463 |
464 |
465 |

Setting limit via script

466 |
<input multiple type="file" id="UpTo3Files"/>
467 |
// wait for document to load
 468 | $(function(){
 469 | 
 470 |   // up to 3 files can be selected
 471 | 
 472 |   // invoke plugin
 473 |   $('#UpTo3Files').MultiFile(5);
 474 | 
 475 |   // if you send in a number the plugin
 476 |   // will treat it as the file limit
 477 | 
 478 | });
479 |
480 | Try it: 481 | 482 | 493 |
494 |
495 |
496 |

Limit and Extension Filter

497 |
<input multiple type="file" id="UpTo3Images"/>
498 |
// wait for document to load
 499 | $(function(){
 500 | 
 501 |   // up to 3 files can be selected
 502 |   // only images are allowed
 503 | 
 504 |   // invoke plugin
 505 |   $('#UpTo3Images').MultiFile({
 506 |     max: 3,
 507 |     accept: 'gif|jpg|png'
 508 |   });
 509 | 
 510 | });
511 |
512 | Try it: 513 | 514 | 526 |
527 |
528 |
529 |

Multi-lingual support

530 |
<input multiple type="file" id="EmPortugues"/>
531 |
// wait for document to load
 532 | $(function(){
 533 | 
 534 |   // use a different language
 535 |   // $file prints the file name
 536 |   // $ext prints the file extension
 537 | 
 538 |   // invoke plugin
 539 |   $('#EmPortugues').MultiFile({
 540 |     max: 3,
 541 |     accept: 'gif|jpg|png'
 542 |     STRING: {
 543 |       remove:'Remover',
 544 |       selected:'Selecionado: $file',
 545 |       denied:'Invalido arquivo de tipo $ext!'
 546 |     }
 547 |   });
 548 | 
 549 | });
550 |
551 | Try it: 552 | 553 | 571 |
572 |
573 | 574 |
575 |
576 | 577 |
578 |

Moving the file list

579 |
580 |
581 |
582 | 587 |

This example populates the file list in a custom element

588 |
$(function() { // wait for document to load
 589 |   $('#T7').MultiFile({
 590 |     list: '#T7-list'
 591 |   });
 592 | });
593 | 600 |
601 |
602 |
603 |
604 | 605 |
606 |
607 | This is div#T7-list - selected files will be populated here... 608 |
609 |
610 |
611 |
612 |
613 |
614 | 615 |
616 |

Customising the file list

617 |
618 | 619 |
620 | 621 | 622 |
623 | 628 |

Use a custom 'remove' image in the file list

629 |
$(function() { // wait for document to load
 630 |   $('#T8A').MultiFile({
 631 |     STRING: {
 632 |       remove: '<img src="/i/bin.gif" height="16" width="16" alt="x"/>'
 633 |     }
 634 |   });
 635 | });
636 | 645 |
646 |
647 |
648 |
649 | 650 |
651 |
652 | 653 |
654 |
655 | 656 |
657 |
658 |
659 |
660 | 665 |

Customising all list content

666 |
$(function() { // wait for document to load
 667 |   $('#T8B').MultiFile({
 668 |     STRING: {
 669 |       file: '<em title="Click to remove" onclick="$(this).parent().prev().click()">$file</em>',
 670 |       remove: '<img src="/i/bin.gif" height="16" width="16" alt="x"/>'
 671 |     }
 672 |   });
 673 | });
674 | 684 |
685 |
686 |
687 |
688 | 689 |
690 |
691 |
692 |
693 | 694 |
695 |

Using events

696 |
697 |
698 |
699 |

700 | The arguments passed on to each event handler are: 701 |
element: file element which triggered the event 702 |
value: the value of the element in question 703 |
master_element: the original element containing all relevant settings 704 |

705 |
706 |
707 |

708 | Selection events: 709 |

    710 |
  • onFileAppend
  • 711 |
  • afterFileAppend
  • 712 |
  • onFileSelect
  • 713 |
  • afterFileSelect
  • 714 |
  • onFileRemove
  • 715 |
  • afterFileRemove
  • 716 |
717 |

718 |
719 |
720 |

721 | Validation events: 722 |

    723 |
  • onFileDuplicate
  • 724 |
  • onFileInvalid
  • 725 |
  • onFileTooMany
  • 726 |
  • onFileTooBig
  • 727 |
  • onFileTooMuch
  • 728 |
729 |

730 |
731 |
732 |
733 |
734 |
735 | 740 |
<input multiple type="file" id="WithEvents"/>
741 |
// wait for document to load
 742 | $(function(){
 743 | 
 744 |   // 2 jpgs under 100kb only
 745 | 
 746 |   $('#WithEvents').MultiFile({
 747 |     max: 2,
 748 |     max_size: 100,
 749 |     accept: 'jpg|png|gif',
 750 |     onFileRemove: function(element, value, master_element) {
 751 |       $('#F9-Log').append('<li>onFileRemove - ' + value + '</li>')
 752 |     },
 753 |     afterFileRemove: function(element, value, master_element) {
 754 |       $('#F9-Log').append('<li>afterFileRemove - ' + value + '</li>')
 755 |     },
 756 |     onFileAppend: function(element, value, master_element) {
 757 |       $('#F9-Log').append('<li>onFileAppend - ' + value + '</li>')
 758 |     },
 759 |     afterFileAppend: function(element, value, master_element) {
 760 |       $('#F9-Log').append('<li>afterFileAppend - ' + value + '</li>')
 761 |     },
 762 |     onFileSelect: function(element, value, master_element) {
 763 |       $('#F9-Log').append('<li>onFileSelect - ' + value + '</li>')
 764 |     },
 765 |     afterFileSelect: function(element, value, master_element) {
 766 |       $('#F9-Log').append('<li>afterFileSelect - ' + value + '</li>')
 767 |     },
 768 |     onFileInvalid: function(element, value, master_element) {
 769 |       $('#F9-Log').append('<li>onFileInvalid - ' + value + '</li>')
 770 |     },
 771 |     onFileDuplicate: function(element, value, master_element) {
 772 |       $('#F9-Log').append('<li>onFileDuplicate - ' + value + '</li>')
 773 |     },
 774 |     onFileTooMany: function(element, value, master_element) {
 775 |       $('#F9-Log').append('<li>onFileTooMany - ' + value + '</li>')
 776 |     },
 777 |     onFileTooBig: function(element, value, master_element) {
 778 |       $('#F9-Log').append('<li>onFileTooBig - ' + value + '</li>')
 779 |     },
 780 |     onFileTooMuch: function(element, value, master_element) {
 781 |       $('#F9-Log').append('<li>onFileTooMuch - ' + value + '</li>')
 782 |     }
 783 |   });
 784 | });
785 | 824 |
825 |
826 |
827 |
828 | 829 |
830 |
831 | This is div#F9-Log - selected files will be populated here... 832 |
833 |
    834 | 835 |
836 |
837 |
838 |
839 |
840 |
841 | 842 | 843 |
844 |
845 | 846 |
847 | 848 | 849 |
850 |

Multi-lingual support

851 |

852 | The plugin doesn't have any additional languages built-in, but it's very easy to customise the messages to any language of your choosing. See the examples below... 853 |

854 |

855 | NB.: This example has been configured to accept gif/pg files only in order to demonstrate the error messages. 856 |

857 |
858 | 859 |
860 | 861 |

Method 1: Using class property (requires the MetaData plugin)

862 |
<input type="file"
 863 |   class="multi {
 864 |     accept:'gif|jpg',
 865 |     max:3,
 866 |     STRING:{
 867 |       remove:'Remover',
 868 |       selected:'Selecionado: $file',
 869 |       denied:'Invalido arquivo de tipo $ext!',
 870 |       duplicate:'Arquivo ja selecionado:\n$file!'
 871 |     }
 872 |   }"
 873 | />
874 | 875 |

Method 2: Programatically by ID (ONE element only, does not require MetaData plugin)

876 |
<input type="file" id="PortugueseFileUpload" />
877 |
$(function(){
 878 |   $('#PortugueseFileUpload').MultiFile({
 879 |     accept:'gif|jpg',
 880 |     max:3,
 881 |     STRING: {
 882 |       remove:'Remover',
 883 |       selected:'Selecionado: $file',
 884 |       denied:'Invalido arquivo de tipo $ext!',
 885 |       duplicate:'Arquivo ja selecionado:\n$file!'
 886 |     }
 887 |   });
 888 | });
889 | 890 |

Method 3: Programatically ( 891 | n emlements, does not require MetaData plugin)

892 | See this feature request for details 893 |
894 |
<input type="file" class="multi-pt" />
 895 | <input type="file" class="multi-pt" />
 896 | <input type="file" class="multi-pt" />
897 |
$(function(){
 898 |   $('.multi-pt').MultiFile({
 899 |     accept:'gif|jpg',
 900 |     max:3,
 901 |     STRING: {
 902 |       remove:'Remover',
 903 |       selected:'Selecionado: $file',
 904 |       denied:'Invalido arquivo de tipo $ext!',
 905 |       duplicate:'Arquivo ja selecionado:\n$file!'
 906 |     }
 907 |   });
 908 | });
909 | 910 |
911 | 912 | 913 |
914 |

Installation

915 | 916 |

Requirements

917 |

You'll need jQuery, we recommend using Google Hosted Libraries.

918 |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js" type="text/javascript" language="javascript"></script>
919 | 920 |

The plugin

921 |

922 | Either download the latest version and host it on your own server 923 |

924 |
<script src="path/to/your/jquery.MultiFile.js" type="text/javascript" language="javascript"></script>
925 | 926 |

927 | OR if you like living on the edge, hotlink the latest release directly from GitHub 928 |

929 |
<script src="//github.com/fyneworks/multifile/blob/master/jquery.MultiFile.min.js" type="text/javascript" language="javascript"></script>
930 | 931 |
932 | 933 | 934 |
935 |

Support

936 |
937 |
938 | 939 |

940 | We very much encourage and would love you all to report issues, contribue and discuss this project on GitHub. 941 |

942 |

943 | There's also a README.md for quick reference, if you're that way inclined. 944 |

945 |

946 | This project started a a very long time ago... and it's been dormant since 2009! Support has been shockingly bad, we admit, 947 | but we would like to engage more actively with our users and the jQuery community from now on. So as of April 2014, 948 | we've left Google Code behind and 949 | will be starting a fresh project on GitHub. 950 | Our other projects (Star Rating & CKEditor will follow shortly). 951 |

952 |
953 |
954 |
955 | 956 | 957 |
958 |

Credit where it's due!

959 |
960 |
961 |
    962 |
  • Fyneworks.com professional web design and google SEO experts 963 |
  • 964 |
  • Dean Edwards - Author of JS Packer used to compress the plugin
  • 965 |
  • Adrian Wróbel - Fixed a nasty bug so the script could work perfectly in Opera
  • 966 |
  • Jonas Wagner - Modified plugin so newly created elements are an exact copy of the original element (ie.: persists attributes)
  • 967 |
  • Mike Alsup - Author of several jQuery Plugins... 968 |
      969 |
    • Suggested solution to element naming convention / server-side handling
    • 970 |
    • Form plugin - Used to submit forms via ajax
    • 971 |
    • blockUI plugin - Used to show pretty error messages
    • 972 |
    973 |
  • 974 |
  • Julien Phalip - Identified conflict with variable name 'class' in several methods
  • 975 |
976 |
977 |
978 |
979 | 980 | 981 |
982 |

License Info

983 |
984 |
985 |
986 | 987 | 988 | 995 | 1001 | 1002 | 1003 | 1027 | 1028 |
989 | Multiple File Selection Plugin 990 | by Fyneworks.com 991 | is licensed, 992 | as jQuery is, under the 993 | MIT License. 994 | 996 | OSI Certified
Open Source™
Software 1000 |
1004 | 1026 |
1029 |
1030 |
1031 |
1032 | 1033 |
1034 | 1035 |
1036 | 1037 |
1038 | 1039 | 1040 | 1065 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1100 | -------------------------------------------------------------------------------- /docs/jquery.MetaData.js: -------------------------------------------------------------------------------- 1 | /* Jörn Zaefferer, Paul McLanahan 2 | * 3 | * Licensed under http://en.wikipedia.org/wiki/MIT_License 4 | * 5 | * Revision: $Id: jquery.MetaData.js 49 2013-02-19 01:19:14Z diego.alto@gmail.com $ 6 | * 7 | */ 8 | 9 | /** 10 | * Sets the type of metadata to use. Metadata is encoded in JSON, and each property 11 | * in the JSON will become a property of the element itself. 12 | * 13 | * There are three supported types of metadata storage: 14 | * 15 | * attr: Inside an attribute. The name parameter indicates *which* attribute. 16 | * 17 | * class: Inside the class attribute, wrapped in curly braces: { } 18 | * 19 | * elem: Inside a child element (e.g. a script tag). The 20 | * name parameter indicates *which* element. 21 | * 22 | * The metadata for an element is loaded the first time the element is accessed via jQuery. 23 | * 24 | * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements 25 | * matched by expr, then redefine the metadata type and run another $(expr) for other elements. 26 | * 27 | * @name $.metadata.setType 28 | * 29 | * @example

This is a p

30 | * @before $.metadata.setType("class") 31 | * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" 32 | * @desc Reads metadata from the class attribute 33 | * 34 | * @example

This is a p

35 | * @before $.metadata.setType("attr", "data") 36 | * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" 37 | * @desc Reads metadata from a "data" attribute 38 | * 39 | * @example

This is a p

40 | * @before $.metadata.setType("elem", "script") 41 | * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" 42 | * @desc Reads metadata from a nested script element 43 | * 44 | * @param String type The encoding type 45 | * @param String name The name of the attribute to be used to get metadata (optional) 46 | * @cat Plugins/Metadata 47 | * @descr Sets the type of encoding to be used when loading metadata for the first time 48 | * @type undefined 49 | * @see metadata() 50 | */ 51 | 52 | (function($) { 53 | 54 | $.extend({ 55 | metadata : { 56 | defaults : { 57 | type: 'class', 58 | name: 'metadata', 59 | cre: /({.*})/, 60 | single: 'metadata' 61 | }, 62 | setType: function( type, name ){ 63 | this.defaults.type = type; 64 | this.defaults.name = name; 65 | }, 66 | get: function( elem, opts ){ 67 | var settings = $.extend({},this.defaults,opts); 68 | // check for empty string in single property 69 | if ( !settings.single.length ) settings.single = 'metadata'; 70 | 71 | var data = $.data(elem, settings.single); 72 | // returned cached data if it already exists 73 | if ( data ) return data; 74 | 75 | data = "{}"; 76 | 77 | if ( settings.type == "class" ) { 78 | var m = settings.cre.exec( elem.className ); 79 | if ( m ) 80 | data = m[1]; 81 | } else if ( settings.type == "elem" ) { 82 | if( !elem.getElementsByTagName ) 83 | return undefined; 84 | var e = elem.getElementsByTagName(settings.name); 85 | if ( e.length ) 86 | data = $.trim(e[0].innerHTML); 87 | } else if ( elem.getAttribute != undefined ) { 88 | var attr = elem.getAttribute( settings.name ); 89 | if ( attr ) 90 | data = attr; 91 | } 92 | 93 | if ( data.indexOf( '{' ) <0 ) 94 | data = "{" + data + "}"; 95 | 96 | data = eval("(" + data + ")"); 97 | 98 | $.data( elem, settings.single, data ); 99 | return data; 100 | } 101 | } 102 | }); 103 | 104 | /** 105 | * Returns the metadata object for the first member of the jQuery object. 106 | * 107 | * @name metadata 108 | * @descr Returns element's metadata object 109 | * @param Object opts An object contianing settings to override the defaults 110 | * @type jQuery 111 | * @cat Plugins/Metadata 112 | */ 113 | $.fn.metadata = function( opts ){ 114 | return $.metadata.get( this[0], opts ); 115 | }; 116 | 117 | })(jQuery); 118 | -------------------------------------------------------------------------------- /docs/jquery.MultiFile.min.js: -------------------------------------------------------------------------------- 1 | /* jquery-multifile v2.2.2 @ 2020-04-16 06:05:29 */ 2 | window.jQuery&&function(d){"use strict";function g(e){return 1048576'),f.wrapper=d("#"+f.wrapID),f.e.name=f.e.name||"file"+i+"[]",f.list||(f.wrapper.append('
'),f.list=d("#"+f.wrapID+"_list")),f.list=d(f.list),f.addSlave=function(u,m){var e;f.n++,u.MultiFile=f,u.id=u.name="",u.id=f.generateID(m),u.name=String(f.namePattern.replace(/\$name/gi,d(f.clone).attr("name")).replace(/\$id/gi,d(f.clone).attr("id")).replace(/\$g/gi,i).replace(/\$i/gi,m)),0f.max&&(e=u.disabled=!0),f.current=u,(u=d(u)).val("").attr("value","")[0].value="",u.addClass("MultiFile-applied"),u.change(function(e,i,t){d(this).blur();var r=this,a=f.files||[],l=this.files||[{name:this.value,size:0,type:((this.value||"").match(/[^\.]+$/i)||[""])[0]}],n=[],s=0,c=f.total_size||0,o=[];d.each(l,function(e,i){n[n.length]=i}),f.trigger("FileSelect",this,f,n),d.each(l,function(e,i){function a(e){return e.replace("$ext",String(l.match(/[^\.]+$/i)||"")).replace("$file",l.match(/[^\/\\]+$/gi)).replace("$size",g(t)+" > "+g(f.maxfile))}var l=i.name.replace(/^C:\\fakepath\\/gi,""),t=i.size;f.accept&&l&&!l.match(f.rxAccept)&&(o[o.length]=a(f.STRING.denied),f.trigger("FileInvalid",this,f,[i])),d(f.wrapper).find("input[type=file]").not(r).each(function(){d.each(h(this),function(e,i){if(i.name){var t=(i.name||"").replace(/^C:\\fakepath\\/gi,"");l!=t&&l!=t.substr(t.length-l.length)||(o[o.length]=a(f.STRING.duplicate),f.trigger("FileDuplicate",r,f,[i]))}})}),0f.maxfile&&(o[o.length]=a(f.STRING.toobig),f.trigger("FileTooBig",this,f,[i]));var n=f.trigger("FileValidate",this,f,[i]);n&&""!=n&&(o[o.length]=a(n)),s+=i.size}),c+=s,n.size=s,n.total=c,n.total_length=n.length+a.length,0f.max&&(o[o.length]=f.STRING.toomany.replace("$max",f.max),f.trigger("FileTooMany",this,f,n)),0f.maxsize&&(o[o.length]=f.STRING.toomuch.replace("$size",g(c)+" > "+g(f.maxsize)),f.trigger("FileTooMuch",this,f,n));var p=d(f.clone).clone();if(p.addClass("MultiFile"),0");d.each(i,function(e,t){var i=String(t.name||"").replace(/[&<>'"]/g,function(e){return"&#"+e.charCodeAt()+";"}),a=f.STRING,l=a.label||a.file||a.name,n=a.title||a.tooltip||a.selected,r="image/"==t.type.substr(0,6)?'':"",s=d((''+l+""+(f.preview||d(c).is(".with-preview")?r:"")+"").replace(/\$(file|name)/gi,(i.match(/[^\/\\]+$/gi)||[i])[0]).replace(/\$(ext|extension|type)/gi,(i.match(/[^\.]+$/gi)||[""])[0]).replace(/\$(size)/gi,g(t.size||0)).replace(/\$(preview)/gi,r).replace(/\$(i)/gi,e));s.find("img.MultiFile-preview").each(function(){var i=this,e=new FileReader;e.readAsDataURL(t),e.onload=function(e){i.src=e.target.result}}),0'+f.STRING.file+"").replace(/\$(file|name)/gi,(i.match(/[^\/\\]+$/gi)||[i])[0]).replace(/\$(ext|extension|type)/gi,(i.match(/[^\.]+$/gi)||[""])[0]).replace(/\$(size)/gi,g(t.size||0)).replace(/\$(i)/gi,e)});var t=d('
'),a=d(''+f.STRING.remove+"").click(function(){var e=h(c);f.trigger("FileRemove",c,f,e),f.n--,f.current.disabled=!1,d(c).remove(),d(this).parent().remove(),d(f.current).css({position:"",top:""}),d(f.current).reset().val("").attr("value","")[0].value="";var t=[],a=0;return d(f.wrapper).find("input[type=file]").each(function(){d.each(h(this),function(e,i){i.name&&(t[t.length]=i,a+=i.size)})}),f.files=t,f.total_size=a,f.size_label=g(a),d(f.wrapper).data("MultiFile",f),f.trigger("afterFileRemove",c,f,e),f.trigger("FileChange",f.current,f,t),!1});f.list.append(t.append(a," ",o)),f.trigger("afterFileAppend",c,f,i),f.trigger("FileChange",c,f,f.files)},f.MultiFile||f.addSlave(f.e,0),f.n++})},d.extend(d.fn.MultiFile,{data:function(){var e=d(this),i=e.is(".MultiFile-wrap")?e:e.data("MultiFile-wrap");if(!i||!i.length)return!console.error("Could not find MultiFile control wrapper");var t=i.data("MultiFile");return t?t||{}:!console.error("Could not find MultiFile data in wrapper")},reset:function(){var e=this.MultiFile("data");return e&&d(e.list).find("a.MultiFile-remove").click(),d(this)},files:function(){var e=this.MultiFile("data");return e?e.files||[]:!console.log("MultiFile plugin not initialized")},size:function(){var e=this.MultiFile("data");return e?e.total_size||0:!console.log("MultiFile plugin not initialized")},count:function(){var e=this.MultiFile("data");return e?e.files&&e.files.length||0:!console.log("MultiFile plugin not initialized")},disableEmpty:function(e){e=("string"==typeof e?e:"")||"mfD";var i=[];return d("input:file.MultiFile").each(function(){""==d(this).val()&&(i[i.length]=this)}),window.clearTimeout(d.fn.MultiFile.reEnableTimeout),d.fn.MultiFile.reEnableTimeout=window.setTimeout(d.fn.MultiFile.reEnableEmpty,500),d(i).each(function(){this.disabled=!0}).addClass(e)},reEnableEmpty:function(e){return d("input:file."+(e=("string"==typeof e?e:"")||"mfD")).removeClass(e).each(function(){this.disabled=!1})},intercepted:{},intercept:function(e,i,t){var a,l;if((t=t||[]).constructor.toString().indexOf("Array")<0&&(t=[t]),"function"==typeof e)return d.fn.MultiFile.disableEmpty(),l=e.apply(i||window,t),setTimeout(function(){d.fn.MultiFile.reEnableEmpty()},1e3),l;e.constructor.toString().indexOf("Array")<0&&(e=[e]);for(var n=0;n").get(0).files !== undefined; 58 | feature.formdata = window.FormData !== undefined; 59 | 60 | /** 61 | * ajaxSubmit() provides a mechanism for immediately submitting 62 | * an HTML form using AJAX. 63 | */ 64 | $.fn.ajaxSubmit = function(options) { 65 | /*jshint scripturl:true */ 66 | 67 | // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) 68 | if (!this.length) { 69 | log('ajaxSubmit: skipping submit process - no element selected'); 70 | return this; 71 | } 72 | 73 | var method, action, url, $form = this; 74 | 75 | if (typeof options == 'function') { 76 | options = { success: options }; 77 | } 78 | 79 | method = this.attr('method'); 80 | action = this.attr('action'); 81 | url = (typeof action === 'string') ? $.trim(action) : ''; 82 | url = url || window.location.href || ''; 83 | if (url) { 84 | // clean url (don't include hash vaue) 85 | url = (url.match(/^([^#]+)/)||[])[1]; 86 | } 87 | 88 | options = $.extend(true, { 89 | url: url, 90 | success: $.ajaxSettings.success, 91 | type: method || 'GET', 92 | iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' 93 | }, options); 94 | 95 | // hook for manipulating the form data before it is extracted; 96 | // convenient for use with rich editors like tinyMCE or FCKEditor 97 | var veto = {}; 98 | this.trigger('form-pre-serialize', [this, options, veto]); 99 | if (veto.veto) { 100 | log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); 101 | return this; 102 | } 103 | 104 | // provide opportunity to alter form data before it is serialized 105 | if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { 106 | log('ajaxSubmit: submit aborted via beforeSerialize callback'); 107 | return this; 108 | } 109 | 110 | var traditional = options.traditional; 111 | if ( traditional === undefined ) { 112 | traditional = $.ajaxSettings.traditional; 113 | } 114 | 115 | var elements = []; 116 | var qx, a = this.formToArray(options.semantic, elements); 117 | if (options.data) { 118 | options.extraData = options.data; 119 | qx = $.param(options.data, traditional); 120 | } 121 | 122 | // give pre-submit callback an opportunity to abort the submit 123 | if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { 124 | log('ajaxSubmit: submit aborted via beforeSubmit callback'); 125 | return this; 126 | } 127 | 128 | // fire vetoable 'validate' event 129 | this.trigger('form-submit-validate', [a, this, options, veto]); 130 | if (veto.veto) { 131 | log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); 132 | return this; 133 | } 134 | 135 | var q = $.param(a, traditional); 136 | if (qx) { 137 | q = ( q ? (q + '&' + qx) : qx ); 138 | } 139 | if (options.type.toUpperCase() == 'GET') { 140 | options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; 141 | options.data = null; // data is null for 'get' 142 | } 143 | else { 144 | options.data = q; // data is the query string for 'post' 145 | } 146 | 147 | var callbacks = []; 148 | if (options.resetForm) { 149 | callbacks.push(function() { $form.resetForm(); }); 150 | } 151 | if (options.clearForm) { 152 | callbacks.push(function() { $form.clearForm(options.includeHidden); }); 153 | } 154 | 155 | // perform a load on the target only if dataType is not provided 156 | if (!options.dataType && options.target) { 157 | var oldSuccess = options.success || function(){}; 158 | callbacks.push(function(data) { 159 | var fn = options.replaceTarget ? 'replaceWith' : 'html'; 160 | $(options.target)[fn](data).each(oldSuccess, arguments); 161 | }); 162 | } 163 | else if (options.success) { 164 | callbacks.push(options.success); 165 | } 166 | 167 | options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg 168 | var context = options.context || this ; // jQuery 1.4+ supports scope context 169 | for (var i=0, max=callbacks.length; i < max; i++) { 170 | callbacks[i].apply(context, [data, status, xhr || $form, $form]); 171 | } 172 | }; 173 | 174 | // are there files to upload? 175 | 176 | // [value] (issue #113), also see comment: 177 | // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219 178 | var fileInputs = $('input[type=file]:enabled[value!=""]', this); 179 | 180 | var hasFileInputs = fileInputs.length > 0; 181 | var mp = 'multipart/form-data'; 182 | var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); 183 | 184 | var fileAPI = feature.fileapi && feature.formdata; 185 | log("fileAPI :" + fileAPI); 186 | var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; 187 | 188 | var jqxhr; 189 | 190 | // options.iframe allows user to force iframe mode 191 | // 06-NOV-09: now defaulting to iframe mode if file input is detected 192 | if (options.iframe !== false && (options.iframe || shouldUseFrame)) { 193 | // hack to fix Safari hang (thanks to Tim Molendijk for this) 194 | // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d 195 | if (options.closeKeepAlive) { 196 | $.get(options.closeKeepAlive, function() { 197 | jqxhr = fileUploadIframe(a); 198 | }); 199 | } 200 | else { 201 | jqxhr = fileUploadIframe(a); 202 | } 203 | } 204 | else if ((hasFileInputs || multipart) && fileAPI) { 205 | jqxhr = fileUploadXhr(a); 206 | } 207 | else { 208 | jqxhr = $.ajax(options); 209 | } 210 | 211 | $form.removeData('jqxhr').data('jqxhr', jqxhr); 212 | 213 | // clear element array 214 | for (var k=0; k < elements.length; k++) 215 | elements[k] = null; 216 | 217 | // fire 'notify' event 218 | this.trigger('form-submit-notify', [this, options]); 219 | return this; 220 | 221 | // utility fn for deep serialization 222 | function deepSerialize(extraData){ 223 | var serialized = $.param(extraData).split('&'); 224 | var len = serialized.length; 225 | var result = []; 226 | var i, part; 227 | for (i=0; i < len; i++) { 228 | // #252; undo param space replacement 229 | serialized[i] = serialized[i].replace(/\+/g,' '); 230 | part = serialized[i].split('='); 231 | // #278; use array instead of object storage, favoring array serializations 232 | result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]); 233 | } 234 | return result; 235 | } 236 | 237 | // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz) 238 | function fileUploadXhr(a) { 239 | var formdata = new FormData(); 240 | 241 | for (var i=0; i < a.length; i++) { 242 | formdata.append(a[i].name, a[i].value); 243 | } 244 | 245 | if (options.extraData) { 246 | var serializedData = deepSerialize(options.extraData); 247 | for (i=0; i < serializedData.length; i++) 248 | if (serializedData[i]) 249 | formdata.append(serializedData[i][0], serializedData[i][1]); 250 | } 251 | 252 | options.data = null; 253 | 254 | var s = $.extend(true, {}, $.ajaxSettings, options, { 255 | contentType: false, 256 | processData: false, 257 | cache: false, 258 | type: method || 'POST' 259 | }); 260 | 261 | if (options.uploadProgress) { 262 | // workaround because jqXHR does not expose upload property 263 | s.xhr = function() { 264 | var xhr = jQuery.ajaxSettings.xhr(); 265 | if (xhr.upload) { 266 | xhr.upload.addEventListener('progress', function(event) { 267 | var percent = 0; 268 | var position = event.loaded || event.position; /*event.position is deprecated*/ 269 | var total = event.total; 270 | if (event.lengthComputable) { 271 | percent = Math.ceil(position / total * 100); 272 | } 273 | options.uploadProgress(event, position, total, percent); 274 | }, false); 275 | } 276 | return xhr; 277 | }; 278 | } 279 | 280 | s.data = null; 281 | var beforeSend = s.beforeSend; 282 | s.beforeSend = function(xhr, o) { 283 | o.data = formdata; 284 | if(beforeSend) 285 | beforeSend.call(this, xhr, o); 286 | }; 287 | return $.ajax(s); 288 | } 289 | 290 | // private function for handling file uploads (hat tip to YAHOO!) 291 | function fileUploadIframe(a) { 292 | var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; 293 | var useProp = !!$.fn.prop; 294 | var deferred = $.Deferred(); 295 | 296 | if (a) { 297 | // ensure that every serialized input is still enabled 298 | for (i=0; i < elements.length; i++) { 299 | el = $(elements[i]); 300 | if ( useProp ) 301 | el.prop('disabled', false); 302 | else 303 | el.removeAttr('disabled'); 304 | } 305 | } 306 | 307 | s = $.extend(true, {}, $.ajaxSettings, options); 308 | s.context = s.context || s; 309 | id = 'jqFormIO' + (new Date().getTime()); 310 | if (s.iframeTarget) { 311 | $io = $(s.iframeTarget); 312 | n = $io.attr('name'); 313 | if (!n) 314 | $io.attr('name', id); 315 | else 316 | id = n; 317 | } 318 | else { 319 | $io = $(' 60 | 61 | 62 | 63 | 76 | 77 | 78 |
<form action="test.php" method="post" enctype="multipart/form-data" target="upload-frame">
79 | 	<input type="submit" value="Report"/> (will NEVER upload)
80 | 	<br/>
81 | 	<input name="files[]" type="file" multiple="multiple" class="multi maxsize-1024" />
82 | </form>
83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /test/maxfile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 39 | 47 |
48 | 49 |
50 |
51 |
52 | 53 |
54 |
55 | 56 |
57 | Files will never be uploaded. You can see the code here. 58 |
59 | 60 |
61 |
62 |
63 | 76 | 77 | 78 |
<form action="test.php" method="post" enctype="multipart/form-data" target="upload-frame">
79 | 	<input type="submit" value="Report"/> (will NEVER upload)
80 | 	<br/>
81 | 	<input name="files[]" type="file" multiple="multiple" class="multi maxfile-1024" />
82 | </form>
83 | 84 |
85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /test/maxsize.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 39 | 47 |
48 | 49 |
50 |
51 |
52 | 53 |
54 |
55 | 56 |
57 | Files will never be uploaded. You can see the code here. 58 |
59 | 60 |
61 |
62 |
63 | 76 | 77 | 78 |
<form action="test.php" method="post" enctype="multipart/form-data" target="upload-frame">
79 | 	<input type="submit" value="Report"/> (will NEVER upload)
80 | 	<br/>
81 | 	<input name="files[]" type="file" multiple="multiple" class="multi maxsize-1024" />
82 | </form>
83 | 84 |
85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /test/nocomma.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 39 | 47 |
48 | 49 |
50 |
51 |
52 | 53 |
54 |
55 | 56 |
57 | Files will never be uploaded. You can see the code here. 58 |
59 | 60 |
61 |
62 |
63 | 82 | 83 | 84 |
<form action="test.php" method="post" enctype="multipart/form-data" target="upload-frame">
 85 | 	<input type="submit" value="Report"/> (will NEVER upload)
 86 | 	<br/>
 87 | 	<input name="files[]" type="file" multiple="multiple" class="multi maxsize-1024" />
 88 | </form>
89 | 90 |
91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /test/preview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Preview | MultiFile Test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 39 | 47 |
48 | 49 |
50 |
51 |
52 | 53 |
54 |
55 | 56 |
57 | Files will never be uploaded. You can see the code here. 58 |
59 | 60 |
61 |
62 |
63 | 76 | 77 | 78 |
<form action="test.php" method="post" enctype="multipart/form-data" target="upload-frame">
79 | 	<input type="submit" value="Report"/> (will NEVER upload)
80 | 	<br/>
81 | 	<input name="files[]" type="file" multiple="multiple" class="multi with-preview" />
82 | </form>
83 | 84 |
85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /test/test.php: -------------------------------------------------------------------------------- 1 | >>>>>>>>>'.$nl); 7 | print_r($_FILES); 8 | //echo('<<<<<<<<<<<<<<'.$nl.$nl); 9 | 10 | //echo('POST DATA'.' >>>>>>>>>>'.$nl); 11 | //print_r($_POST); 12 | //echo('<<<<<<<<<<<<<<'.$nl.$nl); 13 | 14 | //echo('REQUEST HEADERS:'.'>>>>>>>>>>'.$nl); 15 | //print_r($_REQUEST); 16 | //echo('<<<<<<<<<<<<<<'.$nl.$nl); 17 | -------------------------------------------------------------------------------- /test/test1.js: -------------------------------------------------------------------------------- 1 | var webdriver = require('selenium-webdriver'); 2 | 3 | var driver = new webdriver.Builder(). 4 | withCapabilities(webdriver.Capabilities.chrome()). 5 | build(); 6 | 7 | driver.get('http://www.google.com'); 8 | driver.findElement(webdriver.By.name('q')).sendKeys('simple programmer'); 9 | driver.findElement(webdriver.By.name('btnG')).click(); 10 | driver.quit(); 11 | -------------------------------------------------------------------------------- /test/test2.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | test = require('selenium-webdriver/testing'), 3 | webdriver = require('selenium-webdriver'); 4 | 5 | test.describe('Google Search', function() { 6 | test.it('should work', function() { 7 | var driver = new webdriver.Builder(). 8 | withCapabilities(webdriver.Capabilities.chrome()). 9 | build(); 10 | driver.get('http://www.google.com'); 11 | var searchBox = driver.findElement(webdriver.By.name('q')); 12 | searchBox.sendKeys('simple programmer'); 13 | searchBox.getAttribute('value').then(function(value) { 14 | assert.equal(value, 'simple programmer'); 15 | }); 16 | driver.quit(); 17 | }); 18 | }); 19 | --------------------------------------------------------------------------------