Compare commits

...

41 Commits

Author SHA1 Message Date
Linden van der
3e8c18a738 Update simple demo
Also hide table headers with isHTML5 option.
2018-03-21 16:04:36 +01:00
Adrian Fâciu
fb48f4411d Merge pull request #927 from Amos47/development
Expand compression mime types
2017-12-09 23:07:49 +02:00
Adrian Fâciu
e423a3089c Merge pull request #939 from mattmcsparran/patch-1
Updated Readme for easier implementation
2017-12-09 23:06:14 +02:00
Matthew McSparran
502789dad6 Updated Readme
Updated to show what needs to be imported for a project to work like the demo.
2017-12-09 12:42:15 -05:00
Adrian Fâciu
d4bed8a045 Merge pull request #930 from adrianfaciu/release-1.3
Releasing 1.3.0
2017-11-25 19:09:39 +02:00
Adrian Fâciu
954240cfdc Releasing 1.3.0 2017-11-25 19:07:56 +02:00
Jordan Amos
7d25b57e1b expand compression mime types 2017-11-17 16:50:11 -08:00
Adrian Fâciu
0d97b76228 Merge pull request #904 from guanbo/options
Update: setOptions
2017-10-22 13:03:45 +03:00
Adrian Fâciu
9d0408e595 Merge pull request #911 from WisdomFusion/development
add file type .zip
2017-10-22 12:59:19 +03:00
WisdomFusion
35c5131c47 add file type .zip 2017-10-16 08:17:34 +08:00
Guan Bo
ccee135949 Update: setOptions
prevent from overwrite options which set before, such as authToken
2017-10-09 15:42:00 +08:00
Adrian Fâciu
aa1448392b Merge pull request #903 from adrianfaciu/chore/docs
Updating docs and formatting files
2017-10-07 13:00:53 +03:00
Adrian Fâciu
e1e36bbab4 Updating docs and formating files 2017-10-07 12:48:05 +03:00
Adrian Fâciu
bcf40f4407 Merge pull request #649 from infinum/feature/file-like-object-with-raw-file
Add rawFile in the file like object
2017-10-07 12:07:51 +03:00
Adrian Fâciu
e1bc9ff086 Merge pull request #658 from kopertop/development
Adds some Fixes for AWS Support.
2017-10-07 12:06:23 +03:00
Adrian Fâciu
631b4aa607 Merge pull request #786 from albpara/feature/emit-event-when-file-is-selected
Emit event when file is selected
2017-10-07 12:04:31 +03:00
Adrian Fâciu
57b2d0711d Merge branch 'development' into feature/emit-event-when-file-is-selected 2017-10-07 11:53:53 +03:00
Adrian Fâciu
898f297967 Merge pull request #901 from davidmds/development
Add response and function to modify the request body
2017-10-07 11:48:47 +03:00
David Martins
be7f164d98 Updating example 2017-10-06 17:22:20 -03:00
David Martins
4c0c4c70bc Fixing bug in response 2017-10-06 17:20:26 -03:00
David Martins
c84046e86e Update README 2017-10-04 17:03:16 -03:00
David Martins
14812e0cf7 Added option to send request body modifier function 2017-10-04 16:52:28 -03:00
David Martins
5357a243f6 Added event with return of request 2017-10-04 16:36:48 -03:00
Adrian Fâciu
5df3c5f076 Merge pull request #844 from spike31/patch-1
Fix correct path for isHTML5 option
2017-10-02 17:57:14 +03:00
Adrian Fâciu
7fc4945ff0 Merge pull request #857 from joshterrill/development
Added onFileDrop() event to documentation
2017-10-02 17:50:35 +03:00
Adrian Fâciu
0370d334d7 Merge pull request #898 from adrianfaciu/chore/tests
Fixing tests execution and adding a few more tests
2017-10-02 17:27:52 +03:00
Adrian Fâciu
048f534aa2 Adding tests for file select directive 2017-10-01 17:33:38 +03:00
Adrian Fâciu
0df30f996f Fixing test execution on CI 2017-10-01 17:07:54 +03:00
Adrian Fâciu
6bdf60fac4 Adding tests for file drop directive 2017-09-26 23:04:21 +03:00
Adrian
eca11298ee Fixed karma config 2017-09-26 21:40:55 +03:00
Joshua Terrill
28d98bc8af Added onFileDrop() event to documentation
In case anyone wants to use the onFileDrop event to handle the files in their own way, I've added it to the documentation.
2017-08-01 15:08:21 -07:00
Gilles Gauthier
74306fc210 Update simple demo
Fix correct path for isHTML5 option
2017-07-12 11:35:55 +02:00
Alberto Para
1f0ca3072b Emit event when file is selected 2017-05-08 23:55:06 +02:00
Dmitriy Shekhovtsov
41759be974 chore(package): dependencies upgrade 2017-04-10 13:57:32 +03:00
Dmitriy Shekhovtsov
e8d5ced3f6 chore(package): update to angular cli v1.0.0 2017-04-10 13:48:58 +03:00
smartm0use
7704e0e970 feat(package): relaxed peer dependencies to allow ng v4 (#713)
Add Angular 4 peer dependencies support
2017-04-10 13:31:27 +03:00
Chris Moyer
a333c59f82 Make sure it's a string before trying to do indexOf 2017-03-07 09:59:55 -05:00
Chris Moyer
8b36c892d5 Fixes {{file_name}} template 2017-03-06 17:41:47 -05:00
Chris Moyer
0e17d55633 Adds some Fixes for AWS Support.
AWS Requires any additional parameters to be specified BEFORE Files.
This also adds the ability to specify a {{file_name}} template in any
additional parameters to allow adding the filename to additional
parameters.

For example, you can now specify:

additionalParameter: {
	key: "path/to/uploads/{{file_name}}"
}
2017-03-06 17:30:18 -05:00
Charles Mark Maynard
99c83035d1 [On behalf of Lexmark]: Add export of FileLikeObject to allow callback to function (#619) 2017-03-01 23:28:57 +02:00
Gabrijel Škoro
e08f80ee74 Add rawFile in the file like object 2017-02-28 10:09:26 +01:00
24 changed files with 671 additions and 8154 deletions

View File

@@ -19,8 +19,8 @@
],
"scripts": [
],
"environmentSource": "environments/environment.ts",
"environments": {
"source": "environments/environment.ts",
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}

View File

@@ -1,3 +1,28 @@
<a name="1.3.0"></a>
# [1.3.0](https://github.com/valor-software/ng2-file-upload/compare/v1.2.0...v1.3.0) (2017-11-25)
### Features
* **file-upload:** Add response and function to modify the request body ([#901](https://github.com/valor-software/ng2-file-upload/pull/901))
* **file-upload** add file type .zip ([#911](https://github.com/valor-software/ng2-file-upload/pull/911))
### Bug Fixes
* **file-uploader** Update: setOptions ([#904](https://github.com/valor-software/ng2-file-upload/pull/904))
* **docs** Fix correct path for isHTML5 option ([#844](https://github.com/valor-software/ng2-file-upload/pull/844))
* **docs** Added onFileDrop() event to documentation ([#857](https://github.com/valor-software/ng2-file-upload/pull/857))
<a name="1.2.1"></a>
## [1.2.1](https://github.com/valor-software/ng2-file-upload/compare/v1.2.0...v1.2.1) (2017-04-10)
### Features
* **package:** relaxed peer dependencies to allow ng v4 ([#713](https://github.com/valor-software/ng2-file-upload/issues/713)) ([7704e0e](https://github.com/valor-software/ng2-file-upload/commit/7704e0e))
<a name="1.2.0"></a>
# [1.2.0](https://github.com/valor-software/ng2-file-upload/compare/v1.1.3-0...v1.2.0) (2017-01-17)

View File

@@ -18,6 +18,30 @@ Easy to use Angular2 directives for files upload ([demo](http://valor-software.g
3. More information regarding using of ***ng2-file-upload*** is located in
[demo](http://valor-software.github.io/ng2-file-upload/) and [demo sources](https://github.com/valor-software/ng2-file-upload/tree/master/demo).
## Using ***ng2-file-upload*** in a project
1. Install as shown in the above section.
2. Import `FileUploadModule` into the module that declares the component using ***ng2-file-upload***:
```import { FileUploadModule } from 'ng2-file-upload';```
3. Add it to `[imports]` under `@NgModule`:
```imports: [ ... FileUploadModule, ... ]```
4. Import `FileUploader` into the component:
```import { FileUploader } from 'ng2-file-upload';```
5. Create a variable for the API url:
```const URL = 'path_to_api';```
6. Initialize it:
```public uploader:FileUploader = new FileUploader({url: URL}); ```
## API for `ng2FileSelect`
@@ -25,6 +49,9 @@ Easy to use Angular2 directives for files upload ([demo](http://valor-software.g
- `uploader` - (`FileUploader`) - uploader object. See using in [demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts)
### Events
- `onFileSelected` - fires when files are selected and added to the uploader queue
## API for `ng2FileDrop`
### Properties
@@ -37,12 +64,16 @@ Easy to use Angular2 directives for files upload ([demo](http://valor-software.g
2. `authToken` - Auth token that will be applied as 'Authorization' header during file send.
3. `disableMultipart` - If 'true', disable using a multipart form for file upload and instead stream the file. Some APIs (e.g. Amazon S3) may expect the file to be streamed rather than sent via a form. Defaults to false.
4. `itemAlias` - item alias (form name redefenition)
5. `formatDataFunction` - Function to modify the request body. 'DisableMultipart' must be 'true' for this function to be called.
6. `formatDataFunctionIsAsync` - Informs if the function sent in 'formatDataFunction' is asynchronous. Defaults to false.
7. `parametersBeforeFiles` - States if additional parameters should be appended before or after the file. Defaults to false.
### Events
- `fileOver` - it fires during 'over' and 'out' events for Drop Area; returns `boolean`: `true` if file is over Drop Area, `false` in case of out.
See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and
[html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html)
- `onFileDrop` - it fires after a file has been dropped on a Drop Area; you can pass in `$event` to get the list of files that were dropped. i.e. `(onFileDrop)="dropped($event)"`
# Troubleshooting

View File

@@ -3,7 +3,7 @@ import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { TabsModule } from 'ng2-bootstrap';
import { TabsModule } from 'ngx-bootstrap/tabs';
import { FileUploadModule } from 'ng2-file-upload';
import { AppComponent } from './app.component';

View File

@@ -52,8 +52,8 @@
<thead>
<tr>
<th width="50%">Name</th>
<th>Size</th>
<th>Progress</th>
<th *ngIf="uploader.options.isHTML5">Size</th>
<th *ngIf="uploader.options.isHTML5">Progress</th>
<th>Status</th>
<th>Actions</th>
</tr>
@@ -61,8 +61,8 @@
<tbody>
<tr *ngFor="let item of uploader.queue">
<td><strong>{{ item?.file?.name }}</strong></td>
<td *ngIf="uploader.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
<td *ngIf="uploader.isHTML5">
<td *ngIf="uploader.options.isHTML5" nowrap>{{ item?.file?.size/1024/1024 | number:'.2' }} MB</td>
<td *ngIf="uploader.options.isHTML5">
<div class="progress" style="margin-bottom: 0;">
<div class="progress-bar" role="progressbar" [ngStyle]="{ 'width': item.progress + '%' }"></div>
</div>
@@ -115,4 +115,16 @@
</div>
<br><br>
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">Response</div>
<div class="panel-body">
{{ response }}
</div>
</div>
</div>
</div>
</div>

View File

@@ -9,9 +9,36 @@ const URL = 'https://evening-anchorage-3159.herokuapp.com/api/';
templateUrl: './simple-demo.html'
})
export class SimpleDemoComponent {
public uploader:FileUploader = new FileUploader({url: URL});
public hasBaseDropZoneOver:boolean = false;
public hasAnotherDropZoneOver:boolean = false;
uploader:FileUploader;
hasBaseDropZoneOver:boolean;
hasAnotherDropZoneOver:boolean;
response:string;
constructor (){
this.uploader = new FileUploader({
url: URL,
disableMultipart: true, // 'DisableMultipart' must be 'true' for formatDataFunction to be called.
formatDataFunctionIsAsync: true,
formatDataFunction: async (item) => {
return new Promise( (resolve, reject) => {
resolve({
name: item._file.name,
length: item._file.size,
contentType: item._file.type,
date: new Date()
});
});
}
});
this.hasBaseDropZoneOver = false;
this.hasAnotherDropZoneOver = false;
this.response = '';
this.uploader.response.subscribe( res => this.response = res );
}
public fileOverBase(e:any):void {
this.hasBaseDropZoneOver = e;

View File

@@ -25,6 +25,13 @@ import { FileSelectDirective, FileDropDirective, FileUploader } from 'ng2-file-u
1. `url` - URL of File Uploader's route
2. `authToken` - auth token that will be applied as 'Authorization' header during file send.
3. `disableMultipart` - If 'true', disable using a multipart form for file upload and instead stream the file. Some APIs (e.g. Amazon S3) may expect the file to be streamed rather than sent via a form. Defaults to false.
4. `itemAlias` - item alias (form name redefenition)
5. `formatDataFunction` - Function to modify the request body. 'DisableMultipart' must be 'true' for this function to be called.
6. `formatDataFunctionIsAsync` - Informs if the function sent in 'formatDataFunction' is asynchronous. Defaults to false.
7. `parametersBeforeFiles` - States if additional parameters should be appended before or after the file. Defaults to false.
### Events
- `onFileSelected` - fires when files are selected and added to the uploader queue
## FileDrop API
@@ -37,3 +44,4 @@ import { FileSelectDirective, FileDropDirective, FileUploader } from 'ng2-file-u
- `fileOver` - it fires during 'over' and 'out' events for Drop Area; returns `boolean`: `true` if file is over Drop Area, `false` in case of out.
See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and
[html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html)
- `onFileDrop` - it fires after a file has been dropped on a Drop Area; you can pass in `$event` to get the list of files that were dropped. i.e. `(onFileDrop)="dropped($event)"`

View File

@@ -3,7 +3,7 @@
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noEmitHelpers" :true,
"noEmitHelpers": false,
"lib": ["es6", "dom"],
"types": [
"jasmine",

View File

@@ -6,8 +6,8 @@ declare const ENV:string;
// google code-prettify
declare const PR:any;
declare const require:any;
declare const global:any;
// declare const require:any;
// declare const global:any;
declare module jasmine {
interface Matchers {

View File

@@ -6,31 +6,29 @@ const customLaunchers = require('./scripts/sauce-browsers').customLaunchers;
module.exports = function (config) {
const configuration = {
basePath: '',
frameworks: ['jasmine', 'angular-cli'],
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-remap-istanbul'),
require('angular-cli/plugins/karma')
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
files: [
{pattern: './scripts/test.ts', watched: false}
],
preprocessors: {
'./scripts/test.ts': ['angular-cli']
'./scripts/test.ts': ['@angular/cli']
},
remapIstanbulReporter: {
reports: {
html: 'coverage',
lcovonly: './coverage/coverage.lcov'
}
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: false
},
angularCli: {
config: './angular-cli.json',
environment: 'dev'
},
reporters: config.angularCli && config.angularCli.codeCoverage
? ['dots', 'karma-remap-istanbul']
? ['dots', 'coverage-istanbul']
: ['dots'],
port: 9876,
colors: true,

View File

@@ -1,6 +1,6 @@
{
"name": "ng2-file-upload-base",
"version": "1.2.0",
"version": "1.3.0",
"private": true,
"description": "Angular file upload directives",
"scripts": {
@@ -45,10 +45,11 @@
"homepage": "https://github.com/valor-software/ng2-file-upload#readme",
"dependencies": {},
"peerDependencies": {
"@angular/common": "^2.3.0",
"@angular/core": "^2.3.0"
"@angular/common": "^2.3.1 || >=4.0.0",
"@angular/core": "^2.3.1 || >=4.0.0"
},
"devDependencies": {
"@angular/cli": "1.0.0",
"@angular/common": "2.4.3",
"@angular/compiler": "2.4.3",
"@angular/compiler-cli": "2.4.3",
@@ -60,12 +61,10 @@
"@angular/platform-browser-dynamic": "2.4.3",
"@angular/router": "3.4.3",
"@angular/tsc-wrapped": "0.5.1",
"@ngtools/webpack": "1.2.3",
"@types/jasmine": "2.5.40",
"@types/marked": "0.0.28",
"@types/node": "7.0.0",
"@types/webpack": "^2.2.1",
"angular-cli": "1.0.0-beta.25.5",
"bootstrap": "3.3.7",
"chokidar-cli": "1.2.0",
"classlist-polyfill": "1.0.3",
@@ -88,6 +87,7 @@
"karma": "1.4.0",
"karma-chrome-launcher": "^2.0.0",
"karma-cli": "^1.0.1",
"karma-coverage-istanbul-reporter": "^1.3.0",
"karma-jasmine": "^1.0.2",
"karma-remap-istanbul": "0.4.0",
"karma-sauce-launcher": "1.1.0",
@@ -95,9 +95,9 @@
"lodash": "4.17.4",
"markdown-loader": "^0.1.7",
"marked": "0.3.6",
"ng2-bootstrap": "1.2.2",
"ng2-page-scroll": "4.0.0-beta.2",
"ngm-cli": "0.4.0",
"ngx-bootstrap": "1.6.6",
"npm-run-all": "^4.0.1",
"pre-commit": "1.2.2",
"protractor": "5.0.0",

View File

@@ -8,7 +8,7 @@ declare const ENV:string;
// google code-prettify
declare const PR:any;
declare const global:any;
// declare const global:any;
declare module jasmine {
interface Matchers {

View File

@@ -1,29 +1,29 @@
import { Directive, EventEmitter, ElementRef, HostListener, Input, Output } from '@angular/core';
import { FileUploader } from './file-uploader.class';
import { FileUploader, FileUploaderOptions } from './file-uploader.class';
@Directive({selector: '[ng2FileDrop]'})
@Directive({ selector: '[ng2FileDrop]' })
export class FileDropDirective {
@Input() public uploader:FileUploader;
@Output() public fileOver:EventEmitter<any> = new EventEmitter();
@Output() public onFileDrop:EventEmitter<File[]> = new EventEmitter<File[]>();
@Input() public uploader: FileUploader;
@Output() public fileOver: EventEmitter<any> = new EventEmitter();
@Output() public onFileDrop: EventEmitter<File[]> = new EventEmitter<File[]>();
protected element:ElementRef;
protected element: ElementRef;
public constructor(element:ElementRef) {
public constructor(element: ElementRef) {
this.element = element;
}
public getOptions():any {
public getOptions(): FileUploaderOptions {
return this.uploader.options;
}
public getFilters():any {
public getFilters(): any {
return {};
}
@HostListener('drop', ['$event'])
public onDrop(event:any):void {
@HostListener('drop', [ '$event' ])
public onDrop(event: any): void {
let transfer = this._getTransfer(event);
if (!transfer) {
return;
@@ -37,8 +37,8 @@ export class FileDropDirective {
this.onFileDrop.emit(transfer.files);
}
@HostListener('dragover', ['$event'])
public onDragOver(event:any):void {
@HostListener('dragover', [ '$event' ])
public onDragOver(event: any): void {
let transfer = this._getTransfer(event);
if (!this._haveFiles(transfer.types)) {
return;
@@ -49,10 +49,10 @@ export class FileDropDirective {
this.fileOver.emit(true);
}
@HostListener('dragleave', ['$event'])
public onDragLeave(event:any):any {
@HostListener('dragleave', [ '$event' ])
public onDragLeave(event: any): any {
if ((this as any).element) {
if (event.currentTarget === (this as any).element[0]) {
if (event.currentTarget === (this as any).element[ 0 ]) {
return;
}
}
@@ -61,16 +61,16 @@ export class FileDropDirective {
this.fileOver.emit(false);
}
protected _getTransfer(event:any):any {
protected _getTransfer(event: any): any {
return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix;
}
protected _preventAndStop(event:any):any {
protected _preventAndStop(event: any): any {
event.preventDefault();
event.stopPropagation();
}
protected _haveFiles(types:any):any {
protected _haveFiles(types: any): any {
if (!types) {
return false;
}
@@ -83,13 +83,4 @@ export class FileDropDirective {
return false;
}
}
/*
_addOverClass(item:any):any {
item.addOverClass();
}
_removeOverClass(item:any):any {
item.removeOverClass();
}*/
}

View File

@@ -2,30 +2,30 @@ import { FileLikeObject } from './file-like-object.class';
import { FileUploader, ParsedResponseHeaders, FileUploaderOptions } from './file-uploader.class';
export class FileItem {
public file:FileLikeObject;
public _file:File;
public alias:string;
public url:string = '/';
public method:string;
public headers:any = [];
public withCredentials:boolean = true;
public formData:any = [];
public isReady:boolean = false;
public isUploading:boolean = false;
public isUploaded:boolean = false;
public isSuccess:boolean = false;
public isCancel:boolean = false;
public isError:boolean = false;
public progress:number = 0;
public index:number = void 0;
public _xhr:XMLHttpRequest;
public _form:any;
public file: FileLikeObject;
public _file: File;
public alias: string;
public url: string = '/';
public method: string;
public headers: any = [];
public withCredentials: boolean = true;
public formData: any = [];
public isReady: boolean = false;
public isUploading: boolean = false;
public isUploaded: boolean = false;
public isSuccess: boolean = false;
public isCancel: boolean = false;
public isError: boolean = false;
public progress: number = 0;
public index: number = void 0;
public _xhr: XMLHttpRequest;
public _form: any;
protected uploader:FileUploader;
protected some:File;
protected options:FileUploaderOptions;
protected uploader: FileUploader;
protected some: File;
protected options: FileUploaderOptions;
public constructor(uploader:FileUploader, some:File, options:FileUploaderOptions) {
public constructor(uploader: FileUploader, some: File, options: FileUploaderOptions) {
this.uploader = uploader;
this.some = some;
this.options = options;
@@ -38,7 +38,7 @@ export class FileItem {
this.url = uploader.options.url;
}
public upload():void {
public upload(): void {
try {
this.uploader.uploadItem(this);
} catch (e) {
@@ -47,43 +47,43 @@ export class FileItem {
}
}
public cancel():void {
public cancel(): void {
this.uploader.cancelItem(this);
}
public remove():void {
public remove(): void {
this.uploader.removeFromQueue(this);
}
public onBeforeUpload():void {
public onBeforeUpload(): void {
return void 0;
}
public onBuildForm(form:any):any {
return {form};
public onBuildForm(form: any): any {
return { form };
}
public onProgress(progress:number):any {
return {progress};
public onProgress(progress: number): any {
return { progress };
}
public onSuccess(response:string, status:number, headers:ParsedResponseHeaders):any {
return {response, status, headers};
public onSuccess(response: string, status: number, headers: ParsedResponseHeaders): any {
return { response, status, headers };
}
public onError(response:string, status:number, headers:ParsedResponseHeaders):any {
return {response, status, headers};
public onError(response: string, status: number, headers: ParsedResponseHeaders): any {
return { response, status, headers };
}
public onCancel(response:string, status:number, headers:ParsedResponseHeaders):any {
return {response, status, headers};
public onCancel(response: string, status: number, headers: ParsedResponseHeaders): any {
return { response, status, headers };
}
public onComplete(response:string, status:number, headers:ParsedResponseHeaders):any {
return {response, status, headers};
public onComplete(response: string, status: number, headers: ParsedResponseHeaders): any {
return { response, status, headers };
}
public _onBeforeUpload():void {
public _onBeforeUpload(): void {
this.isReady = true;
this.isUploading = true;
this.isUploaded = false;
@@ -94,16 +94,16 @@ export class FileItem {
this.onBeforeUpload();
}
public _onBuildForm(form:any):void {
public _onBuildForm(form: any): void {
this.onBuildForm(form);
}
public _onProgress(progress:number):void {
public _onProgress(progress: number): void {
this.progress = progress;
this.onProgress(progress);
}
public _onSuccess(response:string, status:number, headers:ParsedResponseHeaders):void {
public _onSuccess(response: string, status: number, headers: ParsedResponseHeaders): void {
this.isReady = false;
this.isUploading = false;
this.isUploaded = true;
@@ -115,7 +115,7 @@ export class FileItem {
this.onSuccess(response, status, headers);
}
public _onError(response:string, status:number, headers:ParsedResponseHeaders):void {
public _onError(response: string, status: number, headers: ParsedResponseHeaders): void {
this.isReady = false;
this.isUploading = false;
this.isUploaded = true;
@@ -127,7 +127,7 @@ export class FileItem {
this.onError(response, status, headers);
}
public _onCancel(response:string, status:number, headers:ParsedResponseHeaders):void {
public _onCancel(response: string, status: number, headers: ParsedResponseHeaders): void {
this.isReady = false;
this.isUploading = false;
this.isUploaded = false;
@@ -139,7 +139,7 @@ export class FileItem {
this.onCancel(response, status, headers);
}
public _onComplete(response:string, status:number, headers:ParsedResponseHeaders):void {
public _onComplete(response: string, status: number, headers: ParsedResponseHeaders): void {
this.onComplete(response, status, headers);
if (this.uploader.options.removeAfterUpload) {
@@ -147,7 +147,7 @@ export class FileItem {
}
}
public _prepareToUploading():void {
public _prepareToUploading(): void {
this.index = this.index || ++this.uploader._nextIndex;
this.isReady = true;
}

View File

@@ -1,30 +1,31 @@
function isElement(node:any):boolean {
function isElement(node: any): boolean {
return !!(node && (node.nodeName || node.prop && node.attr && node.find));
}
export class FileLikeObject {
public lastModifiedDate:any;
public size:any;
public type:string;
public name:string;
public lastModifiedDate: any;
public size: any;
public type: string;
public name: string;
public rawFile: string;
public constructor(fileOrInput:any) {
public constructor(fileOrInput: any) {
this.rawFile = fileOrInput;
let isInput = isElement(fileOrInput);
let fakePathOrObject = isInput ? fileOrInput.value : fileOrInput;
let postfix = typeof fakePathOrObject === 'string' ? 'FakePath' : 'Object';
let method = '_createFrom' + postfix;
(this as any)[method](fakePathOrObject);
(this as any)[ method ](fakePathOrObject);
}
public _createFromFakePath(path:string):void {
public _createFromFakePath(path: string): void {
this.lastModifiedDate = void 0;
this.size = void 0;
this.type = 'like/' + path.slice(path.lastIndexOf('.') + 1).toLowerCase();
this.name = path.slice(path.lastIndexOf('/') + path.lastIndexOf('\\') + 2);
}
public _createFromObject(object:{size:number, type:string, name:string}):void {
// this.lastModifiedDate = copy(object.lastModifiedDate);
public _createFromObject(object: { size: number, type: string, name: string }): void {
this.size = object.size;
this.type = object.type;
this.name = object.name;

View File

@@ -1,46 +1,41 @@
import { Directive, ElementRef, Input, HostListener } from '@angular/core';
import { Directive, EventEmitter, ElementRef, Input, HostListener, Output } from '@angular/core';
import { FileUploader } from './file-uploader.class';
// todo: filters
@Directive({selector: '[ng2FileSelect]'})
@Directive({ selector: '[ng2FileSelect]' })
export class FileSelectDirective {
@Input() public uploader:FileUploader;
@Input() public uploader: FileUploader;
@Output() public onFileSelected: EventEmitter<File[]> = new EventEmitter<File[]>();
protected element:ElementRef;
protected element: ElementRef;
public constructor(element:ElementRef) {
public constructor(element: ElementRef) {
this.element = element;
}
public getOptions():any {
public getOptions(): any {
return this.uploader.options;
}
public getFilters():any {
return void 0;
public getFilters(): any {
return {};
}
public isEmptyAfterSelection():boolean {
public isEmptyAfterSelection(): boolean {
return !!this.element.nativeElement.attributes.multiple;
}
@HostListener('change')
public onChange():any {
// let files = this.uploader.isHTML5 ? this.element.nativeElement[0].files : this.element.nativeElement[0];
public onChange(): any {
let files = this.element.nativeElement.files;
let options = this.getOptions();
let filters = this.getFilters();
// if(!this.uploader.isHTML5) this.destroy();
this.uploader.addToQueue(files, options, filters);
this.onFileSelected.emit(files);
if (this.isEmptyAfterSelection()) {
// todo
this.element.nativeElement.value = '';
/*this.element.nativeElement
.replaceWith(this.element = this.element.nativeElement.clone(true)); // IE fix*/
}
}
}

View File

@@ -1,6 +1,8 @@
import { FileLikeObject } from "../ng2-file-upload";
export class FileType {
/* MS office */
public static mime_doc:string[] = [
public static mime_doc: string[] = [
'application/msword',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
@@ -8,7 +10,7 @@ export class FileType {
'application/vnd.ms-word.document.macroEnabled.12',
'application/vnd.ms-word.template.macroEnabled.12'
];
public static mime_xsl:string[] = [
public static mime_xsl: string[] = [
'application/vnd.ms-excel',
'application/vnd.ms-excel',
'application/vnd.ms-excel',
@@ -19,7 +21,7 @@ export class FileType {
'application/vnd.ms-excel.addin.macroEnabled.12',
'application/vnd.ms-excel.sheet.binary.macroEnabled.12'
];
public static mime_ppt:string[] = [
public static mime_ppt: string[] = [
'application/vnd.ms-powerpoint',
'application/vnd.ms-powerpoint',
'application/vnd.ms-powerpoint',
@@ -34,7 +36,7 @@ export class FileType {
];
/* PSD */
public static mime_psd:string[] = [
public static mime_psd: string[] = [
'image/photoshop',
'image/x-photoshop',
'image/psd',
@@ -44,16 +46,21 @@ export class FileType {
];
/* Compressed files */
public static mime_compress:string[] = [
public static mime_compress: string[] = [
'application/x-gtar',
'application/x-gcompress',
'application/compress',
'application/x-tar',
'application/x-rar-compressed',
'application/octet-stream'
'application/octet-stream',
'application/x-zip-compressed',
'application/zip-compressed',
'application/x-7z-compressed',
'application/gzip',
'application/x-bzip2'
];
public static getMimeClass(file:any):string {
public static getMimeClass(file: FileLikeObject): string {
let mimeClass = 'application';
if (this.mime_psd.indexOf(file.type) !== -1) {
mimeClass = 'image';
@@ -81,8 +88,8 @@ export class FileType {
return mimeClass;
}
public static fileTypeDetection(inputFilename:string):string {
let types:{[key:string]:string} = {
public static fileTypeDetection(inputFilename: string): string {
let types: { [ key: string ]: string } = {
'jpg': 'image',
'jpeg': 'image',
'tif': 'image',
@@ -107,10 +114,13 @@ export class FileType {
'mod': 'audio',
'm4a': 'audio',
'compress': 'compress',
'zip': 'compress',
'rar': 'compress',
'7z': 'compress',
'lz': 'compress',
'z01': 'compress',
'bz2': 'compress',
'gz': 'compress',
'pdf': 'pdf',
'xls': 'xls',
'xlsx': 'xls',
@@ -144,11 +154,11 @@ export class FileType {
if (chunks.length < 2) {
return 'application';
}
let extension = chunks[chunks.length - 1].toLowerCase();
if (types[extension] === undefined) {
let extension = chunks[ chunks.length - 1 ].toLowerCase();
if (types[ extension ] === undefined) {
return 'application';
} else {
return types[extension];
return types[ extension ];
}
}
}

View File

@@ -5,9 +5,9 @@ import { FileDropDirective } from './file-drop.directive';
import { FileSelectDirective } from './file-select.directive';
@NgModule({
imports: [CommonModule],
declarations: [FileDropDirective, FileSelectDirective],
exports: [FileDropDirective, FileSelectDirective]
imports: [ CommonModule ],
declarations: [ FileDropDirective, FileSelectDirective ],
exports: [ FileDropDirective, FileSelectDirective ]
})
export class FileUploadModule {
}

View File

@@ -1,98 +1,108 @@
import { EventEmitter } from '@angular/core';
import { FileLikeObject } from './file-like-object.class';
import { FileItem } from './file-item.class';
import { FileType } from './file-type.class';
function isFile(value:any):boolean {
function isFile(value: any): boolean {
return (File && value instanceof File);
}
// function isFileLikeObject(value:any) {
export interface Headers {
name:string;
value:string;
name: string;
value: string;
}
export type ParsedResponseHeaders = {[headerFieldName:string]:string};
export type ParsedResponseHeaders = { [ headerFieldName: string ]: string };
export type FilterFunction = {name:string, fn:(item?:FileLikeObject, options?:FileUploaderOptions)=>boolean};
export type FilterFunction = {
name: string,
fn: (item?: FileLikeObject, options?: FileUploaderOptions) => boolean
};
export interface FileUploaderOptions {
allowedMimeType?:Array<string>;
allowedFileType?:Array<string>;
autoUpload?:boolean;
isHTML5?:boolean;
filters?:Array<FilterFunction>;
headers?:Array<Headers>;
method?:string;
authToken?:string;
maxFileSize?:number;
queueLimit?:number;
removeAfterUpload?:boolean;
url?:string;
disableMultipart?:boolean;
allowedMimeType?: string[];
allowedFileType?: string[];
autoUpload?: boolean;
isHTML5?: boolean;
filters?: FilterFunction[];
headers?: Headers[];
method?: string;
authToken?: string;
maxFileSize?: number;
queueLimit?: number;
removeAfterUpload?: boolean;
url?: string;
disableMultipart?: boolean;
itemAlias?: string;
authTokenHeader?: string;
additionalParameter?:{[key: string]: any};
additionalParameter?: { [ key: string ]: any };
parametersBeforeFiles?: boolean;
formatDataFunction?: Function;
formatDataFunctionIsAsync?: boolean;
}
export class FileUploader {
public authToken:string;
public isUploading:boolean = false;
public queue:Array<FileItem> = [];
public progress:number = 0;
public _nextIndex:number = 0;
public autoUpload:any;
public authToken: string;
public isUploading: boolean = false;
public queue: FileItem[] = [];
public progress: number = 0;
public _nextIndex: number = 0;
public autoUpload: any;
public authTokenHeader: string;
public response: EventEmitter<any>;
public options:FileUploaderOptions = {
public options: FileUploaderOptions = {
autoUpload: false,
isHTML5: true,
filters: [],
removeAfterUpload: false,
disableMultipart: false
disableMultipart: false,
formatDataFunction: (item: FileItem) => item._file,
formatDataFunctionIsAsync: false
};
protected _failFilterIndex:number;
protected _failFilterIndex: number;
public constructor(options:FileUploaderOptions) {
public constructor(options: FileUploaderOptions) {
this.setOptions(options);
this.response = new EventEmitter<any>();
}
public setOptions(options:FileUploaderOptions):void {
public setOptions(options: FileUploaderOptions): void {
this.options = Object.assign(this.options, options);
this.authToken = options.authToken;
this.authTokenHeader = options.authTokenHeader || 'Authorization';
this.autoUpload = options.autoUpload;
this.options.filters.unshift({name: 'queueLimit', fn: this._queueLimitFilter});
this.authToken = this.options.authToken;
this.authTokenHeader = this.options.authTokenHeader || 'Authorization';
this.autoUpload = this.options.autoUpload;
this.options.filters.unshift({ name: 'queueLimit', fn: this._queueLimitFilter });
if (this.options.maxFileSize) {
this.options.filters.unshift({name: 'fileSize', fn: this._fileSizeFilter});
this.options.filters.unshift({ name: 'fileSize', fn: this._fileSizeFilter });
}
if (this.options.allowedFileType) {
this.options.filters.unshift({name: 'fileType', fn: this._fileTypeFilter});
this.options.filters.unshift({ name: 'fileType', fn: this._fileTypeFilter });
}
if (this.options.allowedMimeType) {
this.options.filters.unshift({name: 'mimeType', fn: this._mimeTypeFilter});
this.options.filters.unshift({ name: 'mimeType', fn: this._mimeTypeFilter });
}
for(let i = 0; i < this.queue.length; i++) {
this.queue[i].url = this.options.url;
for (let i = 0; i < this.queue.length; i++) {
this.queue[ i ].url = this.options.url;
}
// this.options.filters.unshift({name: 'folder', fn: this._folderFilter});
}
public addToQueue(files:File[], options?:FileUploaderOptions, filters?:FilterFunction[]|string):void {
let list:File[] = [];
public addToQueue(files: File[], options?: FileUploaderOptions, filters?: FilterFunction[] | string): void {
let list: File[] = [];
for (let file of files) {
list.push(file);
}
let arrayOfFilters = this._getFilters(filters);
let count = this.queue.length;
let addedFileItems:FileItem[] = [];
list.map((some:File) => {
let addedFileItems: FileItem[] = [];
list.map((some: File) => {
if (!options) {
options = this.options;
}
@@ -104,7 +114,7 @@ export class FileUploader {
this.queue.push(fileItem);
this._onAfterAddingFile(fileItem);
} else {
let filter = arrayOfFilters[this._failFilterIndex];
let filter = arrayOfFilters[ this._failFilterIndex ];
this._onWhenAddingFileFailed(temp, filter, options);
}
});
@@ -118,9 +128,9 @@ export class FileUploader {
}
}
public removeFromQueue(value:FileItem):void {
public removeFromQueue(value: FileItem): void {
let index = this.getIndexOfItem(value);
let item = this.queue[index];
let item = this.queue[ index ];
if (item.isUploading) {
item.cancel();
}
@@ -128,149 +138,144 @@ export class FileUploader {
this.progress = this._getTotalProgress();
}
public clearQueue():void {
public clearQueue(): void {
while (this.queue.length) {
this.queue[0].remove();
this.queue[ 0 ].remove();
}
this.progress = 0;
}
public uploadItem(value:FileItem):void {
public uploadItem(value: FileItem): void {
let index = this.getIndexOfItem(value);
let item = this.queue[index];
let item = this.queue[ index ];
let transport = this.options.isHTML5 ? '_xhrTransport' : '_iframeTransport';
item._prepareToUploading();
if (this.isUploading) {
return;
}
this.isUploading = true;
(this as any)[transport](item);
(this as any)[ transport ](item);
}
public cancelItem(value:FileItem):void {
public cancelItem(value: FileItem): void {
let index = this.getIndexOfItem(value);
let item = this.queue[index];
let item = this.queue[ index ];
let prop = this.options.isHTML5 ? item._xhr : item._form;
if (item && item.isUploading) {
prop.abort();
}
}
public uploadAll():void {
let items = this.getNotUploadedItems().filter((item:FileItem) => !item.isUploading);
public uploadAll(): void {
let items = this.getNotUploadedItems().filter((item: FileItem) => !item.isUploading);
if (!items.length) {
return;
}
items.map((item:FileItem) => item._prepareToUploading());
items[0].upload();
items.map((item: FileItem) => item._prepareToUploading());
items[ 0 ].upload();
}
public cancelAll():void {
public cancelAll(): void {
let items = this.getNotUploadedItems();
items.map((item:FileItem) => item.cancel());
items.map((item: FileItem) => item.cancel());
}
public isFile(value:any):boolean {
public isFile(value: any): boolean {
return isFile(value);
}
public isFileLikeObject(value:any):boolean {
public isFileLikeObject(value: any): boolean {
return value instanceof FileLikeObject;
}
public getIndexOfItem(value:any):number {
public getIndexOfItem(value: any): number {
return typeof value === 'number' ? value : this.queue.indexOf(value);
}
public getNotUploadedItems():Array<any> {
return this.queue.filter((item:FileItem) => !item.isUploaded);
public getNotUploadedItems(): any[] {
return this.queue.filter((item: FileItem) => !item.isUploaded);
}
public getReadyItems():Array<any> {
public getReadyItems(): any[] {
return this.queue
.filter((item:FileItem) => (item.isReady && !item.isUploading))
.sort((item1:any, item2:any) => item1.index - item2.index);
.filter((item: FileItem) => (item.isReady && !item.isUploading))
.sort((item1: any, item2: any) => item1.index - item2.index);
}
public destroy():void {
return void 0;
/*forEach(this._directives, (key) => {
forEach(this._directives[key], (object) => {
object.destroy();
});
});*/
}
public onAfterAddingAll(fileItems:any):any {
return {fileItems};
}
public onBuildItemForm(fileItem:FileItem, form:any):any {
return {fileItem, form};
}
public onAfterAddingFile(fileItem:FileItem):any {
return {fileItem};
}
public onWhenAddingFileFailed(item:FileLikeObject, filter:any, options:any):any {
return {item, filter, options};
}
public onBeforeUploadItem(fileItem:FileItem):any {
return {fileItem};
}
public onProgressItem(fileItem:FileItem, progress:any):any {
return {fileItem, progress};
}
public onProgressAll(progress:any):any {
return {progress};
}
public onSuccessItem(item:FileItem, response:string, status:number, headers:ParsedResponseHeaders):any {
return {item, response, status, headers};
}
public onErrorItem(item:FileItem, response:string, status:number, headers:ParsedResponseHeaders):any {
return {item, response, status, headers};
}
public onCancelItem(item:FileItem, response:string, status:number, headers:ParsedResponseHeaders):any {
return {item, response, status, headers};
}
public onCompleteItem(item:FileItem, response:string, status:number, headers:ParsedResponseHeaders):any {
return {item, response, status, headers};
}
public onCompleteAll():any {
public destroy(): void {
return void 0;
}
public _mimeTypeFilter(item:FileLikeObject):boolean {
public onAfterAddingAll(fileItems: any): any {
return { fileItems };
}
public onBuildItemForm(fileItem: FileItem, form: any): any {
return { fileItem, form };
}
public onAfterAddingFile(fileItem: FileItem): any {
return { fileItem };
}
public onWhenAddingFileFailed(item: FileLikeObject, filter: any, options: any): any {
return { item, filter, options };
}
public onBeforeUploadItem(fileItem: FileItem): any {
return { fileItem };
}
public onProgressItem(fileItem: FileItem, progress: any): any {
return { fileItem, progress };
}
public onProgressAll(progress: any): any {
return { progress };
}
public onSuccessItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any {
return { item, response, status, headers };
}
public onErrorItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any {
return { item, response, status, headers };
}
public onCancelItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any {
return { item, response, status, headers };
}
public onCompleteItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any {
return { item, response, status, headers };
}
public onCompleteAll(): any {
return void 0;
}
public _mimeTypeFilter(item: FileLikeObject): boolean {
return !(this.options.allowedMimeType && this.options.allowedMimeType.indexOf(item.type) === -1);
}
public _fileSizeFilter(item:FileLikeObject):boolean {
public _fileSizeFilter(item: FileLikeObject): boolean {
return !(this.options.maxFileSize && item.size > this.options.maxFileSize);
}
public _fileTypeFilter(item:FileLikeObject):boolean {
public _fileTypeFilter(item: FileLikeObject): boolean {
return !(this.options.allowedFileType &&
this.options.allowedFileType.indexOf(FileType.getMimeClass(item)) === -1);
this.options.allowedFileType.indexOf(FileType.getMimeClass(item)) === -1);
}
public _onErrorItem(item:FileItem, response:string, status:number, headers:ParsedResponseHeaders):void {
public _onErrorItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
item._onError(response, status, headers);
this.onErrorItem(item, response, status, headers);
}
public _onCompleteItem(item:FileItem, response:string, status:number, headers:ParsedResponseHeaders):void {
public _onCompleteItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
item._onComplete(response, status, headers);
this.onCompleteItem(item, response, status, headers);
let nextItem = this.getReadyItems()[0];
let nextItem = this.getReadyItems()[ 0 ];
this.isUploading = false;
if (nextItem) {
nextItem.upload();
@@ -281,25 +286,21 @@ export class FileUploader {
this._render();
}
protected _headersGetter(parsedHeaders:ParsedResponseHeaders):any {
return (name:any):any => {
protected _headersGetter(parsedHeaders: ParsedResponseHeaders): any {
return (name: any): any => {
if (name) {
return parsedHeaders[name.toLowerCase()] || void 0;
return parsedHeaders[ name.toLowerCase() ] || void 0;
}
return parsedHeaders;
};
}
protected _xhrTransport(item:FileItem):any {
protected _xhrTransport(item: FileItem): any {
let that = this;
let xhr = item._xhr = new XMLHttpRequest();
let sendable:any;
let sendable: any;
this._onBeforeUploadItem(item);
// todo
/*item.formData.map(obj => {
obj.map((value, key) => {
form.append(key, value);
});
});*/
if (typeof item._file.size !== 'number') {
throw new TypeError('The file specified is no longer valid');
}
@@ -307,18 +308,31 @@ export class FileUploader {
sendable = new FormData();
this._onBuildItemForm(item, sendable);
sendable.append(item.alias, item._file, item.file.name);
const appendFile = () => sendable.append(item.alias, item._file, item.file.name);
if (!this.options.parametersBeforeFiles) {
appendFile();
}
// For AWS, Additional Parameters must come BEFORE Files
if (this.options.additionalParameter !== undefined) {
Object.keys(this.options.additionalParameter).forEach((key:string) => {
sendable.append(key, this.options.additionalParameter[key]);
Object.keys(this.options.additionalParameter).forEach((key: string) => {
let paramVal = this.options.additionalParameter[ key ];
// Allow an additional parameter to include the filename
if (typeof paramVal === 'string' && paramVal.indexOf('{{file_name}}') >= 0) {
paramVal = paramVal.replace('{{file_name}}', item.file.name);
}
sendable.append(key, paramVal);
});
}
if (this.options.parametersBeforeFiles) {
appendFile();
}
} else {
sendable = item._file;
sendable = this.options.formatDataFunction(item);
}
xhr.upload.onprogress = (event:any) => {
xhr.upload.onprogress = (event: any) => {
let progress = Math.round(event.lengthComputable ? event.loaded * 100 / event.total : 0);
this._onProgressItem(item, progress);
};
@@ -327,7 +341,7 @@ export class FileUploader {
let response = this._transformResponse(xhr.response, headers);
let gist = this._isSuccessCode(xhr.status) ? 'Success' : 'Error';
let method = '_on' + gist + 'Item';
(this as any)[method](item, response, xhr.status, headers);
(this as any)[ method ](item, response, xhr.status, headers);
this._onCompleteItem(item, response, xhr.status, headers);
};
xhr.onerror = () => {
@@ -357,11 +371,22 @@ export class FileUploader {
if (this.authToken) {
xhr.setRequestHeader(this.authTokenHeader, this.authToken);
}
xhr.send(sendable);
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
that.response.emit(xhr.responseText)
}
}
if (this.options.formatDataFunctionIsAsync) {
sendable.then(
(result: any) => xhr.send(JSON.stringify(result))
);
} else {
xhr.send(sendable);
}
this._render();
}
protected _getTotalProgress(value:number = 0):number {
protected _getTotalProgress(value: number = 0): number {
if (this.options.removeAfterUpload) {
return value;
}
@@ -372,7 +397,7 @@ export class FileUploader {
return Math.round(uploaded * ratio + current);
}
protected _getFilters(filters:FilterFunction[]|string):FilterFunction[] {
protected _getFilters(filters: FilterFunction[] | string): FilterFunction[] {
if (!filters) {
return this.options.filters;
}
@@ -382,93 +407,77 @@ export class FileUploader {
if (typeof filters === 'string') {
let names = filters.match(/[^\s,]+/g);
return this.options.filters
.filter((filter:any) => names.indexOf(filter.name) !== -1);
.filter((filter: any) => names.indexOf(filter.name) !== -1);
}
return this.options.filters;
}
protected _render():any {
protected _render(): any {
return void 0;
// todo: ?
}
// protected _folderFilter(item:FileItem):boolean {
// return !!(item.size || item.type);
// }
protected _queueLimitFilter():boolean {
protected _queueLimitFilter(): boolean {
return this.options.queueLimit === undefined || this.queue.length < this.options.queueLimit;
}
protected _isValidFile(file:FileLikeObject, filters:FilterFunction[], options:FileUploaderOptions):boolean {
protected _isValidFile(file: FileLikeObject, filters: FilterFunction[], options: FileUploaderOptions): boolean {
this._failFilterIndex = -1;
return !filters.length ? true : filters.every((filter:FilterFunction) => {
return !filters.length ? true : filters.every((filter: FilterFunction) => {
this._failFilterIndex++;
return filter.fn.call(this, file, options);
});
}
protected _isSuccessCode(status:number):boolean {
protected _isSuccessCode(status: number): boolean {
return (status >= 200 && status < 300) || status === 304;
}
/* tslint:disable */
protected _transformResponse(response:string, headers:ParsedResponseHeaders):string {
// todo: ?
/*var headersGetter = this._headersGetter(headers);
forEach($http.defaults.transformResponse, (transformFn) => {
response = transformFn(response, headersGetter);
});*/
protected _transformResponse(response: string, headers: ParsedResponseHeaders): string {
return response;
}
/* tslint:enable */
protected _parseHeaders(headers:string):ParsedResponseHeaders {
let parsed:any = {};
let key:any;
let val:any;
let i:any;
protected _parseHeaders(headers: string): ParsedResponseHeaders {
let parsed: any = {};
let key: any;
let val: any;
let i: any;
if (!headers) {
return parsed;
}
headers.split('\n').map((line:any) => {
headers.split('\n').map((line: any) => {
i = line.indexOf(':');
key = line.slice(0, i).trim().toLowerCase();
val = line.slice(i + 1).trim();
if (key) {
parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
parsed[ key ] = parsed[ key ] ? parsed[ key ] + ', ' + val : val;
}
});
return parsed;
}
/*protected _iframeTransport(item:FileItem) {
// todo: implement it later
}*/
protected _onWhenAddingFileFailed(item:FileLikeObject, filter:any, options:any):void {
protected _onWhenAddingFileFailed(item: FileLikeObject, filter: any, options: any): void {
this.onWhenAddingFileFailed(item, filter, options);
}
protected _onAfterAddingFile(item:FileItem):void {
protected _onAfterAddingFile(item: FileItem): void {
this.onAfterAddingFile(item);
}
protected _onAfterAddingAll(items:any):void {
protected _onAfterAddingAll(items: any): void {
this.onAfterAddingAll(items);
}
protected _onBeforeUploadItem(item:FileItem):void {
protected _onBeforeUploadItem(item: FileItem): void {
item._onBeforeUpload();
this.onBeforeUploadItem(item);
}
protected _onBuildItemForm(item:FileItem, form:any):void {
protected _onBuildItemForm(item: FileItem, form: any): void {
item._onBuildForm(form);
this.onBuildItemForm(item, form);
}
protected _onProgressItem(item:FileItem, progress:any):void {
protected _onProgressItem(item: FileItem, progress: any): void {
let total = this._getTotalProgress(progress);
this.progress = total;
item._onProgress(progress);
@@ -477,14 +486,12 @@ export class FileUploader {
this._render();
}
/* tslint:disable */
protected _onSuccessItem(item:FileItem, response:string, status:number, headers:ParsedResponseHeaders):void {
protected _onSuccessItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
item._onSuccess(response, status, headers);
this.onSuccessItem(item, response, status, headers);
}
/* tslint:enable */
protected _onCancelItem(item:FileItem, response:string, status:number, headers:ParsedResponseHeaders):void {
protected _onCancelItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
item._onCancel(response, status, headers);
this.onCancelItem(item, response, status, headers);
}

View File

@@ -2,5 +2,6 @@ export * from './file-upload/file-select.directive';
export * from './file-upload/file-drop.directive';
export * from './file-upload/file-uploader.class';
export * from './file-upload/file-item.class';
export * from './file-upload/file-like-object.class';
export { FileUploadModule } from './file-upload/file-upload.module';

View File

@@ -1,6 +1,6 @@
{
"name": "ng2-file-upload",
"version": "1.2.0",
"version": "1.3.0",
"peerDependencies": {
"@angular/common": "*",
"@angular/core": "*"

View File

@@ -1,28 +1,147 @@
import { Component } from '@angular/core';
import { Component, DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { inject, ComponentFixture, TestBed } from '@angular/core/testing';
import { FileUploader } from '../file-upload/file-uploader.class';
import { FileUploadModule } from '../file-upload/file-upload.module';
import { FileDropDirective } from '../file-upload/file-drop.directive';
@Component({
selector: 'container',
template: `<input type="file" ng2FileSelect [uploader]="uploader" />`
template: `<div type="file"
ng2FileDrop
[uploader]="uploader"
></div>`
})
export class ContainerComponent {
public uploader:FileUploader = new FileUploader({url: 'localhost:3000'});
public get url(): string { return 'localhost:3000'; }
public uploader: FileUploader = new FileUploader({ url: this.url });
}
describe('Directive: FileSelectDirective', () => {
describe('Directive: FileDropDirective', () => {
let fixture: ComponentFixture<ContainerComponent>;
let hostComponent: ContainerComponent;
let directiveElement: DebugElement;
let fileDropDirective: FileDropDirective;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [FileUploadModule],
declarations: [ContainerComponent],
providers: [ContainerComponent]
imports: [ FileUploadModule ],
declarations: [ ContainerComponent ],
providers: [ ContainerComponent ]
});
});
it('should be fine', inject([ContainerComponent], (fixture:ComponentFixture<ContainerComponent>) => {
expect(fixture).not.toBeNull();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ContainerComponent);
hostComponent = fixture.componentInstance;
fixture.detectChanges();
directiveElement = fixture.debugElement.query(By.directive(FileDropDirective));
fileDropDirective = directiveElement.injector.get(FileDropDirective) as FileDropDirective;
});
it('can be initialized', () => {
expect(fixture).toBeDefined();
expect(hostComponent).toBeDefined();
expect(fileDropDirective).toBeDefined();
});
it('can set file uploader', () => {
expect(fileDropDirective.uploader).toBe(hostComponent.uploader);
});
it('can get uploader options', () => {
const options = fileDropDirective.getOptions();
// Check url set through binding
expect(options.url).toBe(hostComponent.url);
// Check default options
expect(options.autoUpload).toBeFalsy();
expect(options.isHTML5).toBeTruthy();
expect(options.removeAfterUpload).toBeFalsy();
expect(options.disableMultipart).toBeFalsy();
});
it('can get filters', () => {
const filters = fileDropDirective.getFilters();
// TODO: Update test once implemented
expect(filters).toEqual({});
});
it('handles drop event', () => {
spyOn(fileDropDirective, 'onDrop');
directiveElement.triggerEventHandler('drop', getFakeEventData());
expect(fileDropDirective.onDrop).toHaveBeenCalled();
});
it('adds file to upload', () => {
spyOn(fileDropDirective.uploader, 'addToQueue');
let fileOverData;
fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data);
let fileDropData;
fileDropDirective.onFileDrop.subscribe((data: File[]) => fileDropData = data);
fileDropDirective.onDrop(getFakeEventData());
const uploadedFiles = getFakeEventData().dataTransfer.files;
const expectedArguments = [ uploadedFiles, fileDropDirective.getOptions(), fileDropDirective.getFilters() ];
expect(fileDropDirective.uploader.addToQueue).toHaveBeenCalledWith(...expectedArguments);
expect(fileOverData).toBeFalsy();
expect(fileDropData).toEqual(uploadedFiles);
});
it('handles dragover event', () => {
spyOn(fileDropDirective, 'onDragOver');
directiveElement.triggerEventHandler('dragover', getFakeEventData());
expect(fileDropDirective.onDragOver).toHaveBeenCalled();
});
it('handles file over', () => {
let fileOverData;
fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data);
fileDropDirective.onDragOver(getFakeEventData());
expect(fileOverData).toBeTruthy();
});
it('handles dragleave event', () => {
spyOn(fileDropDirective, 'onDragLeave');
directiveElement.triggerEventHandler('dragleave', getFakeEventData());
expect(fileDropDirective.onDragLeave).toHaveBeenCalled();
});
it('handles file over leave', () => {
let fileOverData;
fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data);
fileDropDirective.onDragLeave(getFakeEventData());
expect(fileOverData).toBeFalsy();
});
});
function getFakeEventData(): any {
return {
dataTransfer: {
files: [ 'foo.bar' ],
types: [ 'Files' ]
},
preventDefault: () => undefined,
stopPropagation: () => undefined
}
}

View File

@@ -0,0 +1,99 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { Component, DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { FileUploadModule } from '../file-upload/file-upload.module';
import { FileSelectDirective } from '../file-upload/file-select.directive';
import { FileUploader } from '../file-upload/file-uploader.class';
@Component({
selector: 'container',
template: `<input type="file"
ng2FileSelect
[uploader]="uploader"
/>`
})
export class ContainerComponent {
public get url(): string { return 'localhost:3000'; }
public uploader: FileUploader = new FileUploader({ url: this.url });
}
describe('Directive: FileSelectDirective', () => {
let fixture: ComponentFixture<ContainerComponent>;
let hostComponent: ContainerComponent;
let directiveElement: DebugElement;
let fileSelectDirective: FileSelectDirective;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ FileUploadModule ],
declarations: [ ContainerComponent ],
providers: [ ContainerComponent ]
});
});
beforeEach(() => {
fixture = TestBed.createComponent(ContainerComponent);
hostComponent = fixture.componentInstance;
fixture.detectChanges();
directiveElement = fixture.debugElement.query(By.directive(FileSelectDirective));
fileSelectDirective = directiveElement.injector.get(FileSelectDirective) as FileSelectDirective;
});
it('can be initialized', () => {
expect(fixture).toBeDefined();
expect(hostComponent).toBeDefined();
expect(fileSelectDirective).toBeDefined();
});
it('can set file uploader', () => {
expect(fileSelectDirective.uploader).toBe(hostComponent.uploader);
});
it('can get uploader options', () => {
const options = fileSelectDirective.getOptions();
// Check url set through binding
expect(options.url).toBe(hostComponent.url);
// Check default options
expect(options.autoUpload).toBeFalsy();
expect(options.isHTML5).toBeTruthy();
expect(options.removeAfterUpload).toBeFalsy();
expect(options.disableMultipart).toBeFalsy();
});
it('can get filters', () => {
const filters = fileSelectDirective.getFilters();
// TODO: Update test once implemented
expect(filters).toEqual({});
});
it('can check if element is empty', () => {
const isElementEmpty = fileSelectDirective.isEmptyAfterSelection();
expect(isElementEmpty).toBeFalsy();
});
it('can listed on change event', () => {
spyOn(fileSelectDirective, 'onChange');
directiveElement.triggerEventHandler('change', {});
expect(fileSelectDirective.onChange).toHaveBeenCalled();
});
it('handles change event', () => {
spyOn(fileSelectDirective.uploader, 'addToQueue');
fileSelectDirective.onChange();
const expectedArguments = [ directiveElement.nativeElement.files,
fileSelectDirective.getOptions(),
fileSelectDirective.getFilters() ];
expect(fileSelectDirective.uploader.addToQueue).toHaveBeenCalledWith(...expectedArguments);
});
});

7807
yarn.lock

File diff suppressed because it is too large Load Diff