Compare commits

..

92 Commits

Author SHA1 Message Date
Linden van der
ed27008383 add file type .dwf 2018-03-21 13:26:03 +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
Dmitriy Shekhovtsov
cf12851e1d chore(readme): badges updates 2017-01-18 15:19:20 +02:00
Dmitriy Shekhovtsov
6fe71bc464 v1.2.0 2017-01-17 16:41:45 +02:00
Dmitriy Shekhovtsov
3cc6a9946f feat(package): upgrade to ng v2.3+ (#574) 2017-01-17 16:38:35 +02:00
Dmitriy Shekhovtsov
f5b5dc3bd2 Merge branch 'development' of github.com:valor-software/ng2-file-upload into development 2017-01-17 15:58:36 +02:00
Dmitriy Shekhovtsov
a9971981f1 Merge branch 'ediri-patch-1' into development 2017-01-17 15:57:55 +02:00
Dmitriy Shekhovtsov
35448680b2 Merge branch 'patch-1' of git://github.com/ediri/ng2-file-upload into ediri-patch-1
Conflicts:
	.npmignore
2017-01-17 15:57:45 +02:00
Daniel Kucal
be70a82303 Allow to extend classes (#468)
* private accessors replaced by protected to allow extending of classes

* FileItem class protected accessors
2017-01-17 15:07:03 +02:00
Kevin FONTAINE
d6e75984ed #492 Add FileItem in declaration ng2-file-upload.d.ts (#523) 2017-01-17 15:03:15 +02:00
Kevin FONTAINE
410efda505 feat(file-select): Clear file select automatically (#524) 2017-01-17 15:02:52 +02:00
Florian Kinder
397de09e7d feat(fileUpload): added additionalParameter (#565) 2017-01-17 15:02:12 +02:00
retrospectacus
e4a7099d92 fix(headers): Add FileItem headers to XHR (#553)
fixes #552
2017-01-17 15:01:33 +02:00
Engin.Diri
63bf587d80 https://github.com/valor-software/ng2-file-upload/issues/272 2016-10-19 16:30:02 +02:00
Dmitriy Shekhovtsov
34c0d35c9c 1.1.3-0 2016-10-19 17:12:59 +03:00
Dmitriy Shekhovtsov
f67a7a6530 chore(yarn): added lock 2016-10-19 16:09:15 +03:00
Dmitriy Shekhovtsov
f0b2879c4d feat(build): added support for AoT and ng-cli
fixes #436
2016-10-19 16:03:32 +03:00
Dmitriy Shekhovtsov
b55c85218e fix(typing): added authTokenHeader property to options and file upload class 2016-10-19 14:15:56 +03:00
Jose Berrocal
282295ce20 feat(file-upload): Add the possibility of set the token header (#213)
It will be very useful set which is the Token that is going to be send to the server
2016-10-19 13:45:02 +03:00
GuardianFree
1a4eb3a0fd fix(file-uploader):Changing url when files are selected does not work (#448)
* fix issue #406 Changing url when files are selected does not work

* fix issue #406 Changing url when files are selected does not work

* fix issue #406 Changing url when files are selected does not work

fixes #406
2016-10-19 12:33:59 +03:00
Dmitriy Shekhovtsov
5af17612cb 1.1.2 2016-10-17 17:57:47 +03:00
Dmitriy Shekhovtsov
87395e668e feat(package): allow of ng2 v2.0.* and v2.*.* 2016-10-17 17:57:22 +03:00
Dmitriy Shekhovtsov
ad1d710ff1 1.1.1 2016-10-17 17:53:57 +03:00
Karl Hiramoto
3fec3850b4 feat(package): angular ~2.0.1 stable release (#425) 2016-10-05 16:55:50 +03:00
Dmitriy Schekhovtsov
d218b9665b chore(build): fix travis config 2016-09-21 23:17:42 +03:00
Dmitriy Schekhovtsov
9d2da3809d 1.1.0 2016-09-21 23:10:55 +03:00
Dmitriy Schekhovtsov
4fef496698 feat(package): updated to typescript 2 2016-09-21 23:10:17 +03:00
Dmitriy Shekhovtsov
c1b3b5dc19 Merge pull request #404 from adrianfaciu/angular-release
Updating to angular 2.0.0
fixes #402, fixes #398, fixes #378, fixes #344
2016-09-21 11:32:41 +03:00
Dmitriy Shekhovtsov
003f1eb0d2 Merge pull request #403 from serhiisol/set-forms-name
Fix #22: Unable to set form's "name" on file upload
2016-09-21 09:55:51 +03:00
Adrian Faciu
0d1fd54f45 Updating to angular 2.0.0 2016-09-20 16:45:07 +03:00
Serhii Solonko
b886f7846b Fix #22: Unable to set form's "name" on file upload 2016-09-20 15:39:30 +02:00
Dmitriy Shekhovtsov
b50116313b Merge pull request #393 from valor-software/feat-rc7
feat(core) add ng2-webpack-config
2016-09-15 10:46:22 +03:00
Oleksandr Telnov
04152e2809 add tsconf publish 2016-09-15 10:29:10 +03:00
Oleksandr Telnov
cdc76cced0 add ng2-webpack-config 2016-09-15 10:22:43 +03:00
Adrian Fâciu
0e7e397f7d Fixing test execution 2016-09-10 12:14:21 +03:00
Adrian Fâciu
48128becdd Fixing tests and lint errors 2016-09-07 22:24:43 +03:00
Adrian Fâciu
6f42e303f9 Fixing demo page 2016-09-07 22:05:54 +03:00
Adrian Fâciu
e9d356b1ce Updating to RC6 2016-09-07 00:03:35 +03:00
Engin.Diri
9863507799 https://github.com/valor-software/ng2-file-upload/issues/272 2016-07-29 13:33:29 +02:00
Engin.Diri
0e2730a45e https://github.com/valor-software/ng2-file-upload/issues/272 2016-06-23 15:46:44 +02:00
Tim Donohue
22307d266f feat(multipart): Create disableMultipart option in FileUploader (#224)
* Create disableMultipart option in FileUploader

* Add basic docs
2016-06-21 17:48:12 +03:00
Johannes Hiemer
e068511917 fix(uploader): Add the ability to upload files via PUT instead of POST (#239)
* Add the ability to upload files via PUT instead of POST

* Add the method Propery to FileUploaderOptions

* Added braces and removed whitespaces.
2016-06-06 14:10:13 +03:00
Greenkeeper
8133246439 chore(package): update systemjs-builder to version 0.15.19 (#233)
https://greenkeeper.io/
2016-06-06 11:30:27 +03:00
Marvin Scharle
db77e89235 fix(zone.js): error in Safari, Added Typings (#221)
* Changed tsconfig.json to match tsconfig schema

* Change package.json to include all necessary packages for this package

* Added type for EventEmitter

* Fix for zone.js error "More tasks executed then were scheduled" in Safari, explicit call of NgZone not required in zone.js ^0.6.12

* Added type information for methods in FileUploader

* Added type information for methods in FileItem

* Added type information for methods in FileUploader

* Removed codelyzer / eslint according to PR valor-software/ng2-file-upload#221
2016-06-02 16:17:25 +03:00
Greenkeeper
ec1e5ae556 chore(package): update ng2-bootstrap to version 1.0.17 (#232)
https://greenkeeper.io/
2016-05-31 17:07:06 +03:00
Greenkeeper
9a00e47318 chore(package): update systemjs-builder to version 0.15.18 (#222)
https://greenkeeper.io/
2016-05-31 16:42:27 +03:00
Greenkeeper
97cf9c2a94 chore(package): update copy-webpack-plugin to version 3.0.1 (#229)
https://greenkeeper.io/
2016-05-31 16:42:21 +03:00
Greenkeeper
efb086d6b4 chore(package): update html-webpack-plugin to version 2.19.0 (#230)
https://greenkeeper.io/
2016-05-31 16:42:16 +03:00
Greenkeeper
c7793b7a50 chore(package): update eslint-config-valorsoft to version 0.0.15 (#231)
https://greenkeeper.io/
2016-05-31 16:42:10 +03:00
Greenkeeper
4f13f2e356 chore(package): update webpack to version 1.13.1 (#210)
https://greenkeeper.io/
2016-05-20 14:52:17 +03:00
Greenkeeper
897c8131c8 chore(package): update cpy-cli to version 1.0.1 (#207)
https://greenkeeper.io/
2016-05-19 18:48:21 +03:00
Greenkeeper
ccdfc664be chore(package): update systemjs-builder to version 0.15.17 (#208)
https://greenkeeper.io/
2016-05-19 18:48:17 +03:00
Greenkeeper
0daff86ec6 chore(package): update eslint-config-valorsoft to version 0.0.14 (#209)
https://greenkeeper.io/
2016-05-19 18:48:12 +03:00
76 changed files with 2145 additions and 1768 deletions

57
.angular-cli.json Normal file
View File

@@ -0,0 +1,57 @@
{
"project": {
"name": "ng2-file-upload"
},
"apps": [
{
"root": "demo/src",
"outDir": "demo/dist",
"assets": [
"assets"
],
"index": "index.html",
"main": "main.ts",
"test": "../../scripts/test.ts",
"tsconfig": "tsconfig.json",
"prefix": "",
"mobile": false,
"styles": [
],
"scripts": [
],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"addons": [],
"packages": [],
"e2e": {
"protractor": {
"config": "protractor.conf.js"
}
},
"test": {
"karma": {
"config": "karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"prefixInterfaces": false,
"inline": {
"style": false,
"template": false
},
"spec": {
"class": false,
"component": true,
"directive": true,
"module": false,
"pipe": true,
"service": true
}
}
}

View File

@@ -1,107 +0,0 @@
#!/usr/bin/env node
'use strict';
/*eslint no-console: 0, no-sync: 0*/
// System.js bundler
// simple and yet reusable system.js bundler
// bundles, minifies and gzips
const fs = require('fs');
const del = require('del');
const path = require('path');
const zlib = require('zlib');
const async = require('async');
const Builder = require('systemjs-builder');
const pkg = require('../package.json');
const name = pkg.name;
const targetFolder = path.resolve('./bundles');
async.waterfall([
cleanBundlesFolder,
getSystemJsBundleConfig,
buildSystemJs({minify: false, sourceMaps: true, mangle: false}),
getSystemJsBundleConfig,
buildSystemJs({minify: true, sourceMaps: true, mangle: false}),
gzipSystemJsBundle
], err => {
if (err) {
throw err;
}
});
function getSystemJsBundleConfig(cb) {
const config = {
baseURL: '..',
transpiler: 'typescript',
typescriptOptions: {
module: 'cjs'
},
map: {
typescript: path.resolve('node_modules/typescript/lib/typescript.js'),
'@angular/core': path.resolve('node_modules/@angular/core/index.js'),
'@angular/common': path.resolve('node_modules/@angular/common/index.js'),
'@angular/compiler': path.resolve('node_modules/@angular/compiler/index.js'),
'@angular/platform-browser': path.resolve('node_modules/@angular/platform-browser/index.js'),
'@angular/platform-browser-dynamic': path.resolve('node_modules/@angular/platform-browser-dynamic/'),
rxjs: path.resolve('node_modules/rxjs')
},
paths: {
'*': '*.js'
}
};
config.meta = ['@angular/common','@angular/compiler','@angular/core',
'@angular/platform-browser','@angular/platform-browser-dynamic', 'rxjs'].reduce((memo, currentValue) => {
memo[path.resolve(`node_modules/${currentValue}/*`)] = {build: false};
return memo;
}, {});
config.meta.moment = {build: false};
return cb(null, config);
}
function cleanBundlesFolder(cb) {
return del(targetFolder)
.then(paths => {
console.log('Deleted files and folders:\n', paths.join('\n'));
cb();
});
}
function buildSystemJs(options) {
return (config, cb) => {
const minPostFix = options && options.minify ? '.min' : '';
const fileName = `${name}${minPostFix}.js`;
const dest = path.resolve(__dirname, targetFolder, fileName);
const builder = new Builder();
console.log('Bundling system.js file:', fileName, options);
builder.config(config);
return builder
.bundle([name, name].join('/'), dest, options)
.then(() => cb())
.catch(cb);
};
}
function gzipSystemJsBundle(cb) {
const files = fs
.readdirSync(path.resolve(targetFolder))
.map(file => path.resolve(targetFolder, file))
.filter(file => fs.statSync(file).isFile())
.filter(file => path.extname(file) !== 'gz');
return async.eachSeries(files, (file, gzipcb) => {
process.nextTick(() => {
console.log('Gzipping ', file);
const gzip = zlib.createGzip({level: 9});
const inp = fs.createReadStream(file);
const out = fs.createWriteStream(`${file}.gz`);
inp.on('end', () => gzipcb());
inp.on('error', err => gzipcb(err));
return inp.pipe(gzip).pipe(out);
});
}, cb);
}

View File

@@ -1,6 +0,0 @@
{
"extends": "./node_modules/eslint-config-valorsoft/.eslintrc.json",
"env": {
"node": true
}
}

51
.gitignore vendored
View File

@@ -1,31 +1,38 @@
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
/node_modules
/bower_components
# IDEs and editors
/.idea
/.vscode
.project
.classpath
*.launch
.settings/
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
# type script artifacts
/typings
# WebStorm
.idea
# ignore build and dist for now
/bundles
/demo-build
/dist
/coverage
/ts
# ignore incline compiling
/demo/**/*.js
/demo/**/*.d.ts
/demo/**/*.js.map
/components/**/*.js
/components/**/*.d.ts
/components/**/*.js.map
ng2-file-upload.js
ng2-file-upload.d.ts
ng2-file-upload.js.map
/temp
/demo/dist
/demo/temp
/logs
!/demo/components/file-upload/file-catcher.js
#System Files
.DS_Store
Thumbs.db
/demo/e2e/*.js
/demo/e2e/*.map
src/**/*.js
src/**/*.map
scripts/**/*.js
scripts/**/*.map

View File

@@ -1,24 +0,0 @@
.idea
gulp-tasks
logs
# typings
typings
# testing
karma.conf.js
test.bundle.js
coverage
# demo build
demo
demo-build
webpack.config.js
#typescript sources
*.ts
*.js.map
!*.d.ts
/components/**/*.ts
!/components/**/*.d.ts

View File

@@ -2,17 +2,20 @@ language: node_js
node_js:
- "6"
before_install:
- export CHROME_BIN=chromium-browser
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
script:
- npm run flow.install:typings
- npm test
- npm run pretest
- npm run test-coverage
after_success:
- ./node_modules/.bin/codecov
addons:
# sauce labs tunel connector (read more https://docs.travis-ci.com/user/sauce-connect/ )
sauce_connect: true
firefox: "42.0"
firefox: "latest"
apt:
sources:
- ubuntu-toolchain-r-test

View File

@@ -1,3 +1,106 @@
<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)
### Bug Fixes
* **headers:** Add FileItem headers to XHR ([#553](https://github.com/valor-software/ng2-file-upload/issues/553)) ([e4a7099](https://github.com/valor-software/ng2-file-upload/commit/e4a7099)), closes [#552](https://github.com/valor-software/ng2-file-upload/issues/552)
### Features
* **file-select:** Clear file select automatically ([#524](https://github.com/valor-software/ng2-file-upload/issues/524)) ([410efda](https://github.com/valor-software/ng2-file-upload/commit/410efda))
* **fileUpload:** added additionalParameter ([#565](https://github.com/valor-software/ng2-file-upload/issues/565)) ([397de09](https://github.com/valor-software/ng2-file-upload/commit/397de09))
* **package:** upgrade to ng v2.3+ ([#574](https://github.com/valor-software/ng2-file-upload/issues/574)) ([3cc6a99](https://github.com/valor-software/ng2-file-upload/commit/3cc6a99))
<a name="1.1.3-0"></a>
## [1.1.3-0](https://github.com/valor-software/ng2-file-upload/compare/v1.1.2...v1.1.3-0) (2016-10-19)
### Bug Fixes
* **typing:** added authTokenHeader property to options and file upload class ([b55c852](https://github.com/valor-software/ng2-file-upload/commit/b55c852))
### Features
* **build:** added support for AoT and ng-cli ([f0b2879](https://github.com/valor-software/ng2-file-upload/commit/f0b2879)), closes [#436](https://github.com/valor-software/ng2-file-upload/issues/436)
* **file-upload:** Add the possibility of set the token header ([#213](https://github.com/valor-software/ng2-file-upload/issues/213)) ([282295c](https://github.com/valor-software/ng2-file-upload/commit/282295c))
<a name="1.1.2"></a>
## [1.1.2](https://github.com/valor-software/ng2-file-upload/compare/v1.1.1...v1.1.2) (2016-10-17)
### Features
* **package:** allow of ng2 v2.0.* and v2.*.* ([87395e6](https://github.com/valor-software/ng2-file-upload/commit/87395e6))
<a name="1.1.1"></a>
## [1.1.1](https://github.com/valor-software/ng2-file-upload/compare/v1.0.3...v1.1.1) (2016-10-17)
### Bug Fixes
* **uploader:** Add the ability to upload files via PUT instead of POST ([#239](https://github.com/valor-software/ng2-file-upload/issues/239)) ([e068511](https://github.com/valor-software/ng2-file-upload/commit/e068511))
* **zone.js:** error in Safari, Added Typings ([#221](https://github.com/valor-software/ng2-file-upload/issues/221)) ([db77e89](https://github.com/valor-software/ng2-file-upload/commit/db77e89))
### Features
* **multipart:** Create disableMultipart option in FileUploader ([#224](https://github.com/valor-software/ng2-file-upload/issues/224)) ([22307d2](https://github.com/valor-software/ng2-file-upload/commit/22307d2))
* **package:** angular ~2.0.1 stable release ([#425](https://github.com/valor-software/ng2-file-upload/issues/425)) ([3fec385](https://github.com/valor-software/ng2-file-upload/commit/3fec385))
* **package:** updated to typescript 2 ([4fef496](https://github.com/valor-software/ng2-file-upload/commit/4fef496))
<a name="1.1.0"></a>
# [1.1.0](https://github.com/valor-software/ng2-file-upload/compare/v1.0.3...v1.1.0) (2016-09-21)
### Bug Fixes
* **uploader:** Add the ability to upload files via PUT instead of POST ([#239](https://github.com/valor-software/ng2-file-upload/issues/239)) ([e068511](https://github.com/valor-software/ng2-file-upload/commit/e068511))
* **zone.js:** error in Safari, Added Typings ([#221](https://github.com/valor-software/ng2-file-upload/issues/221)) ([db77e89](https://github.com/valor-software/ng2-file-upload/commit/db77e89))
### Features
* **multipart:** Create disableMultipart option in FileUploader ([#224](https://github.com/valor-software/ng2-file-upload/issues/224)) ([22307d2](https://github.com/valor-software/ng2-file-upload/commit/22307d2))
* **package:** updated to typescript 2 ([4fef496](https://github.com/valor-software/ng2-file-upload/commit/4fef496))
<a name="1.0.3"></a>
## [1.0.3](https://github.com/valor-software/ng2-file-upload/compare/v1.0.2...v1.0.3) (2016-05-12)

View File

@@ -1,7 +1,7 @@
The MIT License (MIT)
Copyright (c) 2015 Dmitriy Shekhovtsov <valorkin@gmail.com>
Copyright (c) 2015 Valor Software
Copyright (c) 2015-2017 Dmitriy Shekhovtsov <valorkin@gmail.com>
Copyright (c) 2015-1017 Valor Software
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,15 +1,9 @@
# ng2-file-upload [![npm version](https://badge.fury.io/js/ng2-file-upload.svg)](http://badge.fury.io/js/ng2-file-upload)
# ng2-file-upload [![npm version](https://badge.fury.io/js/ng2-file-upload.svg)](http://badge.fury.io/js/ng2-file-upload) [![npm downloads](https://img.shields.io/npm/dm/ng2-file-upload.svg)](https://npmjs.org/ng2-file-upload)[![slack](https://ngx-slack.herokuapp.com/badge.svg)](https://ngx-slack.herokuapp.com)
Easy to use Angular2 directives for files upload ([demo](http://valor-software.github.io/ng2-file-upload/))
Follow me [![twitter](https://img.shields.io/twitter/follow/valorkin.svg?style=social&label=%20valorkin)](https://twitter.com/valorkin) to be notified about new releases.
[![Angular 2 Style Guide](https://mgechev.github.io/angular2-style-guide/images/badge.svg)](https://github.com/mgechev/angular2-style-guide)
[![Build Status](https://travis-ci.org/valor-software/ng2-file-upload.svg?branch=master)](https://travis-ci.org/valor-software/ng2-file-upload)
[![Code Climate](https://codeclimate.com/github/valor-software/ng2-file-upload/badges/gpa.svg)](https://codeclimate.com/github/valor-software/ng2-file-upload)
[![Join the chat at https://gitter.im/valor-software/ng2-bootstrap](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/valor-software/ng2-bootstrap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/valor-software/ng2-file-upload.svg?branch=development)](https://travis-ci.org/valor-software/ng2-file-upload)
[![Dependency Status](https://david-dm.org/valor-software/ng2-file-upload.svg)](https://david-dm.org/valor-software/ng2-file-upload)
[![devDependency Status](https://david-dm.org/valor-software/ng2-file-upload/dev-status.svg)](https://david-dm.org/valor-software/ng2-file-upload#info=devDependencies)
[![Throughput Graph](https://graphs.waffle.io/valor-software/ng2-file-upload/throughput.svg)](https://waffle.io/valor-software/ng2-file-upload/metrics)
## Quick start
@@ -24,6 +18,30 @@ Follow me [![twitter](https://img.shields.io/twitter/follow/valorkin.svg?style=s
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`
@@ -31,22 +49,31 @@ Follow me [![twitter](https://img.shields.io/twitter/follow/valorkin.svg?style=s
- `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
- `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)
Parameters that supported by this object:
Parameters supported by this object:
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
- `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

@@ -1,21 +0,0 @@
import {Component} from '@angular/core';
import {it, inject, beforeEachProviders} from '@angular/core/testing';
import {ComponentFixture} from '@angular/compiler/testing';
import {FileUploader} from './file-uploader.class';
import {FileSelectDirective} from './file-select.directive';
@Component({
selector: 'container',
template: `<input type="file" ng2FileSelect [uploader]="uploader" />`,
directives: [FileSelectDirective]
})
export class ContainerComponent {
public uploader:FileUploader = new FileUploader({url: 'localhost:3000'});
}
describe('Directive: FileSelectDirective', () => {
beforeEachProviders(() => [
ContainerComponent
]);
it('should be fine', inject([ContainerComponent], (fixture:ComponentFixture<ContainerComponent>) => {
expect(fixture).not.toBeNull();
}));
});

View File

@@ -1,154 +0,0 @@
import {NgZone} from '@angular/core';
import {FileLikeObject} from './file-like-object.class';
import {FileUploader} from './file-uploader.class';
export class FileItem {
public file:FileLikeObject;
public _file:File;
public alias:string = 'file';
public url:string = '/';
public method:string = 'POST';
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;
private _zone:NgZone;
private uploader:FileUploader;
private some:any;
private options:any;
public constructor(uploader:FileUploader, some:any, options:any) {
this.uploader = uploader;
this.some = some;
this.options = options;
this.file = new FileLikeObject(some);
this._file = some;
this.url = uploader.options.url;
this._zone = new NgZone({ enableLongStackTrace: false });
}
public upload():void {
try {
this.uploader.uploadItem(this);
} catch (e) {
this.uploader._onCompleteItem(this, '', 0, []);
this.uploader._onErrorItem(this, '', 0, []);
}
}
public cancel():void {
this.uploader.cancelItem(this);
}
public remove():void {
this.uploader.removeFromQueue(this);
}
public onBeforeUpload():void {
return void 0;
}
public onBuildForm(form:any):any {
return {form};
}
public onProgress(progress:number):any {
return {progress};
}
public onSuccess(response:any, status:any, headers:any):any {
return {response,status,headers};
}
public onError(response:any, status:any, headers:any):any {
return {response,status,headers};
}
public onCancel(response:any, status:any, headers:any):any {
return {response,status,headers};
}
public onComplete(response:any, status:any, headers:any):any {
return {response,status,headers};
}
public _onBeforeUpload():void {
this.isReady = true;
this.isUploading = true;
this.isUploaded = false;
this.isSuccess = false;
this.isCancel = false;
this.isError = false;
this.progress = 0;
this.onBeforeUpload();
}
public _onBuildForm(form:any):void {
this.onBuildForm(form);
}
public _onProgress(progress:number):void {
this._zone.run(() => {
this.progress = progress;
});
this.onProgress(progress);
}
public _onSuccess(response:any, status:any, headers:any):void {
this.isReady = false;
this.isUploading = false;
this.isUploaded = true;
this.isSuccess = true;
this.isCancel = false;
this.isError = false;
this.progress = 100;
this.index = void 0;
this.onSuccess(response, status, headers);
}
public _onError(response:any, status:any, headers:any):void {
this.isReady = false;
this.isUploading = false;
this.isUploaded = true;
this.isSuccess = false;
this.isCancel = false;
this.isError = true;
this.progress = 0;
this.index = void 0;
this.onError(response, status, headers);
}
public _onCancel(response:any, status:any, headers:any):void {
this.isReady = false;
this.isUploading = false;
this.isUploaded = false;
this.isSuccess = false;
this.isCancel = true;
this.isError = false;
this.progress = 0;
this.index = void 0;
this.onCancel(response, status, headers);
}
public _onComplete(response:any, status:any, headers:any):void {
this.onComplete(response, status, headers);
if (this.uploader.options.removeAfterUpload) {
this.remove();
}
}
public _prepareToUploading():void {
this.index = this.index || ++this.uploader._nextIndex;
this.isReady = true;
}
}

View File

@@ -1,45 +0,0 @@
import { Directive, ElementRef, Input, HostListener } from '@angular/core';
import {FileUploader} from './file-uploader.class';
// todo: filters
@Directive({selector: '[ng2FileSelect]'})
export class FileSelectDirective {
@Input() public uploader:FileUploader;
private element:ElementRef;
public constructor(element:ElementRef) {
this.element = element;
}
public getOptions():any {
return this.uploader.options;
}
public getFilters():any {
return void 0;
}
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];
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);
if (this.isEmptyAfterSelection()) {
// todo
// this.element.nativeElement.properties.value = '';
/*this.element.nativeElement
.replaceWith(this.element = this.element.nativeElement.clone(true)); // IE fix*/
}
}
}

View File

@@ -1,462 +0,0 @@
import {FileLikeObject} from './file-like-object.class';
import {FileItem} from './file-item.class';
import {FileType} from './file-type.class';
function isFile(value:any):boolean {
return (File && value instanceof File);
}
// function isFileLikeObject(value:any) {
export interface Headers {
name:string;
value:string;
}
export interface FileUploaderOptions {
allowedMimeType?:Array<string>;
allowedFileType?:Array<string>;
autoUpload?:boolean;
isHTML5?:boolean;
filters?:Array<any>;
headers?:Array<Headers>;
maxFileSize?:number;
queueLimit?:number;
removeAfterUpload?:boolean;
url?:string;
}
export class FileUploader {
public authToken:string;
public isUploading:boolean = false;
public queue:Array<any> = [];
public progress:number = 0;
public _nextIndex:number = 0;
public autoUpload:any;
public options:FileUploaderOptions = {
autoUpload: false,
isHTML5: true,
filters: [],
removeAfterUpload: false
};
private _failFilterIndex:number;
public constructor(options:any) {
this.setOptions(options);
}
public setOptions(options:any):void {
this.options = Object.assign(this.options, options);
this.authToken = options.authToken;
this.autoUpload = options.autoUpload;
this.options.filters.unshift({name: 'queueLimit', fn: this._queueLimitFilter});
if (this.options.maxFileSize) {
this.options.filters.unshift({name: 'fileSize', fn: this._fileSizeFilter});
}
if (this.options.allowedFileType) {
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: 'folder', fn: this._folderFilter});
}
public addToQueue(files:any[], options?:any, filters?:any):void {
let list:any[] = [];
for (let file of files) {
list.push(file);
}
let arrayOfFilters = this._getFilters(filters);
let count = this.queue.length;
let addedFileItems:any[] = [];
list.map((some:any) => {
if (!options) {
options = this.options;
}
let temp = new FileLikeObject(some);
if (this._isValidFile(temp, arrayOfFilters, options)) {
let fileItem = new FileItem(this, some, options);
addedFileItems.push(fileItem);
this.queue.push(fileItem);
this._onAfterAddingFile(fileItem);
} else {
let filter = arrayOfFilters[this._failFilterIndex];
this._onWhenAddingFileFailed(temp, filter, options);
}
});
if (this.queue.length !== count) {
this._onAfterAddingAll(addedFileItems);
this.progress = this._getTotalProgress();
}
this._render();
if (this.options.autoUpload) {
this.uploadAll();
}
}
public removeFromQueue(value:any):void {
let index = this.getIndexOfItem(value);
let item = this.queue[index];
if (item.isUploading) {
item.cancel();
}
this.queue.splice(index, 1);
this.progress = this._getTotalProgress();
}
public clearQueue():void {
while (this.queue.length) {
this.queue[0].remove();
}
this.progress = 0;
}
public uploadItem(value:FileItem):void {
let index = this.getIndexOfItem(value);
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);
}
public cancelItem(value:any):void {
let index = this.getIndexOfItem(value);
let item = this.queue[index];
let prop = this.options.isHTML5 ? '_xhr' : '_form';
if (item && item.isUploading) {
item[prop].abort();
}
}
public uploadAll():void {
let items = this.getNotUploadedItems().filter((item:any) => !item.isUploading);
if (!items.length) {
return;
}
items.map((item:any) => item._prepareToUploading());
items[0].upload();
}
public cancelAll():void {
let items = this.getNotUploadedItems();
items.map((item:any) => item.cancel());
}
public isFile(value:any):boolean {
return isFile(value);
}
public isFileLikeObject(value:any):boolean {
return value instanceof FileLikeObject;
}
public getIndexOfItem(value:any):number {
return typeof value === 'number' ? value : this.queue.indexOf(value);
}
public getNotUploadedItems():Array<any> {
return this.queue.filter((item:any) => !item.isUploaded);
}
public getReadyItems():Array<any> {
return this.queue
.filter((item:any) => (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:any, form:any):any {
return {fileItem, form};
}
public onAfterAddingFile(fileItem:any):any {
return {fileItem};
}
public onWhenAddingFileFailed(item:any, filter:any, options:any):any {
return {item, filter, options};
}
public onBeforeUploadItem(fileItem:any):any {
return {fileItem};
}
public onProgressItem(fileItem:any, progress:any):any {
return {fileItem, progress};
}
public onProgressAll(progress:any):any {
return {progress};
}
public onSuccessItem(item:any, response:any, status:any, headers:any):any {
return {item, response, status, headers};
}
public onErrorItem(item:any, response:any, status:any, headers:any):any {
return {item, response, status, headers};
}
public onCancelItem(item:any, response:any, status:any, headers:any):any {
return {item, response, status, headers};
}
public onCompleteItem(item:any, response:any, status:any, headers:any):any {
return {item, response, status, headers};
}
public onCompleteAll():any {
return void 0;
}
public _mimeTypeFilter(item:any):boolean {
return !(this.options.allowedMimeType && this.options.allowedMimeType.indexOf(item.type) === -1);
}
public _fileSizeFilter(item:any):boolean {
return !(this.options.maxFileSize && item.size > this.options.maxFileSize);
}
public _fileTypeFilter(item:any):boolean {
return !(this.options.allowedFileType &&
this.options.allowedFileType.indexOf(FileType.getMimeClass(item)) === -1);
}
public _onErrorItem(item:any, response:any, status:any, headers:any):void {
item._onError(response, status, headers);
this.onErrorItem(item, response, status, headers);
}
public _onCompleteItem(item:any, response:any, status:any, headers:any):void {
item._onComplete(response, status, headers);
this.onCompleteItem(item, response, status, headers);
let nextItem = this.getReadyItems()[0];
this.isUploading = false;
if (nextItem) {
nextItem.upload();
return;
}
this.onCompleteAll();
this.progress = this._getTotalProgress();
this._render();
}
protected _headersGetter(parsedHeaders:any):any {
return (name:any) => {
if (name) {
return parsedHeaders[name.toLowerCase()] || void 0;
}
return parsedHeaders;
};
}
protected _xhrTransport(item:any):any {
let xhr = item._xhr = new XMLHttpRequest();
let form = new FormData();
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');
}
this._onBuildItemForm(item, form);
form.append(item.alias, item._file, item.file.name);
xhr.upload.onprogress = (event:any) => {
let progress = Math.round(event.lengthComputable ? event.loaded * 100 / event.total : 0);
this._onProgressItem(item, progress);
};
xhr.onload = () => {
let headers = this._parseHeaders(xhr.getAllResponseHeaders());
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._onCompleteItem(item, response, xhr.status, headers);
};
xhr.onerror = () => {
let headers = this._parseHeaders(xhr.getAllResponseHeaders());
let response = this._transformResponse(xhr.response, headers);
this._onErrorItem(item, response, xhr.status, headers);
this._onCompleteItem(item, response, xhr.status, headers);
};
xhr.onabort = () => {
let headers = this._parseHeaders(xhr.getAllResponseHeaders());
let response = this._transformResponse(xhr.response, headers);
this._onCancelItem(item, response, xhr.status, headers);
this._onCompleteItem(item, response, xhr.status, headers);
};
xhr.open(item.method, item.url, true);
xhr.withCredentials = item.withCredentials;
// todo
/*item.headers.map((value, name) => {
xhr.setRequestHeader(name, value);
});*/
if (this.options.headers) {
for (let header of this.options.headers) {
xhr.setRequestHeader(header.name, header.value);
}
}
if (this.authToken) {
xhr.setRequestHeader('Authorization', this.authToken);
}
xhr.send(form);
this._render();
}
private _getTotalProgress(value:number = 0):number {
if (this.options.removeAfterUpload) {
return value;
}
let notUploaded = this.getNotUploadedItems().length;
let uploaded = notUploaded ? this.queue.length - notUploaded : this.queue.length;
let ratio = 100 / this.queue.length;
let current = value * ratio / 100;
return Math.round(uploaded * ratio + current);
}
private _getFilters(filters:any):any {
if (!filters) {
return this.options.filters;
}
if (Array.isArray(filters)) {
return filters;
}
if (typeof filters === 'string') {
let names = filters.match(/[^\s,]+/g);
return this.options.filters
.filter((filter:any) => names.indexOf(filter.name) !== -1);
}
return this.options.filters;
}
private _render():any {
return void 0;
// todo: ?
}
// private _folderFilter(item:any):boolean {
// return !!(item.size || item.type);
// }
private _queueLimitFilter():boolean {
return this.options.queueLimit === undefined || this.queue.length < this.options.queueLimit;
}
private _isValidFile(file:any, filters:any, options:any):boolean {
this._failFilterIndex = -1;
return !filters.length ? true : filters.every((filter:any) => {
this._failFilterIndex++;
return filter.fn.call(this, file, options);
});
}
private _isSuccessCode(status:any):boolean {
return (status >= 200 && status < 300) || status === 304;
}
/* tslint:disable */
private _transformResponse(response:any, headers:any):any {
// todo: ?
/*var headersGetter = this._headersGetter(headers);
forEach($http.defaults.transformResponse, (transformFn) => {
response = transformFn(response, headersGetter);
});*/
return response;
}
/* tslint:enable */
private _parseHeaders(headers:any):any {
let parsed:any = {};
let key:any;
let val:any;
let i:any;
if (!headers) {
return parsed;
}
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;
}
});
return parsed;
}
/*private _iframeTransport(item:any) {
// todo: implement it later
}*/
private _onWhenAddingFileFailed(item:any, filter:any, options:any):void {
this.onWhenAddingFileFailed(item, filter, options);
}
private _onAfterAddingFile(item:any):void {
this.onAfterAddingFile(item);
}
private _onAfterAddingAll(items:any):void {
this.onAfterAddingAll(items);
}
private _onBeforeUploadItem(item:any):void {
item._onBeforeUpload();
this.onBeforeUploadItem(item);
}
private _onBuildItemForm(item:any, form:any):void {
item._onBuildForm(form);
this.onBuildItemForm(item, form);
}
private _onProgressItem(item:any, progress:any):void {
let total = this._getTotalProgress(progress);
this.progress = total;
item._onProgress(progress);
this.onProgressItem(item, progress);
this.onProgressAll(total);
this._render();
}
/* tslint:disable */
private _onSuccessItem(item:any, response:any, status:any, headers:any):void {
item._onSuccess(response, status, headers);
this.onSuccessItem(item, response, status, headers);
}
/* tslint:enable */
private _onCancelItem(item:any, response:any, status:any, headers:any):void {
item._onCancel(response, status, headers);
this.onCancelItem(item, response, status, headers);
}
}

2
demo/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
# Created by .ignore support plugin (hsz.mobi)
src/api-doc.json

View File

@@ -1,119 +0,0 @@
/**
* okaidia theme for JavaScript, CSS and HTML
* Loosely based on Monokai textmate theme by http://www.monokai.nl/
* @author ocodia
*/
code[class*="language-"],
pre[class*="language-"] {
color: #f8f8f2;
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #272822;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #f8f8f2;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted {
color: #f92672;
}
.token.boolean,
.token.number {
color: #ae81ff;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #a6e22e;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function {
color: #e6db74;
}
.token.keyword {
color: #66d9ef;
}
.token.regex,
.token.important {
color: #fd971f;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

4
demo/bs-config.json Normal file
View File

@@ -0,0 +1,4 @@
{
"port": 4200,
"server": { "baseDir": "./demo/dist" }
}

View File

@@ -1,81 +0,0 @@
import {Component} from '@angular/core';
import {CORE_DIRECTIVES} from '@angular/common';
import {TAB_DIRECTIVES} from 'ng2-bootstrap/ng2-bootstrap';
import {SimpleDemoComponent} from './file-upload/simple-demo';
let name = 'File Upload';
let doc = require('../../components/file-upload/readme.md');
let tabDesc:Array<any> = [
{
heading: 'Simple',
ts: require('!!prismjs?lang=typescript!./file-upload/simple-demo.ts'),
html: require('!!prismjs?lang=markup!./file-upload/simple-demo.html'),
js: require('!!prismjs?lang=javascript!./file-upload/file-catcher.js')
}
];
let tabsContent:string = ``;
tabDesc.forEach((desc:any) => {
tabsContent += `
<tab heading="${desc.heading}" (select)="select($event)">
<div class="card card-block panel panel-default panel-body">
<${desc.heading.toLowerCase()}-demo *ngIf="currentHeading === '${desc.heading}'"></${desc.heading.toLowerCase()}-demo>
<br>
<div class="row" style="margin: 0px;">
<tabset>
<tab heading="Markup">
<div class="card card-block panel panel-default panel-body">
<pre class="language-html"><code class="language-html" ng-non-bindable>${desc.html}</code></pre>
</div>
</tab>
<tab heading="TypeScript">
<div class="card card-block panel panel-default panel-body">
<pre class="language-typescript"><code class="language-typescript" ng-non-bindable>${desc.ts}</code></pre>
</div>
</tab>
<tab heading="Backend Demo">
<div class="card card-block panel panel-default panel-body">
<pre class="language-javascript"><code class="language-javascript" ng-non-bindable>${desc.js}</code></pre>
</div>
</tab>
</tabset>
</div>
</div>
</tab>
`;
});
@Component({
selector: 'file-upload-section',
template: `
<section id="${name.toLowerCase()}">
<div class="row">
<tabset>
${tabsContent}
</tabset>
</div>
<div class="row">
<h2>API</h2>
<div class="card card-block panel panel-default panel-body">${doc}</div>
</div>
</section>
`,
directives: [SimpleDemoComponent, TAB_DIRECTIVES, CORE_DIRECTIVES]
})
export class FileUploadSectionComponent {
public currentHeading:string = 'Simple';
public select(e:any):void {
if (e.heading) {
this.currentHeading = e.heading;
}
}
}

View File

@@ -1,28 +0,0 @@
import {Component} from '@angular/core';
import {CORE_DIRECTIVES, FORM_DIRECTIVES, NgClass, NgStyle} from '@angular/common';
import {FILE_UPLOAD_DIRECTIVES, FileUploader} from '../../../ng2-file-upload';
// webpack html imports
let template = require('./simple-demo.html');
// const URL = '/api/';
const URL = 'https://evening-anchorage-3159.herokuapp.com/api/';
@Component({
selector: 'simple-demo',
template: template,
directives: [FILE_UPLOAD_DIRECTIVES, NgClass, NgStyle, CORE_DIRECTIVES, FORM_DIRECTIVES]
})
export class SimpleDemoComponent {
public uploader:FileUploader = new FileUploader({url: URL});
public hasBaseDropZoneOver:boolean = false;
public hasAnotherDropZoneOver:boolean = false;
public fileOverBase(e:any):void {
this.hasBaseDropZoneOver = e;
}
public fileOverAnother(e:any):void {
this.hasAnotherDropZoneOver = e;
}
}

View File

@@ -1,3 +0,0 @@
<label class="btn btn-primary">Select File
<input type="file" (change)="onChange($event)" [multiple]="multiple" style="display: none;"/>
</label>

View File

@@ -1,122 +0,0 @@
import {Component, ElementRef, Renderer, Input, HostListener, HostBinding, OnInit} from '@angular/core';
import {FileUploader, FileUploaderOptions} from '../../../../ng2-file-upload';
@Component({
selector: 'demo-file-upload',
providers: [FileUploader],
template: require('./demo.html'),
styles: [':host {border:1px solid black; padding:59px;display: block;}' +
'.hover {border: 3px solid green; backgroud: black;}']
})
export class DemoFileUploadComponent implements OnInit {
@Input() public url:string;
@Input() public queueLimit:number;
@Input() public maxFileSize:number;
@Input() public autoUpload:boolean;
@Input() public allowedMimeType:Array<string>;
@Input() public allowedFileType:Array<string>;
@Input() public headers:Array<any>;
@HostBinding('class.hover') private isHover:boolean = false;
private inputs:string[] = ['allowedMimeType',
'allowedFileType',
'autoUpload',
'isHTML5',
'headers',
'maxFileSize',
'queueLimit',
'removeAfterUpload',
'url'
];
private uploaderOptions:FileUploaderOptions = {};
private multiple:boolean = true;
private element:ElementRef;
private fileUploadService:FileUploader;
private renderer:Renderer;
public constructor(element:ElementRef, fileUploadService:FileUploader, renderer:Renderer) {
this.element = element;
this.fileUploadService = fileUploadService;
this.renderer = renderer;
}
public ngOnInit():any {
for (let input of this.inputs) {
if (this[input]) {
this.uploaderOptions[input] = this[input];
}
}
this.fileUploadService.setOptions(this.uploaderOptions);
this.multiple = (!this.queueLimit || this.queueLimit > 1);
}
@HostListener('drop', ['$event'])
public onDrop(event:any):void {
this._preventAndStop(event);
this.isHover = false;
let transfer = this._getTransfer(event);
if (!transfer) {
return;
}
this.fileUploadService.addToQueue(transfer.files);
}
@HostListener('dragover', ['$event'])
public onDragOver(event:any):void {
this._preventAndStop(event);
if (this.isHover) {
return;
}
let transfer = this._getTransfer(event);
if (!this._haveFiles(transfer.types)) {
return;
}
this.isHover = true;
}
@HostListener('dragleave', ['$event'])
public onDragLeave(event:any):void {
this._preventAndStop(event);
if (event.currentTarget === (this as any).element[0]) {
return;
}
this.isHover = false;
}
public onChange($event:any):void {
this.fileUploadService.addToQueue($event.srcElement.files);
}
private _getTransfer(event:any):any {
return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer;
}
private _preventAndStop(event:any):any {
event.preventDefault();
event.stopPropagation();
}
private _haveFiles(types:any):any {
if (!types) {
return false;
}
if (types.indexOf) {
return types.indexOf('Files') !== -1;
} else if (types.contains) {
return types.contains('Files');
} else {
return false;
}
}
}

View File

@@ -1,10 +1,6 @@
import {bootstrap} from '@angular/platform-browser-dynamic';
import {Component} from '@angular/core';
import {NgClass} from '@angular/common';
import { Component } from '@angular/core';
import {FileUploadSectionComponent} from './components/file-upload-section';
let gettingStarted = require('./getting-started.md');
let gettingStarted = require('html-loader!markdown-loader!../getting-started.md');
@Component({
selector: 'app',
@@ -22,7 +18,7 @@ let gettingStarted = require('./getting-started.md');
</main>
<div class="container">
<section id="getting-started">${gettingStarted}</section>
<section id="getting-started" [innerHtml]="gettingStarted"></section>
<file-upload-section class="col-md-12"></file-upload-section>
</div>
@@ -32,13 +28,16 @@ let gettingStarted = require('./getting-started.md');
<p class="text-muted text-center"><a href="https://github.com/valor-software/ng2-file-upload">ng2-file-upload</a> is maintained by <a href="https://github.com/valor-software">valor-software</a>.</p>
</div>
</footer>
`,
directives: [
NgClass,
FileUploadSectionComponent
]
`
})
export class DemoComponent {
export class AppComponent {
public gettingStarted:string = gettingStarted;
public ngAfterContentInit(): any {
setTimeout(()=>{
if (typeof PR !== 'undefined') {
// google code-prettify
PR.prettyPrint();
}
}, 150);
}
}
bootstrap(DemoComponent);

View File

@@ -0,0 +1,19 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { TabsModule } from 'ngx-bootstrap/tabs';
import { FileUploadModule } from 'ng2-file-upload';
import { AppComponent } from './app.component';
import { FileUploadSectionComponent } from './components/file-upload-section';
import { SimpleDemoComponent } from './components/file-upload/simple-demo';
@NgModule({
imports: [BrowserModule, CommonModule, FileUploadModule, TabsModule.forRoot(), FormsModule],
declarations: [AppComponent, FileUploadSectionComponent, SimpleDemoComponent],
bootstrap: [AppComponent]
})
export class AppModule {
}

View File

@@ -0,0 +1,40 @@
<section [attr.id]="name.toLowerCase()">
<div class="row">
<tabset>
<tab *ngFor="let desc of tabs" heading="{{desc.heading}}" (select)="select($event)">
<div class="card card-block panel panel-default panel-body">
<simple-demo></simple-demo>
<br>
<div class="row" style="margin: 0px;">
<tabset>
<tab heading="Markup">
<div class="card card-block panel panel-default panel-body">
<pre class="prettyprint linenums lang-html">{{desc.html}}</pre>
</div>
</tab>
<tab heading="TypeScript">
<div class="card card-block panel panel-default panel-body">
<pre class="prettyprint linenums lang-js">{{desc.ts}}</pre>
<pre class="language-typescript"><code class="language-typescript" ng-non-bindable [innerHTML]="desc.ts"></code></pre>
</div>
</tab>
<tab heading="Backend Demo">
<div class="card card-block panel panel-default panel-body">
<pre class="prettyprint linenums lang-js">{{desc.js}}</pre>
</div>
</tab>
</tabset>
</div>
</div>
</tab>
</tabset>
</div>
<div class="row">
<h2>API</h2>
<div class="card card-block panel panel-default panel-body" [innerHTML]="doc"></div>
</div>
</section>

View File

@@ -0,0 +1,29 @@
import { Component } from '@angular/core';
let doc = require('html-loader!markdown-loader!../../doc.md');
let tabDesc:Array<any> = [
{
heading: 'Simple',
ts: require('!!raw-loader?lang=typescript!./file-upload/simple-demo.ts'),
html: require('!!raw-loader?lang=markup!./file-upload/simple-demo.html'),
js: require('!!raw-loader?lang=javascript!./file-upload/file-catcher.js')
}
];
@Component({
selector: 'file-upload-section',
templateUrl: './file-upload-section.html'
})
export class FileUploadSectionComponent {
public name:string = 'File Upload';
public currentHeading:string = 'Simple';
public doc:string = doc;
public tabs:any = tabDesc;
public select(e:any):void {
if (e.heading) {
this.currentHeading = e.heading;
}
}
}

View File

@@ -0,0 +1,50 @@
/*eslint-disable*/
var express = require('express');
var multer = require('multer');
var fs = require('fs');
var app = express();
var DIR = './uploads/';
var upload = multer({dest: DIR});
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://valor-software.github.io');
res.setHeader('Access-Control-Allow-Methods', 'POST');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.use(multer({
dest: DIR,
rename: function (fieldname, filename) {
return filename + Date.now();
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...');
},
onFileUploadComplete: function (file) {
console.log(file.fieldname + ' uploaded to ' + file.path);
}
}));
app.get('/api', function (req, res) {
res.end('file catcher example');
});
app.post('/api', function (req, res) {
upload(req, res, function (err) {
if (err) {
return res.end(err.toString());
}
res.end('File is uploaded');
});
});
var PORT = process.env.PORT || 3000;
app.listen(PORT, function () {
console.log('Working on port ' + PORT);
});

View File

@@ -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

@@ -0,0 +1,50 @@
import { Component } from '@angular/core';
import { FileUploader } from 'ng2-file-upload';
// const URL = '/api/';
const URL = 'https://evening-anchorage-3159.herokuapp.com/api/';
@Component({
selector: 'simple-demo',
templateUrl: './simple-demo.html'
})
export class SimpleDemoComponent {
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;
}
public fileOverAnother(e:any):void {
this.hasAnotherDropZoneOver = e;
}
}

2
demo/src/app/index.ts Normal file
View File

@@ -0,0 +1,2 @@
export * from './app.component';
export * from './app.module';

View File

@@ -0,0 +1,217 @@
.prettyprint {
white-space: pre-wrap;
background: #F5F6F7;
font-family: Monaco,"Lucida Console",monospace;
color: #5C707A;
width: auto;
overflow: auto;
position: relative;
padding: 0;
font-size: 13px;
line-height: 24px;
margin-bottom: 24px;
border-radius: 4px;
padding: 16px 32px
}
.prettyprint.linenums,.prettyprint[class^="linenums:"],.prettyprint[class*=" linenums:"] {
padding: 0
}
.prettyprint.is-showcase {
border: 4px solid #0273D4
}
.prettyprint code {
background: none;
font-size: 13px;
padding: 0
}
.prettyprint ol {
background: #F5F6F7;
padding: 16px 32px 16px 56px;
margin: 0;
overflow: auto;
font-size: 13px
}
.prettyprint ol li,.prettyprint .tag {
color: #7a8b94;
background: none;
margin-bottom: 5px;
line-height: normal;
list-style-type: decimal;
font-size: 12px
}
.prettyprint ol li:last-child {
margin-bottom: 0
}
.prettyprint ol li code {
background: none;
font-size: 13px
}
.prettyprint .pnk,.prettyprint .blk {
border-radius: 4px;
padding: 2px 4px
}
.prettyprint .pnk {
background: #CFD8DC;
color: #5C707A
}
.prettyprint .blk {
background: #E0E0E0
}
.prettyprint .otl {
outline: 1px solid rgba(169,169,169,0.56)
}
.prettyprint .kwd {
color: #D43669
}
.prettyprint .typ,.prettyprint .tag {
color: #D43669
}
.prettyprint .str,.prettyprint .atv {
color: #647f11
}
.prettyprint .atn {
/*color: #647f11*/
color: #31708f
}
.prettyprint .com {
color: #647f11
}
.prettyprint .lit {
color: #647f11
}
.prettyprint .pun {
color: #7a8b94
}
.prettyprint .pln {
color: #5C707A
/*color: #8a6d3b*/
}
.prettyprint .dec {
color: #647f11
}
@media print {
.prettyprint {
background: #F5F6F7;
border: none;
box-shadow: none
}
.prettyprint ol {
background: #F5F6F7
}
.prettyprint .kwd {
color: #D43669
}
.prettyprint .typ,.prettyprint .tag {
color: #D43669
}
.prettyprint .str,.prettyprint .atv {
color: #647f11
}
.prettyprint .atn {
/*color: #647f11*/
color: #31708f
}
.prettyprint .com {
color: #647f11
}
.prettyprint .lit {
color: #647f11
}
.prettyprint .pun {
color: #7a8b94
}
.prettyprint .pln {
color: #5C707A
}
.prettyprint .dec {
color: #647f11
}
}
h1 .prettyprint,h2 .prettyprint,h3 .prettyprint,h4 .prettyprint {
background: none;
font-family: Monaco,"Lucida Console",monospace;
color: #253238;
overflow: hidden;
position: relative;
font-size: 15px;
font-weight: 600;
line-height: 24px;
margin: 0;
border: none;
box-shadow: none;
padding: 0
}
h1 .prettyprint code,h2 .prettyprint code,h3 .prettyprint code,h4 .prettyprint code {
background: none;
font-size: 15px;
padding: 0
}
h1 .prettyprint .kwd,h2 .prettyprint .kwd,h3 .prettyprint .kwd,h4 .prettyprint .kwd {
color: #253238
}
h1 .prettyprint .typ,h1 .prettyprint .tag,h2 .prettyprint .typ,h2 .prettyprint .tag,h3 .prettyprint .typ,h3 .prettyprint .tag,h4 .prettyprint .typ,h4 .prettyprint .tag {
color: #B52E31
}
h1 .prettyprint .str,h1 .prettyprint .atv,h2 .prettyprint .str,h2 .prettyprint .atv,h3 .prettyprint .str,h3 .prettyprint .atv,h4 .prettyprint .str,h4 .prettyprint .atv {
color: #9d8d00
}
h1 .prettyprint .atn,h2 .prettyprint .atn,h3 .prettyprint .atn,h4 .prettyprint .atn {
color: #71a436
}
h1 .prettyprint .com,h2 .prettyprint .com,h3 .prettyprint .com,h4 .prettyprint .com {
color: #AFBEC5
}
h1 .prettyprint .lit,h2 .prettyprint .lit,h3 .prettyprint .lit,h4 .prettyprint .lit {
color: #9d8d00
}
h1 .prettyprint .pun,h2 .prettyprint .pun,h3 .prettyprint .pun,h4 .prettyprint .pun {
color: #000
}
h1 .prettyprint .pln,h2 .prettyprint .pln,h3 .prettyprint .pln,h4 .prettyprint .pln {
color: #000
}
h1 .prettyprint .dec,h2 .prettyprint .dec,h3 .prettyprint .dec,h4 .prettyprint .dec {
color: #8762c6
}

View File

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

36
demo/src/assets/js/prettify.min.js vendored Normal file
View File

@@ -0,0 +1,36 @@
!function () { var q = null; window.PR_SHOULD_USE_CONTINUATION = !0;
(function () { function S(a) { function d(e) { var b = e.charCodeAt(0); if (b !== 92) return b; var a = e.charAt(1); return (b = r[a]) ? b : '0' <= a && a <= '7' ? parseInt(e.substring(1), 8) : a === 'u' || a === 'x' ? parseInt(e.substring(2), 16) : e.charCodeAt(1); } function g(e) { if (e < 32) return (e < 16 ? '\\x0' : '\\x') + e.toString(16); e = String.fromCharCode(e); return e === '\\' || e === '-' || e === ']' || e === '^' ? '\\' + e : e; } function b(e) { var b = e.substring(1, e.length - 1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g), e = [], a =
b[0] === '^', c = ['[']; a && c.push('^'); for (var a = a ? 1 : 0, f = b.length; a < f; ++a) { var h = b[a]; if (/\\[bdsw]/i.test(h))c.push(h); else { var h = d(h), l; a + 2 < f && '-' === b[a + 1] ? (l = d(b[a + 2]), a += 2) : l = h; e.push([h, l]); l < 65 || h > 122 || (l < 65 || h > 90 || e.push([Math.max(65, h) | 32, Math.min(l, 90) | 32]), l < 97 || h > 122 || e.push([Math.max(97, h) & -33, Math.min(l, 122) & -33])); } }e.sort(function (e, a) { return e[0] - a[0] || a[1] - e[1]; }); b = []; f = []; for (a = 0; a < e.length; ++a)h = e[a], h[0] <= f[1] + 1 ? f[1] = Math.max(f[1], h[1]) : b.push(f = h); for (a = 0; a < b.length; ++a)h = b[a], c.push(g(h[0])),
h[1] > h[0] && (h[1] + 1 > h[0] && c.push('-'), c.push(g(h[1]))); c.push(']'); return c.join(''); } function s(e) { for (var a = e.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g), c = a.length, d = [], f = 0, h = 0; f < c; ++f) { var l = a[f]; l === '(' ? ++h : '\\' === l.charAt(0) && (l = +l.substring(1)) && (l <= h ? d[l] = -1 : a[f] = g(l)); } for (f = 1; f < d.length; ++f)-1 === d[f] && (d[f] = ++x); for (h = f = 0; f < c; ++f)l = a[f], l === '(' ? (++h, d[h] || (a[f] = '(?:')) : '\\' === l.charAt(0) && (l = +l.substring(1)) && l <= h &&
(a[f] = '\\' + d[l]); for (f = 0; f < c; ++f)'^' === a[f] && '^' !== a[f + 1] && (a[f] = ''); if (e.ignoreCase && m) for (f = 0; f < c; ++f)l = a[f], e = l.charAt(0), l.length >= 2 && e === '[' ? a[f] = b(l) : e !== '\\' && (a[f] = l.replace(/[A-Za-z]/g, function (a) { a = a.charCodeAt(0); return '[' + String.fromCharCode(a & -33, a | 32) + ']'; })); return a.join(''); } for (var x = 0, m = !1, j = !1, k = 0, c = a.length; k < c; ++k) { var i = a[k]; if (i.ignoreCase)j = !0; else if (/[a-z]/i.test(i.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi, ''))) { m = !0; j = !1; break; } } for (var r = {
b: 8, t: 9, n: 10, v: 11,
f: 12, r: 13
}, n = [], k = 0, c = a.length; k < c; ++k) { i = a[k]; if (i.global || i.multiline) throw Error('' + i); n.push('(?:' + s(i) + ')'); } return RegExp(n.join('|'), j ? 'gi' : 'g'); } function T(a, d) { function g(a) { var c = a.nodeType; if (c == 1) { if (!b.test(a.className)) { for (c = a.firstChild; c; c = c.nextSibling)g(c); c = a.nodeName.toLowerCase(); if ('br' === c || 'li' === c)s[j] = '\n', m[j << 1] = x++, m[j++ << 1 | 1] = a; } } else if (c == 3 || c == 4)c = a.nodeValue, c.length && (c = d ? c.replace(/\r\n?/g, '\n') : c.replace(/[\t\n\r ]+/g, ' '), s[j] = c, m[j << 1] = x, x += c.length, m[j++ << 1 | 1] =
a); } var b = /(?:^|\s)nocode(?:\s|$)/, s = [], x = 0, m = [], j = 0; g(a); return {a: s.join('').replace(/\n$/, ''), d: m}; } function H(a, d, g, b) { d && (a = {a: d, e: a}, g(a), b.push.apply(b, a.g)); } function U(a) { for (var d = void 0, g = a.firstChild; g; g = g.nextSibling) var b = g.nodeType, d = b === 1 ? d ? a : g : b === 3 ? V.test(g.nodeValue) ? a : d : d; return d === a ? void 0 : d; } function C(a, d) { function g(a) { for (var j = a.e, k = [j, 'pln'], c = 0, i = a.a.match(s) || [], r = {}, n = 0, e = i.length; n < e; ++n) { var z = i[n], w = r[z], t = void 0, f; if (typeof w === 'string')f = !1; else { var h = b[z.charAt(0)];
if (h)t = z.match(h[1]), w = h[0]; else { for (f = 0; f < x; ++f) if (h = d[f], t = z.match(h[1])) { w = h[0]; break; }t || (w = 'pln'); } if ((f = w.length >= 5 && 'lang-' === w.substring(0, 5)) && !(t && typeof t[1] === 'string'))f = !1, w = 'src'; f || (r[z] = w); }h = c; c += z.length; if (f) { f = t[1]; var l = z.indexOf(f), B = l + f.length; t[2] && (B = z.length - t[2].length, l = B - f.length); w = w.substring(5); H(j + h, z.substring(0, l), g, k); H(j + h + l, f, I(w, f), k); H(j + h + B, z.substring(B), g, k); } else k.push(j + h, w); }a.g = k; } var b = {}, s; (function () { for (var g = a.concat(d), j = [], k = {}, c = 0, i = g.length; c < i; ++c) { var r =
g[c], n = r[3]; if (n) for (var e = n.length; --e >= 0;)b[n.charAt(e)] = r; r = r[1]; n = '' + r; k.hasOwnProperty(n) || (j.push(r), k[n] = q); }j.push(/[\S\s]/); s = S(j); })(); var x = d.length; return g; } function v(a) { var d = [], g = []; a.tripleQuotedStrings ? d.push(['str', /^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/, q, '\'"']) : a.multiLineStrings ? d.push(['str', /^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
q, '\'"`']) : d.push(['str', /^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/, q, '"\'']); a.verbatimStrings && g.push(['str', /^@"(?:[^"]|"")*(?:"|$)/, q]); var b = a.hashComments; b && (a.cStyleComments ? (b > 1 ? d.push(['com', /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, q, '#']) : d.push(['com', /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/, q, '#']), g.push(['str', /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/, q])) : d.push(['com',
/^#[^\n\r]*/, q, '#'])); a.cStyleComments && (g.push(['com', /^\/\/[^\n\r]*/, q]), g.push(['com', /^\/\*[\S\s]*?(?:\*\/|$)/, q])); if (b = a.regexLiterals) { var s = (b = b > 1 ? '' : '\n\r') ? '.' : '[\\S\\s]'; g.push(['lang-regex', RegExp('^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*(' + ('/(?=[^/*' + b + '])(?:[^/\\x5B\\x5C' + b + ']|\\x5C' + s + '|\\x5B(?:[^\\x5C\\x5D' + b + ']|\\x5C' +
s + ')*(?:\\x5D|$))+/') + ')')]); }(b = a.types) && g.push(['typ', b]); b = ('' + a.keywords).replace(/^ | $/g, ''); b.length && g.push(['kwd', RegExp('^(?:' + b.replace(/[\s,]+/g, '|') + ')\\b'), q]); d.push(['pln', /^\s+/, q, ' \r\n\t\u00a0']); b = '^.[^\\s\\w.$@\'"`/\\\\]*'; a.regexLiterals && (b += '(?!s*/)'); g.push(['lit', /^@[$_a-z][\w$@]*/i, q], ['typ', /^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/, q], ['pln', /^[$_a-z][\w$@]*/i, q], ['lit', /^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i, q, '0123456789'], ['pln', /^\\[\S\s]?/,
q], ['pun', RegExp(b), q]); return C(d, g); } function J(a, d, g) { function b(a) { var c = a.nodeType; if (c == 1 && !x.test(a.className)) if ('br' === a.nodeName)s(a), a.parentNode && a.parentNode.removeChild(a); else for (a = a.firstChild; a; a = a.nextSibling)b(a); else if ((c == 3 || c == 4) && g) { var d = a.nodeValue, i = d.match(m); if (i)c = d.substring(0, i.index), a.nodeValue = c, (d = d.substring(i.index + i[0].length)) && a.parentNode.insertBefore(j.createTextNode(d), a.nextSibling), s(a), c || a.parentNode.removeChild(a); } } function s(a) { function b(a, c) { var d =
c ? a.cloneNode(!1) : a, e = a.parentNode; if (e) { var e = b(e, 1), g = a.nextSibling; e.appendChild(d); for (var i = g; i; i = g)g = i.nextSibling, e.appendChild(i); } return d; } for (;!a.nextSibling;) if (a = a.parentNode, !a) return; for (var a = b(a.nextSibling, 0), d; (d = a.parentNode) && d.nodeType === 1;)a = d; c.push(a); } for (var x = /(?:^|\s)nocode(?:\s|$)/, m = /\r\n?|\n/, j = a.ownerDocument, k = j.createElement('li'); a.firstChild;)k.appendChild(a.firstChild); for (var c = [k], i = 0; i < c.length; ++i)b(c[i]); d === (d | 0) && c[0].setAttribute('value', d); var r = j.createElement('ol');
r.className = 'linenums'; for (var d = Math.max(0, d - 1 | 0) || 0, i = 0, n = c.length; i < n; ++i)k = c[i], k.className = 'L' + (i + d) % 10, k.firstChild || k.appendChild(j.createTextNode('\u00a0')), r.appendChild(k); a.appendChild(r); } function p(a, d) { for (var g = d.length; --g >= 0;) { var b = d[g]; F.hasOwnProperty(b) ? D.console && console.warn('cannot override language handler %s', b) : F[b] = a; } } function I(a, d) { if (!a || !F.hasOwnProperty(a))a = /^\s*</.test(d) ? 'default-markup' : 'default-code'; return F[a]; } function K(a) { var d = a.h; try { var g = T(a.c, a.i), b = g.a;
a.a = b; a.d = g.d; a.e = 0; I(d, b)(a); var s = /\bMSIE\s(\d+)/.exec(navigator.userAgent), s = s && +s[1] <= 8, d = /\n/g, x = a.a, m = x.length, g = 0, j = a.d, k = j.length, b = 0, c = a.g, i = c.length, r = 0; c[i] = m; var n, e; for (e = n = 0; e < i;)c[e] !== c[e + 2] ? (c[n++] = c[e++], c[n++] = c[e++]) : e += 2; i = n; for (e = n = 0; e < i;) { for (var p = c[e], w = c[e + 1], t = e + 2; t + 2 <= i && c[t + 1] === w;)t += 2; c[n++] = p; c[n++] = w; e = t; }c.length = n; var f = a.c, h; if (f)h = f.style.display, f.style.display = 'none'; try { for (;b < k;) { var l = j[b + 2] || m, B = c[r + 2] || m, t = Math.min(l, B), A = j[b + 1], G; if (A.nodeType !== 1 && (G = x.substring(g,
t))) { s && (G = G.replace(d, '\r')); A.nodeValue = G; var L = A.ownerDocument, o = L.createElement('span'); o.className = c[r + 1]; var v = A.parentNode; v.replaceChild(o, A); o.appendChild(A); g < l && (j[b + 1] = A = L.createTextNode(x.substring(t, l)), v.insertBefore(A, o.nextSibling)); }g = t; g >= l && (b += 2); g >= B && (r += 2); } } finally { if (f)f.style.display = h; } } catch (u) { D.console && console.log(u && u.stack || u); } } var D = window, y = ['break,continue,do,else,for,if,return,while'], E = [[y, 'auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile'],
'catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof'], M = [E, 'alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where'], N = [E, 'abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient'],
O = [N, 'as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where'], E = [E, 'debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN'], P = [y, 'and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None'],
Q = [y, 'alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END'], W = [y, 'as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use'], y = [y, 'case,done,elif,esac,eval,fi,function,in,local,set,then,until'], R = /^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
V = /\S/, X = v({keywords: [M, O, E, 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END', P, Q, y], hashComments: !0, cStyleComments: !0, multiLineStrings: !0, regexLiterals: !0}), F = {}; p(X, ['default-code']); p(C([], [['pln', /^[^<?]+/], ['dec', /^<!\w[^>]*(?:>|$)/], ['com', /^<\!--[\S\s]*?(?:--\>|$)/], ['lang-', /^<\?([\S\s]+?)(?:\?>|$)/], ['lang-', /^<%([\S\s]+?)(?:%>|$)/], ['pun', /^(?:<[%?]|[%?]>)/], ['lang-',
/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i], ['lang-js', /^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i], ['lang-css', /^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i], ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i]]), ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']); p(C([['pln', /^\s+/, q, ' \t\r\n'], ['atv', /^(?:"[^"]*"?|'[^']*'?)/, q, '"\'']], [['tag', /^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i], ['atn', /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], ['lang-uq.val', /^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/], ['pun', /^[/<->]+/],
['lang-js', /^on\w+\s*=\s*"([^"]+)"/i], ['lang-js', /^on\w+\s*=\s*'([^']+)'/i], ['lang-js', /^on\w+\s*=\s*([^\s"'>]+)/i], ['lang-css', /^style\s*=\s*"([^"]+)"/i], ['lang-css', /^style\s*=\s*'([^']+)'/i], ['lang-css', /^style\s*=\s*([^\s"'>]+)/i]]), ['in.tag']); p(C([], [['atv', /^[\S\s]+/]]), ['uq.val']); p(v({keywords: M, hashComments: !0, cStyleComments: !0, types: R}), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']); p(v({keywords: 'null,true,false'}), ['json']); p(v({keywords: O, hashComments: !0, cStyleComments: !0, verbatimStrings: !0, types: R}),
['cs']); p(v({keywords: N, cStyleComments: !0}), ['java']); p(v({keywords: y, hashComments: !0, multiLineStrings: !0}), ['bash', 'bsh', 'csh', 'sh']); p(v({keywords: P, hashComments: !0, multiLineStrings: !0, tripleQuotedStrings: !0}), ['cv', 'py', 'python']); p(v({keywords: 'caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END', hashComments: !0, multiLineStrings: !0, regexLiterals: 2}), ['perl', 'pl', 'pm']); p(v({
keywords: Q,
hashComments: !0, multiLineStrings: !0, regexLiterals: !0
}), ['rb', 'ruby']); p(v({keywords: E, cStyleComments: !0, regexLiterals: !0}), ['javascript', 'js']); p(v({keywords: 'all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes', hashComments: 3, cStyleComments: !0, multilineStrings: !0, tripleQuotedStrings: !0, regexLiterals: !0}), ['coffee']); p(v({keywords: W, cStyleComments: !0, multilineStrings: !0}), ['rc', 'rs', 'rust']);
p(C([], [['str', /^[\S\s]+/]]), ['regex']); var Y = D.PR = {
createSimpleLexer: C, registerLangHandler: p, sourceDecorator: v, PR_ATTRIB_NAME: 'atn', PR_ATTRIB_VALUE: 'atv', PR_COMMENT: 'com', PR_DECLARATION: 'dec', PR_KEYWORD: 'kwd', PR_LITERAL: 'lit', PR_NOCODE: 'nocode', PR_PLAIN: 'pln', PR_PUNCTUATION: 'pun', PR_SOURCE: 'src', PR_STRING: 'str', PR_TAG: 'tag', PR_TYPE: 'typ', prettyPrintOne: D.prettyPrintOne = function (a, d, g) { var b = document.createElement('div'); b.innerHTML = '<pre>' + a + '</pre>'; b = b.firstChild; g && J(b, g, !0); K({h: d, j: g, c: b, i: 1});
return b.innerHTML; }, prettyPrint: D.prettyPrint = function (a, d) { function g() { for (var b = D.PR_SHOULD_USE_CONTINUATION ? c.now() + 250 : Infinity; i < p.length && c.now() < b; i++) { for (var d = p[i], j = h, k = d; k = k.previousSibling;) { var m = k.nodeType, o = (m === 7 || m === 8) && k.nodeValue; if (o ? !/^\??prettify\b/.test(o) : m !== 3 || /\S/.test(k.nodeValue)) break; if (o) { j = {}; o.replace(/\b(\w+)=([\w%+\-.:]+)/g, function (a, b, c) { j[b] = c; }); break; } }k = d.className; if ((j !== h || e.test(k)) && !v.test(k)) { m = !1; for (o = d.parentNode; o; o = o.parentNode) if (f.test(o.tagName) &&
o.className && e.test(o.className)) { m = !0; break; } if (!m) { d.className += ' prettyprinted'; m = j.lang; if (!m) { var m = k.match(n), y; if (!m && (y = U(d)) && t.test(y.tagName))m = y.className.match(n); m && (m = m[1]); } if (w.test(d.tagName))o = 1; else var o = d.currentStyle, u = s.defaultView, o = (o = o ? o.whiteSpace : u && u.getComputedStyle ? u.getComputedStyle(d, q).getPropertyValue('white-space') : 0) && 'pre' === o.substring(0, 3); u = j.linenums; if (!(u = u === 'true' || +u))u = (u = k.match(/\blinenums\b(?::(\d+))?/)) ? u[1] && u[1].length ? +u[1] : !0 : !1; u && J(d, u, o); r =
{h: m, c: d, j: u, i: o}; K(r); } } }i < p.length ? setTimeout(g, 250) : 'function' === typeof a && a(); } for (var b = d || document.body, s = b.ownerDocument || document, b = [b.getElementsByTagName('pre'), b.getElementsByTagName('code'), b.getElementsByTagName('xmp')], p = [], m = 0; m < b.length; ++m) for (var j = 0, k = b[m].length; j < k; ++j)p.push(b[m][j]); var b = q, c = Date; c.now || (c = {now() { return +new Date; }}); var i = 0, r, n = /\blang(?:uage)?-([\w.]+)(?!\S)/, e = /\bprettyprint\b/, v = /\bprettyprinted\b/, w = /pre|xmp/i, t = /^code$/i, f = /^(?:pre|code|xmp)$/i,
h = {}; g(); }
}; typeof define === 'function' && define.amd && define('google-code-prettify', [], function () { return Y; }); })(); }();

View File

@@ -1,6 +1,6 @@
### Usage
```typescript
import {FileSelectDirective, FileDropDirective, FileUploader} from 'ng2-file-upload/ng2-file-upload';
import { FileSelectDirective, FileDropDirective, FileUploader } from 'ng2-file-upload/ng2-file-upload';
```
### Annotations
@@ -20,10 +20,18 @@ import {FileSelectDirective, FileDropDirective, FileUploader} from 'ng2-file-upl
- `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)
Parameters that supported by this object:
Parameters supported by this object:
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
@@ -36,3 +44,4 @@ import {FileSelectDirective, FileDropDirective, FileUploader} from 'ng2-file-upl
- `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

@@ -0,0 +1,3 @@
export const environment = {
production: true
};

View File

@@ -0,0 +1,8 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `angular-cli.json`.
export const environment = {
production: false
};

BIN
demo/src/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Angular2 File Upload</title>
<title>Angular File Upload</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@@ -12,10 +12,9 @@
<link rel="author" href="https://github.com/valor-software/ng2-file-upload/graphs/contributors">
<!--link to bootstrap.css-->
<link rel="stylesheet" href="assets/css/prism-okaidia.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="assets/css/style.css">
<link rel="stylesheet" href="assets/css/prettify-angulario.css">
<style media="screen">
.header {
background-color: #0143A3;
@@ -33,6 +32,7 @@
<app>
Loading...
</app>
<script src="assets/js/prettify.min.js"></script>
<!-- script files will be inserted by html-webpack-plugin -->
</body>
</html>

12
demo/src/main.ts Normal file
View File

@@ -0,0 +1,12 @@
import './polyfills.ts';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import { AppModule } from './app/';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);

21
demo/src/polyfills.ts Normal file
View File

@@ -0,0 +1,21 @@
// This file includes polyfills needed by Angular 2 and is loaded before
// the app. You can add your own extra polyfills to this file.
import 'ts-helpers';
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/set';
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
import 'classlist-polyfill';

22
demo/src/tsconfig.json Normal file
View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noEmitHelpers": false,
"lib": ["es6", "dom"],
"types": [
"jasmine",
"webpack"
],
"mapRoot": "./",
"module": "es6",
"moduleResolution": "node",
"outDir": "../temp/out-tsc",
"sourceMap": true,
"target": "es5",
"typeRoots": [
"../node_modules/@types"
]
}
}

16
demo/src/typings.d.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
// Typings reference file, you can add your own global typings here
// https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html
// tslint:disable
declare const System: any;
declare const ENV:string;
// google code-prettify
declare const PR:any;
// declare const require:any;
// declare const global:any;
declare module jasmine {
interface Matchers {
toHaveCssClass(expected: any): boolean;
}
}

View File

@@ -1,18 +0,0 @@
'use strict';
const gulp = require('gulp');
const tslint = require('gulp-tslint');
const paths = gulp.paths;
gulp.task('tslint', () =>
gulp
.src(paths.tssrc)
.pipe(tslint())
.pipe(tslint.report('prose', {
emitError: true,
summarizeFailureOutput: true,
reportLimit: 50
}))
);
gulp.task('lint', ['tslint']);

View File

@@ -1,18 +0,0 @@
'use strict';
const gulp = require('gulp');
gulp.paths = {
tssrc: [
'**/*.ts',
'!**/*.d.ts',
'!node_modules/**/*',
'!bundles/**/*',
'!typings/**/*']
};
require('require-dir')('./gulp-tasks');
gulp.task('default', () => {
gulp.start('lint');
});

View File

@@ -1,101 +1,83 @@
'use strict';
// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
const path = require('path');
const cwd = process.cwd();
const customLaunchers = require('./scripts/sauce-browsers').customLaunchers;
module.exports = config => {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
module.exports = function (config) {
const configuration = {
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
{pattern: 'test.bundle.js', watched: false}
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
files: [
{pattern: './scripts/test.ts', watched: false}
],
// list of files to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'test.bundle.js': ['coverage', 'webpack', 'sourcemap']
'./scripts/test.ts': ['@angular/cli']
},
webpack: {
resolve: {
root: [path.resolve(cwd)],
modulesDirectories: ['node_modules', 'demo', 'components', 'test', '.'],
extensions: ['', '.ts', '.js', '.css']
},
module: {
loaders: [
{test: /\.ts$/, loader: 'ts-loader', exclude: [/node_modules/]}
],
postLoaders: [
// instrument only testing sources with Istanbul
{
test: /\.(js|ts)$/,
include: root('components'),
loader: 'istanbul-instrumenter-loader',
exclude: [
/\.e2e\.ts$/,
/node_modules/
]
}
]
},
stats: {
colors: true,
reasons: true
},
watch: true,
debug: true
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: false
},
coverageReporter: {
dir: 'coverage/',
reporters: [
{type: 'text'},
{type: 'json'},
{type: 'html'}
]
angularCli: {
config: './angular-cli.json',
environment: 'dev'
},
webpackServer: {noInfo: true},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['spec', 'coverage'],
// web server port
reporters: config.angularCli && config.angularCli.codeCoverage
? ['dots', 'coverage-istanbul']
: ['dots'],
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR ||
// config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
customLaunchers: {
Chrome_travis_ci: {
base: 'Chrome',
flags: ['--no-sandbox']
}
},
mime: { 'text/x-typescript': ['ts','tsx'] },
client: { captureConsole: true }
};
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
if (process.env.TRAVIS) {
configuration.browsers = ['Chrome_travis_ci'];
}
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['PhantomJS'],
if (process.env.SAUCE) {
if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
console.log('Make sure the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are set.');
process.exit(1);
}
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: true
});
configuration.plugins.push(require('karma-sauce-launcher'));
configuration.reporters.push('saucelabs');
configuration.sauceLabs = {
verbose: true,
testName: 'ng2-bootstrap unit tests',
recordScreenshots: false,
username: process.env.SAUCE_USERNAME,
accessKey: process.env.SAUCE_ACCESS_KEY,
connectOptions: {
port: 5757,
logfile: 'sauce_connect.log'
},
public: 'public'
};
configuration.captureTimeout = 0;
configuration.customLaunchers = customLaunchers();
configuration.browsers = Object.keys(configuration.customLaunchers);
configuration.concurrency = 3;
configuration.browserDisconnectTolerance = 2;
configuration.browserNoActivityTimeout = 20000;
configuration.browserDisconnectTimeout = 5000;
}
config.set(configuration);
};
function root(partialPath) {
return path.join(__dirname, partialPath);
}

View File

@@ -1,14 +0,0 @@
export * from './components/file-upload/file-select.directive';
export * from './components/file-upload/file-drop.directive';
export * from './components/file-upload/file-uploader.class';
import {FileSelectDirective} from './components/file-upload/file-select.directive';
import {FileDropDirective} from './components/file-upload/file-drop.directive';
export const FILE_UPLOAD_DIRECTIVES:[any] = [FileSelectDirective, FileDropDirective];
export default {
directives: [
FILE_UPLOAD_DIRECTIVES
]
};

View File

@@ -1,40 +1,37 @@
{
"name": "ng2-file-upload",
"version": "1.0.3",
"description": "angular2 file upload directives",
"name": "ng2-file-upload-base",
"version": "1.3.0",
"private": true,
"description": "Angular file upload directives",
"scripts": {
"flow.install:typings": "./node_modules/.bin/typings install",
"flow.compile": "npm run flow.install:typings && npm run flow.compile:common && npm run flow.compile:system ",
"flow.compile:common": "./node_modules/.bin/tsc",
"flow.compile:system": "./.config/bundle-system.js",
"flow.copy:src": "./node_modules/.bin/cpy ng2-file-upload.ts \"components/*.ts\" ts --parents",
"flow.clean": "./node_modules/.bin/del bundles coverage demo-build typings \"components/**/*.+(js|d.ts|js.map)\" dist \"ng2-file-upload.+(js|d.ts|js.map)\"",
"flow.deploy:gh-pages": "npm run flow.build:prod && ./node_modules/.bin/gh-pages -d demo-build",
"flow.eslint": "./node_modules/.bin/eslint --ignore-path .gitignore --ext js --fix . .config",
"flow.tslint": "./node_modules/.bin/gulp lint",
"flow.lint": "npm run flow.eslint && npm run flow.tslint",
"flow.changelog": "./node_modules/.bin/conventional-changelog -i CHANGELOG.md -s -p angular -v",
"flow.github-release": "./node_modules/.bin/conventional-github-releaser -p angular",
"flow.build:prod": "NODE_ENV=production ./node_modules/.bin/webpack --progress --color",
"flow.build:dev": "./node_modules/.bin/webpack --progress --color",
"flow.serve:dev": "./node_modules/.bin/webpack-dev-server --hot --inline --colors --display-error-details --display-cached",
"flow.serve:prod": "NODE_ENV=production ./node_modules/.bin/webpack-dev-server --hot --inline --colors --display-error-details --display-cached",
"prepublish": "npm run flow.clean && npm run flow.compile",
"postpublish": "npm run flow.deploy:gh-pages",
"start": "npm run flow.serve:dev",
"pretest": "npm run flow.lint",
"test": "NODE_ENV=test ./node_modules/.bin/karma start",
"preversion": "npm test",
"version": "npm run flow.changelog && git add -A",
"postversion": "git push origin master && git push --tags"
"lite-server": "lite-server -c demo/bs-config.json",
"demo.serve": "run-s build link demo.build lite-server",
"demo.gh-pages": "run-s build demo.build demo.deploy",
"demo.build": "ng build -prod --aot",
"demo.deploy": "gh-pages -d demo/dist",
"link": "ngm link -p src --here",
"lint": "exit 0",
"disable-lint": "tslint \"**/*.ts\" -c tslint.json --fix --type-check -t prose -e \"node_modules/**\" -e \"dist/**\" -e \"temp/**\" -e \"scripts/docs/**\"",
"flow.changelog": "conventional-changelog -i CHANGELOG.md -s -p angular",
"flow.github-release": "conventional-github-releaser -p angular",
"build": "ngm build -p src --clean",
"build.watch": "ngm build -p src --watch --skip-bundles",
"start": "ng serve --aot",
"pretest": "run-s lint build link",
"test": "ng test -sr",
"test-coverage": "ng test -sr -cc",
"version": "npm run flow.changelog && git add -A"
},
"main": "ng2-file-upload.js",
"typings": "ng2-file-upload.d.ts",
"main": "bundles/ng2-file-upload.umd.js",
"module": "index.js",
"typings": "index.d.ts",
"keywords": [
"angular2",
"bootstrap",
"angularjs",
"twitter-bootstrap"
"twitter-bootstrap",
"file-upload",
"angular-file-upload"
],
"author": "Vyacheslav Chub <vyacheslav.chub@valor-software.com>",
"license": "MIT",
@@ -48,68 +45,75 @@
"homepage": "https://github.com/valor-software/ng2-file-upload#readme",
"dependencies": {},
"peerDependencies": {
"@angular/common": "^2.0.0-rc.1",
"@angular/core": "^2.0.0-rc.1"
"@angular/common": "^2.3.1 || >=4.0.0",
"@angular/core": "^2.3.1 || >=4.0.0"
},
"devDependencies": {
"@angular/common": "^2.0.0-rc.1",
"@angular/compiler": "^2.0.0-rc.1",
"@angular/core": "^2.0.0-rc.1",
"@angular/platform-browser": "^2.0.0-rc.1",
"@angular/platform-browser-dynamic": "^2.0.0-rc.1",
"async": "1.5.2",
"bootstrap": "3.3.6",
"@angular/cli": "1.0.0",
"@angular/common": "2.4.3",
"@angular/compiler": "2.4.3",
"@angular/compiler-cli": "2.4.3",
"@angular/core": "2.4.3",
"@angular/forms": "2.4.3",
"@angular/http": "2.4.3",
"@angular/language-service": "2.4.3",
"@angular/platform-browser": "2.4.3",
"@angular/platform-browser-dynamic": "2.4.3",
"@angular/router": "3.4.3",
"@angular/tsc-wrapped": "0.5.1",
"@types/jasmine": "2.5.40",
"@types/marked": "0.0.28",
"@types/node": "7.0.0",
"@types/webpack": "^2.2.1",
"bootstrap": "3.3.7",
"chokidar-cli": "1.2.0",
"classlist-polyfill": "1.0.3",
"codecov": "1.0.1",
"compression-webpack-plugin": "0.3.1",
"codelyzer": "~2.0.0-beta.4",
"conventional-changelog-cli": "1.2.0",
"conventional-github-releaser": "1.1.2",
"copy-webpack-plugin": "2.1.3",
"cpy-cli": "1.0.0",
"del-cli": "0.2.0",
"es6-promise": "3.1.2",
"es6-shim": "0.35.0",
"es7-reflect-metadata": "1.6.0",
"eslint-config-valorsoft": "0.0.11",
"exports-loader": "0.6.3",
"file-loader": "0.8.5",
"gh-pages": "0.11.0",
"gulp": "3.9.1",
"gulp-size": "2.1.0",
"gulp-tslint": "5.0.0",
"html-loader": "0.4.3",
"html-webpack-plugin": "2.16.1",
"istanbul-instrumenter-loader": "0.2.0",
"jasmine": "2.4.1",
"karma": "0.13.22",
"karma-chrome-launcher": "1.0.1",
"karma-coverage": "1.0.0",
"karma-jasmine": "1.0.2",
"karma-phantomjs-launcher": "1.0.0",
"karma-sourcemap-loader": "0.3.7",
"karma-spec-reporter": "0.0.26",
"karma-webpack": "1.7.0",
"lite-server": "2.2.0",
"markdown-loader": "0.1.7",
"marked": "0.3.5",
"ng2-bootstrap": "1.0.16",
"phantomjs-polyfill": "0.0.2",
"phantomjs-prebuilt": "2.1.7",
"pre-commit": "1.1.3",
"prismjs": "1.4.1",
"prismjs-loader": "0.0.3",
"raw-loader": "0.5.1",
"reflect-metadata": "0.1.2",
"require-dir": "0.3.0",
"rxjs": "5.0.0-beta.6",
"source-map-loader": "0.1.5",
"systemjs-builder": "0.15.16",
"ts-loader": "0.8.2",
"tslint-config-valorsoft": "1.0.3",
"typescript": "1.8.10",
"typings": "0.8.1",
"webpack": "1.13.0",
"webpack-dev-server": "1.14.1",
"zone.js": "0.6.12"
"conventional-github-releaser": "1.1.3",
"core-js": "^2.4.1",
"cpy": "5.0.0",
"cpy-cli": "1.0.1",
"del-cli": "0.2.1",
"gh-pages": "0.12.0",
"gitignore-to-glob": "0.3.0",
"google-code-prettify": "1.0.5",
"html-loader": "0.4.4",
"jasmine": "2.5.3",
"jasmine-core": "2.5.2",
"jasmine-data-provider": "2.2.0",
"jasmine-spec-reporter": "3.2.0",
"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",
"lite-server": "2.2.2",
"lodash": "4.17.4",
"markdown-loader": "^0.1.7",
"marked": "0.3.6",
"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",
"reflect-metadata": "0.1.9",
"require-dir": "0.3.1",
"rxjs": "5.0.3",
"systemjs-builder": "0.15.34",
"ts-helpers": "^1.1.1",
"ts-node": "2.0.0",
"tslint": "4.3.1",
"tslint-config-valorsoft": "1.2.0",
"typedoc": "0.5.5",
"typescript": "2.1.5",
"wallaby-webpack": "0.0.30",
"webdriver-manager": "11.1.1",
"zone.js": "0.7.5"
},
"contributors": [
{
@@ -121,6 +125,16 @@
"name": "Dmitriy Shekhovtsov",
"email": "valorkin@gmail.com",
"url": "https://github.com/valorkin"
},
{
"name": "Adrian Faciu",
"email": "adrian.faciu@gmail.com",
"url": "https://github.com/adrianfaciu"
},
{
"name": "Oleksandr Telnov",
"email": "otelnov@gmail.com",
"url": "https://github.com/otelnov"
}
]
}

1
scripts/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
!**/*.js

21
scripts/matchers.ts Normal file
View File

@@ -0,0 +1,21 @@
// tslint:disable
/**
* @copyright Angular ng-bootstrap team
*/
beforeEach(() => {
jasmine.addMatchers({
toHaveCssClass(/*util, customEqualityTests*/) {
return {compare: buildError(false), negativeCompare: buildError(true)};
function buildError(isNot) {
return function (actual, className) {
const orNot = isNot ? 'not ' : '';
return {
pass: actual.classList.contains(className) === !isNot,
message: `Expected ${actual.outerHTML} ${orNot} to contain the CSS class "${className}"`
};
};
}
}
});
});

18
scripts/sauce-browsers.js Normal file
View File

@@ -0,0 +1,18 @@
module.exports.customLaunchers = function customLaunchers() {
return {
sl_chrome: {base: 'SauceLabs', browserName: 'chrome'},
sl_chrome_1: {base: 'SauceLabs', browserName: 'chrome', version: 'latest-1'},
sl_firefox: {base: 'SauceLabs', browserName: 'firefox'},
sl_firefox_1: {base: 'SauceLabs', browserName: 'firefox', version: 'latest-1'},
sl_ie9: {base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 2008', version: '9'},
'SL_IE10': {base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 2012', version: '10'},
'SL_IE11': {base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11'},
'SL_EDGE': {base: 'SauceLabs', browserName: 'MicrosoftEdge', platform: 'Windows 10', version: '13.10586'},
'SL_IOS9': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '9.3'},
'SL_IOS10': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '10.0'},
'SL_ANDROID4.4': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.4'},
'SL_ANDROID5': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '5.1'},
'SL_SAFARI9': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.11', version: '9.0'}
};
};

37
scripts/test.ts Normal file
View File

@@ -0,0 +1,37 @@
import '../demo/src/polyfills.ts';
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
import './matchers';
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare var __karma__: any;
declare var require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = Function.prototype;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
let context = require.context('../demo/src', true, /\.spec\.ts/);
// And load the modules.
context.keys().map(context);
let context2 = require.context('../src/spec', true, /\.spec\.ts/);
context2.keys().map(context2);
// Finally, start Karma to run the tests.
__karma__.start();

17
scripts/typings.d.ts vendored Normal file
View File

@@ -0,0 +1,17 @@
// Typings reference file, you can add your own global typings here
// https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html
// tslint:disable
declare const System: any;
declare const ENV:string;
// google code-prettify
declare const PR:any;
// declare const global:any;
declare module jasmine {
interface Matchers {
toHaveCssClass(expected: any): boolean;
}
}

View File

@@ -1,28 +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();
@Input() public uploader: FileUploader;
@Output() public fileOver: EventEmitter<any> = new EventEmitter();
@Output() public onFileDrop: EventEmitter<File[]> = new EventEmitter<File[]>();
private element:ElementRef;
public constructor(element:ElementRef) {
protected 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;
@@ -36,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;
@@ -48,26 +49,28 @@ export class FileDropDirective {
this.fileOver.emit(true);
}
@HostListener('dragleave', ['$event'])
public onDragLeave(event:any):any {
if (event.currentTarget === (this as any).element[0]) {
return;
@HostListener('dragleave', [ '$event' ])
public onDragLeave(event: any): any {
if ((this as any).element) {
if (event.currentTarget === (this as any).element[ 0 ]) {
return;
}
}
this._preventAndStop(event);
this.fileOver.emit(false);
}
private _getTransfer(event:any):any {
protected _getTransfer(event: any): any {
return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix;
}
private _preventAndStop(event:any):any {
protected _preventAndStop(event: any): any {
event.preventDefault();
event.stopPropagation();
}
private _haveFiles(types:any):any {
protected _haveFiles(types: any): any {
if (!types) {
return false;
}
@@ -80,12 +83,4 @@ export class FileDropDirective {
return false;
}
}
/*
_addOverClass(item:any):any {
item.addOverClass();
}
_removeOverClass(item:any):any {
item.removeOverClass();
}*/
}

View File

@@ -0,0 +1,154 @@
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;
protected uploader: FileUploader;
protected some: File;
protected options: FileUploaderOptions;
public constructor(uploader: FileUploader, some: File, options: FileUploaderOptions) {
this.uploader = uploader;
this.some = some;
this.options = options;
this.file = new FileLikeObject(some);
this._file = some;
if (uploader.options) {
this.method = uploader.options.method || 'POST';
this.alias = uploader.options.itemAlias || 'file';
}
this.url = uploader.options.url;
}
public upload(): void {
try {
this.uploader.uploadItem(this);
} catch (e) {
this.uploader._onCompleteItem(this, '', 0, {});
this.uploader._onErrorItem(this, '', 0, {});
}
}
public cancel(): void {
this.uploader.cancelItem(this);
}
public remove(): void {
this.uploader.removeFromQueue(this);
}
public onBeforeUpload(): void {
return void 0;
}
public onBuildForm(form: any): any {
return { form };
}
public onProgress(progress: number): any {
return { progress };
}
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 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 _onBeforeUpload(): void {
this.isReady = true;
this.isUploading = true;
this.isUploaded = false;
this.isSuccess = false;
this.isCancel = false;
this.isError = false;
this.progress = 0;
this.onBeforeUpload();
}
public _onBuildForm(form: any): void {
this.onBuildForm(form);
}
public _onProgress(progress: number): void {
this.progress = progress;
this.onProgress(progress);
}
public _onSuccess(response: string, status: number, headers: ParsedResponseHeaders): void {
this.isReady = false;
this.isUploading = false;
this.isUploaded = true;
this.isSuccess = true;
this.isCancel = false;
this.isError = false;
this.progress = 100;
this.index = void 0;
this.onSuccess(response, status, headers);
}
public _onError(response: string, status: number, headers: ParsedResponseHeaders): void {
this.isReady = false;
this.isUploading = false;
this.isUploaded = true;
this.isSuccess = false;
this.isCancel = false;
this.isError = true;
this.progress = 0;
this.index = void 0;
this.onError(response, status, headers);
}
public _onCancel(response: string, status: number, headers: ParsedResponseHeaders): void {
this.isReady = false;
this.isUploading = false;
this.isUploaded = false;
this.isSuccess = false;
this.isCancel = true;
this.isError = false;
this.progress = 0;
this.index = void 0;
this.onCancel(response, status, headers);
}
public _onComplete(response: string, status: number, headers: ParsedResponseHeaders): void {
this.onComplete(response, status, headers);
if (this.uploader.options.removeAfterUpload) {
this.remove();
}
}
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

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

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',
@@ -93,6 +100,7 @@ export class FileType {
'tiff': 'image',
'cr2': 'image',
'dwg': 'image',
'dwf': 'image',
'cdr': 'image',
'ai': 'image',
'indd': 'image',
@@ -107,10 +115,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 +155,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

@@ -0,0 +1,13 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FileDropDirective } from './file-drop.directive';
import { FileSelectDirective } from './file-select.directive';
@NgModule({
imports: [ CommonModule ],
declarations: [ FileDropDirective, FileSelectDirective ],
exports: [ FileDropDirective, FileSelectDirective ]
})
export class FileUploadModule {
}

View File

@@ -0,0 +1,498 @@
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 {
return (File && value instanceof File);
}
export interface Headers {
name: string;
value: string;
}
export type ParsedResponseHeaders = { [ headerFieldName: string ]: string };
export type FilterFunction = {
name: string,
fn: (item?: FileLikeObject, options?: FileUploaderOptions) => boolean
};
export interface FileUploaderOptions {
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 };
parametersBeforeFiles?: boolean;
formatDataFunction?: Function;
formatDataFunctionIsAsync?: boolean;
}
export class FileUploader {
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 = {
autoUpload: false,
isHTML5: true,
filters: [],
removeAfterUpload: false,
disableMultipart: false,
formatDataFunction: (item: FileItem) => item._file,
formatDataFunctionIsAsync: false
};
protected _failFilterIndex: number;
public constructor(options: FileUploaderOptions) {
this.setOptions(options);
this.response = new EventEmitter<any>();
}
public setOptions(options: FileUploaderOptions): void {
this.options = Object.assign(this.options, options);
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 });
}
if (this.options.allowedFileType) {
this.options.filters.unshift({ name: 'fileType', fn: this._fileTypeFilter });
}
if (this.options.allowedMimeType) {
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;
}
}
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) => {
if (!options) {
options = this.options;
}
let temp = new FileLikeObject(some);
if (this._isValidFile(temp, arrayOfFilters, options)) {
let fileItem = new FileItem(this, some, options);
addedFileItems.push(fileItem);
this.queue.push(fileItem);
this._onAfterAddingFile(fileItem);
} else {
let filter = arrayOfFilters[ this._failFilterIndex ];
this._onWhenAddingFileFailed(temp, filter, options);
}
});
if (this.queue.length !== count) {
this._onAfterAddingAll(addedFileItems);
this.progress = this._getTotalProgress();
}
this._render();
if (this.options.autoUpload) {
this.uploadAll();
}
}
public removeFromQueue(value: FileItem): void {
let index = this.getIndexOfItem(value);
let item = this.queue[ index ];
if (item.isUploading) {
item.cancel();
}
this.queue.splice(index, 1);
this.progress = this._getTotalProgress();
}
public clearQueue(): void {
while (this.queue.length) {
this.queue[ 0 ].remove();
}
this.progress = 0;
}
public uploadItem(value: FileItem): void {
let index = this.getIndexOfItem(value);
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);
}
public cancelItem(value: FileItem): void {
let index = this.getIndexOfItem(value);
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);
if (!items.length) {
return;
}
items.map((item: FileItem) => item._prepareToUploading());
items[ 0 ].upload();
}
public cancelAll(): void {
let items = this.getNotUploadedItems();
items.map((item: FileItem) => item.cancel());
}
public isFile(value: any): boolean {
return isFile(value);
}
public isFileLikeObject(value: any): boolean {
return value instanceof FileLikeObject;
}
public getIndexOfItem(value: any): number {
return typeof value === 'number' ? value : this.queue.indexOf(value);
}
public getNotUploadedItems(): any[] {
return this.queue.filter((item: FileItem) => !item.isUploaded);
}
public getReadyItems(): any[] {
return this.queue
.filter((item: FileItem) => (item.isReady && !item.isUploading))
.sort((item1: any, item2: any) => item1.index - item2.index);
}
public destroy(): void {
return void 0;
}
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 {
return !(this.options.maxFileSize && item.size > this.options.maxFileSize);
}
public _fileTypeFilter(item: FileLikeObject): boolean {
return !(this.options.allowedFileType &&
this.options.allowedFileType.indexOf(FileType.getMimeClass(item)) === -1);
}
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 {
item._onComplete(response, status, headers);
this.onCompleteItem(item, response, status, headers);
let nextItem = this.getReadyItems()[ 0 ];
this.isUploading = false;
if (nextItem) {
nextItem.upload();
return;
}
this.onCompleteAll();
this.progress = this._getTotalProgress();
this._render();
}
protected _headersGetter(parsedHeaders: ParsedResponseHeaders): any {
return (name: any): any => {
if (name) {
return parsedHeaders[ name.toLowerCase() ] || void 0;
}
return parsedHeaders;
};
}
protected _xhrTransport(item: FileItem): any {
let that = this;
let xhr = item._xhr = new XMLHttpRequest();
let sendable: any;
this._onBeforeUploadItem(item);
if (typeof item._file.size !== 'number') {
throw new TypeError('The file specified is no longer valid');
}
if (!this.options.disableMultipart) {
sendable = new FormData();
this._onBuildItemForm(item, sendable);
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) => {
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 = this.options.formatDataFunction(item);
}
xhr.upload.onprogress = (event: any) => {
let progress = Math.round(event.lengthComputable ? event.loaded * 100 / event.total : 0);
this._onProgressItem(item, progress);
};
xhr.onload = () => {
let headers = this._parseHeaders(xhr.getAllResponseHeaders());
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._onCompleteItem(item, response, xhr.status, headers);
};
xhr.onerror = () => {
let headers = this._parseHeaders(xhr.getAllResponseHeaders());
let response = this._transformResponse(xhr.response, headers);
this._onErrorItem(item, response, xhr.status, headers);
this._onCompleteItem(item, response, xhr.status, headers);
};
xhr.onabort = () => {
let headers = this._parseHeaders(xhr.getAllResponseHeaders());
let response = this._transformResponse(xhr.response, headers);
this._onCancelItem(item, response, xhr.status, headers);
this._onCompleteItem(item, response, xhr.status, headers);
};
xhr.open(item.method, item.url, true);
xhr.withCredentials = item.withCredentials;
if (this.options.headers) {
for (let header of this.options.headers) {
xhr.setRequestHeader(header.name, header.value);
}
}
if (item.headers.length) {
for (let header of item.headers) {
xhr.setRequestHeader(header.name, header.value);
}
}
if (this.authToken) {
xhr.setRequestHeader(this.authTokenHeader, this.authToken);
}
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 {
if (this.options.removeAfterUpload) {
return value;
}
let notUploaded = this.getNotUploadedItems().length;
let uploaded = notUploaded ? this.queue.length - notUploaded : this.queue.length;
let ratio = 100 / this.queue.length;
let current = value * ratio / 100;
return Math.round(uploaded * ratio + current);
}
protected _getFilters(filters: FilterFunction[] | string): FilterFunction[] {
if (!filters) {
return this.options.filters;
}
if (Array.isArray(filters)) {
return filters;
}
if (typeof filters === 'string') {
let names = filters.match(/[^\s,]+/g);
return this.options.filters
.filter((filter: any) => names.indexOf(filter.name) !== -1);
}
return this.options.filters;
}
protected _render(): any {
return void 0;
}
protected _queueLimitFilter(): boolean {
return this.options.queueLimit === undefined || this.queue.length < this.options.queueLimit;
}
protected _isValidFile(file: FileLikeObject, filters: FilterFunction[], options: FileUploaderOptions): boolean {
this._failFilterIndex = -1;
return !filters.length ? true : filters.every((filter: FilterFunction) => {
this._failFilterIndex++;
return filter.fn.call(this, file, options);
});
}
protected _isSuccessCode(status: number): boolean {
return (status >= 200 && status < 300) || status === 304;
}
protected _transformResponse(response: string, headers: ParsedResponseHeaders): string {
return response;
}
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) => {
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;
}
});
return parsed;
}
protected _onWhenAddingFileFailed(item: FileLikeObject, filter: any, options: any): void {
this.onWhenAddingFileFailed(item, filter, options);
}
protected _onAfterAddingFile(item: FileItem): void {
this.onAfterAddingFile(item);
}
protected _onAfterAddingAll(items: any): void {
this.onAfterAddingAll(items);
}
protected _onBeforeUploadItem(item: FileItem): void {
item._onBeforeUpload();
this.onBeforeUploadItem(item);
}
protected _onBuildItemForm(item: FileItem, form: any): void {
item._onBuildForm(form);
this.onBuildItemForm(item, form);
}
protected _onProgressItem(item: FileItem, progress: any): void {
let total = this._getTotalProgress(progress);
this.progress = total;
item._onProgress(progress);
this.onProgressItem(item, progress);
this.onProgressAll(total);
this._render();
}
protected _onSuccessItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
item._onSuccess(response, status, headers);
this.onSuccessItem(item, response, status, headers);
}
protected _onCancelItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
item._onCancel(response, status, headers);
this.onCancelItem(item, response, status, headers);
}
}

7
src/index.ts Normal file
View File

@@ -0,0 +1,7 @@
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';

1
src/ng2-file-upload.ts Normal file
View File

@@ -0,0 +1 @@
export * from './index';

8
src/package.json Normal file
View File

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

View File

@@ -0,0 +1,147 @@
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: `<div type="file"
ng2FileDrop
[uploader]="uploader"
></div>`
})
export class ContainerComponent {
public get url(): string { return 'localhost:3000'; }
public uploader: FileUploader = new FileUploader({ url: this.url });
}
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 ]
});
});
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);
});
});

37
src/tsconfig.json Normal file
View File

@@ -0,0 +1,37 @@
{
"compilerOptions": {
"outDir": "../dist",
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": false,
"noEmitHelpers": false,
"noImplicitAny": true,
"declaration": true,
"skipLibCheck": true,
"stripInternal": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"lib": ["dom", "es6"],
"types": [
"jasmine",
"webpack"
],
"typeRoots": [
"../node_modules/@types"
]
},
"exclude": [
"node_modules"
],
"files": [
"../scripts/typings.d.ts",
"./ng2-file-upload.ts",
"./index.ts"
],
"angularCompilerOptions": {
"genDir": "../temp/factories"
}
}

View File

@@ -1,47 +0,0 @@
'use strict';
/* eslint vars-on-top:0 no-var:0 */
// @AngularClass
/*
* When testing with webpack and ES6, we have to do some extra
* things get testing to work right. Because we are gonna write test
* in ES6 to, we have to compile those as well. That's handled in
* karma.conf.js with the karma-webpack plugin. This is the entry
* file for webpack test. Just like webpack will create a bundle.js
* file for our client, when we run test, it well compile and bundle them
* all here! Crazy huh. So we need to do some setup
*/
Error.stackTraceLimit = Infinity;
require('phantomjs-polyfill');
require('es6-promise');
require('es6-shim');
require('es7-reflect-metadata/dist/browser');
// require('zone.js');
require('zone.js/dist/zone.js');
require('zone.js/dist/long-stack-trace-zone.js');
require('zone.js/dist/jasmine-patch.js');
require('zone.js/dist/async-test.js');
var testing = require('@angular/core/testing');
var browser = require('@angular/platform-browser-dynamic/testing');
testing.setBaseTestProviders(
browser.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
browser.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);
/*
Ok, this is kinda crazy. We can use the the context method on
require that webpack created in order to tell webpack
what files we actually want to require or import.
Below, context will be an function/object with file names as keys.
using that regex we are saying look in ./src/app and ./test then find
any file that ends with spec.js and get its path. By passing in true
we say do this recursively
*/
var testContext = require.context('./components', true, /\.spec\.ts/);
// get all the files, for each file, call the context function
// that will require the file and load it up here. Context will
// loop and require those spec files here
testContext.keys().forEach(testContext);

View File

@@ -1,22 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": false,
"declaration": true,
"removeComments": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": true,
"listFiles": false,
"noLib": false
},
"exclude": [
"node_modules"
],
"files": [
"./typings/browser.d.ts",
"./ng2-file-upload.ts"
]
}

View File

@@ -1,4 +1,12 @@
{
"extends": "tslint-config-valorsoft",
"rulesDirectory": "./node_modules/codelyzer"
"rulesDirectory": "./node_modules/codelyzer",
"rules": {
"no-forward-ref": false,
"no-null-keyword": false,
"only-arrow-functions": false,
"no-access-missing-member": false,
"directive-selector": false,
"component-selector": false
}
}

View File

@@ -1,12 +0,0 @@
{
"dependencies": {
"moment": "registry:npm/moment#2.10.5+20160211003958",
"webpack": "registry:npm/webpack#1.12.9+20160219013405"
},
"devDependencies": {},
"ambientDependencies": {
"es6-shim": "registry:dt/es6-shim#0.31.2+20160317120654",
"jasmine": "registry:dt/jasmine#2.2.0+20160317120654",
"require": "registry:dt/require#2.1.20+20160316155526"
}
}

View File

@@ -1,178 +0,0 @@
/* eslint global-require: 0 */
'use strict';
const path = require('path');
const marked = require('marked');
const webpack = require('webpack');
const reqPrism = require('prismjs');
const CompressionPlugin = require('compression-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// marked renderer hack
marked.Renderer.prototype.code = function renderCode(code, lang) {
const out = this.options.highlight(code, lang);
const classMap = this.options.langPrefix + lang;
if (!lang) {
return `<pre><code>${out}\n</code></pre>`;
}
return `<pre class="${classMap}"><code class="${classMap}">${out}\n</code></pre>\n`;
};
/*eslint no-process-env:0, camelcase:0*/
const isProduction = (process.env.NODE_ENV || 'development') === 'production';
const devtool = process.env.NODE_ENV === 'test' ? 'inline-source-map' : 'source-map';
const dest = 'demo-build';
const absDest = root(dest);
const config = {
// isProduction ? 'source-map' : 'evale',
devtool,
debug: false,
verbose: true,
displayErrorDetails: true,
context: __dirname,
stats: {
colors: true,
reasons: true
},
resolve: {
cache: false,
root: __dirname,
extensions: ['', '.ts', '.js', '.json']
},
entry: {
angular2: [
// Angular 2 Deps
'es6-shim',
'es6-promise',
'zone.js',
'reflect-metadata',
'@angular/common',
'@angular/core'
],
'angular2-bootstrap': ['ng2-file-upload'],
'angular2-bootstrap-demo': 'demo'
},
output: {
path: absDest,
filename: '[name].js',
sourceMapFilename: '[name].js.map',
chunkFilename: '[id].chunk.js'
},
// our Development Server configs
devServer: {
inline: true,
colors: true,
historyApiFallback: true,
contentBase: dest,
//publicPath: dest,
outputPath: dest,
watchOptions: {aggregateTimeout: 300, poll: 1000}
},
markdownLoader: {
langPrefix: 'language-',
highlight(code, lang) {
const language = !lang || lang === 'html' ? 'markup' : lang;
const Prism = global.Prism || reqPrism;
if (!Prism.languages[language]) {
require(`prismjs/components/prism-${language}.js`);
}
return Prism.highlight(code, Prism.languages[language]);
}
},
module: {
loaders: [
// support markdown
{test: /\.md$/, loader: 'html?minimize=false!markdown'},
// Support for *.json files.
{test: /\.json$/, loader: 'json'},
// Support for CSS as raw text
{test: /\.css$/, loader: 'raw'},
// support for .html as raw text
{test: /\.html$/, loader: 'raw'},
// Support for .ts files.
{
test: /\.ts$/,
loader: 'ts',
query: {
compilerOptions: {
removeComments: true,
noEmitHelpers: false
}
},
exclude: [/\.(spec|e2e)\.ts$/]
}
],
noParse: [
/rtts_assert\/src\/rtts_assert/,
/reflect-metadata/,
/zone\.js\/dist\/zone-microtask/
]
},
plugins: [
//new Clean([dest]),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(true),
new webpack.optimize.CommonsChunkPlugin({
name: 'angular2',
minChunks: Infinity,
filename: 'angular2.js'
}),
// static assets
new CopyWebpackPlugin([{from: 'demo/favicon.ico', to: 'favicon.ico'}]),
new CopyWebpackPlugin([{from: 'demo/assets', to: 'assets'}]),
// generating html
new HtmlWebpackPlugin({template: 'demo/index.html'})
],
pushPlugins() {
if (!isProduction) {
return;
}
const plugins = [
//production only
new webpack.optimize.UglifyJsPlugin({
beautify: false,
mangle: false,
comments: false,
compress: {
screw_ie8: true
//warnings: false,
//drop_debugger: false
}
//verbose: true,
//beautify: false,
//quote_style: 3
}),
new CompressionPlugin({
asset: '{file}.gz',
algorithm: 'gzip',
regExp: /\.js$|\.html|\.css|.map$/,
threshold: 10240,
minRatio: 0.8
})
];
this
.plugins
.push
.apply(plugins);
}
};
config.pushPlugins();
module.exports = config;
function root(partialPath) {
return path.join(__dirname, partialPath);
}