├── .eslintignore ├── .firebaserc ├── libs └── ng2-file-upload │ ├── testing │ ├── test-setup.ts │ └── spec │ │ ├── file-select.directive.spec.ts │ │ ├── file-drop.directive.spec.ts │ │ └── file-uploader.class.spec.ts │ ├── ng-package.json │ ├── tsconfig.lib.prod.json │ ├── tsconfig.spec.json │ ├── index.ts │ ├── file-upload │ ├── file-upload.module.ts │ ├── file-like-object.class.ts │ ├── file-select.directive.ts │ ├── file-drop.directive.ts │ ├── file-item.class.ts │ ├── file-type.class.ts │ └── file-uploader.class.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ ├── jest.config.ts │ ├── package.json │ ├── .eslintrc.json │ ├── project.json │ └── README.md ├── apps └── demo │ ├── .gitignore │ ├── src │ ├── app │ │ ├── index.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── file-upload-section.ts │ │ │ ├── file-upload │ │ │ │ ├── file-catcher.js │ │ │ │ ├── simple-demo.ts │ │ │ │ └── simple-demo.html │ │ │ └── file-upload-section.html │ │ └── app.component.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── assets │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── css │ │ │ ├── prettify-angulario.css │ │ │ ├── style.css │ │ │ └── glyphicons.css │ │ └── js │ │ │ └── prettify.min.js │ ├── getting-started.md │ ├── main.ts │ ├── polyfills.ts │ ├── typings.d.ts │ ├── index.html │ └── doc.md │ ├── bs-config.json │ ├── server │ ├── uploads │ │ └── unnamed1719848822817.jpg │ └── file-catcher.js │ ├── tsconfig.editor.json │ ├── browserslist │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── .eslintrc.json │ └── project.json ├── jest.config.ts ├── .editorconfig ├── firebase.json ├── scripts └── set-version.ts ├── tsconfig.base.json ├── jest.preset.js ├── .gitignore ├── .github └── workflows │ ├── on-gh-release.yml │ ├── on-push-or-pull.yml │ └── on-publish.yml ├── LICENSE ├── .eslintrc.json ├── nx.json ├── package.json ├── README.md └── CHANGELOG.md /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "ngx-file-upload" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/testing/test-setup.ts: -------------------------------------------------------------------------------- 1 | import 'jest-preset-angular/setup-jest'; 2 | -------------------------------------------------------------------------------- /apps/demo/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | src/api-doc.json 3 | -------------------------------------------------------------------------------- /apps/demo/src/app/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app.component'; 2 | export * from './app.module'; 3 | -------------------------------------------------------------------------------- /apps/demo/bs-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": 4200, 3 | "server": { "baseDir": "./dist/apps/demo" } 4 | } 5 | -------------------------------------------------------------------------------- /apps/demo/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /apps/demo/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valor-software/ng2-file-upload/HEAD/apps/demo/src/favicon.ico -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | const { getJestProjects } = require('@nx/jest'); 2 | 3 | export default {"projects": getJestProjects()}; 4 | -------------------------------------------------------------------------------- /apps/demo/server/uploads/unnamed1719848822817.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valor-software/ng2-file-upload/HEAD/apps/demo/server/uploads/unnamed1719848822817.jpg -------------------------------------------------------------------------------- /apps/demo/tsconfig.editor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*.ts"], 4 | "compilerOptions": { 5 | "types": ["jest", "node"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /apps/demo/src/assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valor-software/ng2-file-upload/HEAD/apps/demo/src/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /apps/demo/src/assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valor-software/ng2-file-upload/HEAD/apps/demo/src/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /apps/demo/src/assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valor-software/ng2-file-upload/HEAD/apps/demo/src/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /apps/demo/src/assets/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/valor-software/ng2-file-upload/HEAD/apps/demo/src/assets/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /apps/demo/src/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | ## First of all, Welcome! 4 | 5 | ### Install 6 | 7 | Install the components 8 | ``` 9 | npm install ng2-file-upload --save 10 | ``` 11 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/libs/ng2-file-upload/", 4 | "lib": { 5 | "entryFile": "index.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "./dist/apps/demo/", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false, 5 | "target": "ES2022", 6 | "useDefineForClassFields": false, 7 | "moduleResolution": "bundler" 8 | }, 9 | "angularCompilerOptions": { 10 | "compilationMode": "partial" 11 | }, 12 | "exclude": [ 13 | "jest.config.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /apps/demo/src/main.ts: -------------------------------------------------------------------------------- 1 | import './polyfills'; 2 | 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | import { enableProdMode } from '@angular/core'; 5 | import { environment } from './environments/environment'; 6 | import { AppModule } from './app/'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic().bootstrapModule(AppModule); 13 | -------------------------------------------------------------------------------- /apps/demo/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | * Zone JS is required by default for Angular itself. 3 | */ 4 | import 'zone.js'; // Included with Angular CLI. 5 | 6 | /*************************************************************************************************** 7 | * APPLICATION IMPORTS 8 | */ 9 | 10 | (window as any)['global'] = window; 11 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": [ 7 | "jest", 8 | "node" 9 | ] 10 | }, 11 | "files": [ 12 | "testing/test-setup.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.test.ts", 17 | "**/*.d.ts", 18 | "jest.config.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /apps/demo/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/index.ts: -------------------------------------------------------------------------------- 1 | export * from './file-upload/file-drop.directive'; 2 | export * from './file-upload/file-uploader.class'; 3 | export * from './file-upload/file-item.class'; 4 | export * from './file-upload/file-like-object.class'; 5 | export * from './file-upload/file-like-object.class'; 6 | 7 | export { FileUploadModule } from './file-upload/file-upload.module'; 8 | export { FileSelectDirective } from './file-upload/file-select.directive'; 9 | -------------------------------------------------------------------------------- /apps/demo/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /scripts/set-version.ts: -------------------------------------------------------------------------------- 1 | import { readJson, writeJson } from 'fs-extra'; 2 | 3 | const libPackage = './libs/ng2-file-upload/package.json'; 4 | const mainPackage = './package.json'; 5 | 6 | (async () => { 7 | const version = await readJson(mainPackage).then(json => json.version); 8 | const packageJson = await readJson(libPackage); 9 | if (packageJson.version) { 10 | packageJson.version = version; 11 | } 12 | await writeJson(libPackage, packageJson, { spaces: 2 }); 13 | })(); 14 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/file-upload/file-upload.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { FileDropDirective } from './file-drop.directive'; 5 | import { FileSelectDirective } from './file-select.directive'; 6 | 7 | @NgModule({ 8 | imports: [ CommonModule ], 9 | declarations: [ FileDropDirective, FileSelectDirective ], 10 | exports: [ FileDropDirective, FileSelectDirective ] 11 | }) 12 | export class FileUploadModule { 13 | } 14 | -------------------------------------------------------------------------------- /apps/demo/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"], 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "noImplicitReturns": true, 9 | "noFallthroughCasesInSwitch": true 10 | }, 11 | "angularCompilerOptions": { 12 | "strictInjectionParameters": true, 13 | "strictTemplates": true, 14 | "fullTemplateTypeCheck": true 15 | }, 16 | "files": ["src/main.ts"] 17 | } 18 | -------------------------------------------------------------------------------- /apps/demo/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | // Typings reference file, you can add your own global typings here 2 | // https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html 3 | 4 | // tslint:disable 5 | 6 | declare const System: any; 7 | declare const ENV:string; 8 | // google code-prettify 9 | declare const PR:any; 10 | 11 | // declare const global:any; 12 | // eslint-disable-next-line @typescript-eslint/prefer-namespace-keyword 13 | declare module jasmine { 14 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 15 | interface Matchers { 16 | toHaveCssClass(expected: any): boolean; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /apps/demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [ 4 | "./src/main.ts", 5 | "./src/polyfills.ts" 6 | ], 7 | "include": [ 8 | "./src/typings.d.ts" 9 | ], 10 | "references": [ 11 | { 12 | "path": "./tsconfig.app.json" 13 | }, 14 | { 15 | "path": "./tsconfig.spec.json" 16 | }, 17 | { 18 | "path": "./tsconfig.editor.json" 19 | } 20 | ], 21 | "exclude": [ 22 | "**/*.spec.ts" 23 | ], 24 | "compilerOptions": { 25 | "target": "ES2022", 26 | "useDefineForClassFields": false, 27 | "moduleResolution": "bundler" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "lib": [ 14 | "es2017", 15 | "dom" 16 | ], 17 | "skipLibCheck": true, 18 | "skipDefaultLibCheck": true, 19 | "baseUrl": ".", 20 | "paths": { 21 | "ng2-file-upload": [ 22 | "libs/ng2-file-upload/index.ts" 23 | ] 24 | } 25 | }, 26 | "exclude": [] 27 | } 28 | -------------------------------------------------------------------------------- /apps/demo/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "../../.eslintrc.json" 4 | ], 5 | "ignorePatterns": [ 6 | "!**/*" 7 | ], 8 | "overrides": [ 9 | { 10 | "files": [ 11 | "*.ts" 12 | ], 13 | "extends": [ 14 | "plugin:@nx/angular", 15 | "plugin:@angular-eslint/template/process-inline-templates" 16 | ], 17 | "rules": { 18 | "@angular-eslint/prefer-standalone": [ 19 | "off" 20 | ] 21 | } 22 | }, 23 | { 24 | "files": [ 25 | "*.html" 26 | ], 27 | "extends": [ 28 | "plugin:@nx/angular-template" 29 | ], 30 | "rules": {} 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.lib.prod.json" 11 | }, 12 | { 13 | "path": "./tsconfig.spec.json" 14 | } 15 | ], 16 | "compilerOptions": { 17 | "forceConsistentCasingInFileNames": true, 18 | "strict": true, 19 | "noImplicitReturns": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "target": "es2020" 22 | }, 23 | "angularCompilerOptions": { 24 | "strictInjectionParameters": true, 25 | "strictTemplates": true, 26 | "fullTemplateTypeCheck": true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "target": "ES2022", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "inlineSources": true, 9 | "types": [], 10 | "lib": [ 11 | "dom", 12 | "es2018" 13 | ], 14 | "useDefineForClassFields": false, 15 | "moduleResolution": "bundler" 16 | }, 17 | "angularCompilerOptions": { 18 | "skipTemplateCodegen": true, 19 | "strictMetadataEmit": true, 20 | "enableResourceInlining": true 21 | }, 22 | "include": [ 23 | "**/*.ts" 24 | ], 25 | "exclude": [ 26 | "**/*.spec.ts", 27 | "**/*.test.ts", 28 | "jest.config.ts" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | module.exports = { 3 | ...nxPreset, 4 | ...{ 5 | coverageReporters: ['text-summary', 'json', 'lcov'] 6 | }, 7 | /* TODO: Update to latest Jest snapshotFormat 8 | * By default Nx has kept the older style of Jest Snapshot formats 9 | * to prevent breaking of any existing tests with snapshots. 10 | * It's recommend you update to the latest format. 11 | * You can do this by removing snapshotFormat property 12 | * and running tests with --update-snapshot flag. 13 | * Example: "nx affected --targets=test --update-snapshot" 14 | * More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format 15 | */ 16 | snapshotFormat: { escapeString: true, printBasicPrototype: true } 17 | } 18 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'ng2-file-upload', 4 | preset: '../../jest.preset.js', 5 | setupFilesAfterEnv: ['/testing/test-setup.ts'], 6 | globals: { }, 7 | coverageDirectory: '../../coverage/libs/ng2-file-upload', 8 | snapshotSerializers: [ 9 | 'jest-preset-angular/build/serializers/no-ng-attributes', 10 | 'jest-preset-angular/build/serializers/ng-snapshot', 11 | 'jest-preset-angular/build/serializers/html-comment' 12 | ], 13 | transform: { '^.+.(ts|mjs|js|html)$': ['jest-preset-angular', { 14 | tsconfig: '/tsconfig.spec.json', 15 | 16 | }] }, 17 | transformIgnorePatterns: ['node_modules/(?!.*.mjs$)'], 18 | moduleFileExtensions: ['mjs', 'ts', 'js', 'html'] 19 | }; 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependency directory 2 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 3 | /node_modules 4 | /bower_components 5 | 6 | # IDEs and editors 7 | /.idea 8 | /.vscode 9 | .project 10 | .classpath 11 | *.launch 12 | .settings/ 13 | 14 | # misc 15 | /.angular/cache 16 | /.sass-cache 17 | /connect.lock 18 | /coverage 19 | /libpeerconnection.log 20 | npm-debug.log 21 | 22 | # ignore build and dist for now 23 | /dist 24 | /temp 25 | /demo/dist 26 | /demo/temp 27 | /logs 28 | 29 | #System Files 30 | .DS_Store 31 | Thumbs.db 32 | 33 | 34 | /demo/e2e/*.js 35 | /demo/e2e/*.map 36 | src/**/*.js 37 | src/**/*.map 38 | scripts/**/*.js 39 | scripts/**/*.map 40 | 41 | .nx/ 42 | .yarn 43 | .nx/ 44 | .cursor/rules/nx-rules.mdc 45 | .github/instructions/nx.instructions.md 46 | -------------------------------------------------------------------------------- /apps/demo/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | 6 | import { TabsModule } from 'ngx-bootstrap/tabs'; 7 | import { FileUploadModule } from 'ng2-file-upload'; 8 | 9 | import { AppComponent } from './app.component'; 10 | import { FileUploadSectionComponent } from './components/file-upload-section'; 11 | import { SimpleDemoComponent } from './components/file-upload/simple-demo'; 12 | 13 | @NgModule({ 14 | imports: [BrowserModule, CommonModule, FileUploadModule, TabsModule.forRoot(), FormsModule], 15 | declarations: [AppComponent, FileUploadSectionComponent, SimpleDemoComponent], 16 | bootstrap: [AppComponent] 17 | }) 18 | export class AppModule { 19 | } 20 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-file-upload", 3 | "version": "9.0.0", 4 | "description": "Angular file uploader", 5 | "author": "Dmitriy Shekhovtsov ", 6 | "license": "MIT", 7 | "peerDependencies": { 8 | "@angular/core": "^20.0.0", 9 | "@angular/common": "^20.0.0" 10 | }, 11 | "sideEffects": false, 12 | "publishConfig": { 13 | "registry": "https://registry.npmjs.org/", 14 | "tag": "next" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git+ssh://git@github.com/valor-software/ng2-file-upload.git" 19 | }, 20 | "bugs": { 21 | "url": "https://github.com/valor-software/ng2-file-upload/issues" 22 | }, 23 | "homepage": "https://github.com/valor-software/ng2-file-upload#readme", 24 | "keywords": [ 25 | "angular", 26 | "upload file", 27 | "ng", 28 | "ng2", 29 | "angular2" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "../../.eslintrc.json" 4 | ], 5 | "ignorePatterns": [ 6 | "!**/*" 7 | ], 8 | "overrides": [ 9 | { 10 | "files": ["*.json"], 11 | "parser": "jsonc-eslint-parser", 12 | "rules": { 13 | "@nx/dependency-checks": [ 14 | "error", 15 | { 16 | "ignoredFiles": ["**/*.spec.ts", "**/test-setup.ts"] 17 | } 18 | ] 19 | } 20 | }, 21 | { 22 | "files": [ 23 | "*.ts" 24 | ], 25 | "extends": [ 26 | "plugin:@nx/angular", 27 | "plugin:@angular-eslint/template/process-inline-templates" 28 | ], 29 | "rules": { 30 | "@angular-eslint/prefer-standalone": [ 31 | "off" 32 | ] 33 | } 34 | }, 35 | { 36 | "files": [ 37 | "*.html" 38 | ], 39 | "extends": [ 40 | "plugin:@nx/angular-template" 41 | ], 42 | "rules": {} 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/file-upload/file-like-object.class.ts: -------------------------------------------------------------------------------- 1 | export class FileLikeObject { 2 | lastModifiedDate: any; 3 | size: any; 4 | type?: string; 5 | name?: string; 6 | rawFile: HTMLInputElement | File; 7 | 8 | constructor(fileOrInput: HTMLInputElement | File) { 9 | this.rawFile = fileOrInput; 10 | const fakePathOrObject = fileOrInput instanceof HTMLInputElement ? fileOrInput.value : fileOrInput; 11 | const postfix = typeof fakePathOrObject === 'string' ? 'FakePath' : 'Object'; 12 | const method = `_createFrom${postfix}`; 13 | (this as any)[ method ](fakePathOrObject); 14 | } 15 | 16 | _createFromFakePath(path: string): void { 17 | this.lastModifiedDate = void 0; 18 | this.size = void 0; 19 | this.type = `like/${path.slice(path.lastIndexOf('.') + 1).toLowerCase()}`; 20 | this.name = path.slice(path.lastIndexOf('/') + path.lastIndexOf('\\') + 2); 21 | } 22 | 23 | _createFromObject(object: { size: number, type: string, name: string }): void { 24 | this.size = object.size; 25 | this.type = object.type; 26 | this.name = object.name; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /apps/demo/src/app/components/file-upload-section.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | // eslint-disable-next-line @typescript-eslint/no-var-requires 3 | const doc = require('html-loader!markdown-loader!../../doc.md'); 4 | 5 | const tabDesc: Array = [ 6 | { 7 | heading: 'Simple', 8 | // eslint-disable-next-line @typescript-eslint/no-var-requires 9 | ts: require('!!raw-loader!./file-upload/simple-demo.ts').default, 10 | // eslint-disable-next-line @typescript-eslint/no-var-requires 11 | html: require('!!raw-loader!./file-upload/simple-demo.html').default, 12 | // eslint-disable-next-line @typescript-eslint/no-var-requires 13 | js: require('!!raw-loader!./file-upload/file-catcher.js').default 14 | } 15 | ]; 16 | 17 | @Component({ 18 | selector: 'file-upload-section', 19 | templateUrl: './file-upload-section.html', 20 | standalone: false 21 | }) 22 | export class FileUploadSectionComponent { 23 | name = 'File Upload'; 24 | currentHeading = 'Simple'; 25 | doc = doc; 26 | tabs: any = tabDesc; 27 | 28 | select(e: any): void { 29 | if (e.heading) { 30 | this.currentHeading = e.heading; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/on-gh-release.yml: -------------------------------------------------------------------------------- 1 | name: on-gh-release 2 | on: 3 | release: 4 | types: [released] 5 | branches: 6 | - development 7 | 8 | env: 9 | NX_BRANCH: ${{ github.event.number }} 10 | NX_RUN_GROUP: ${{ github.run_id }} 11 | NX_CLOUD_AUTH_TOKEN: ${{ secrets.NX_CLOUD_AUTH_TOKEN }} 12 | MOZ_HEADLESS: 1 13 | CONVENTIONAL_GITHUB_RELEASER_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | 15 | jobs: 16 | # one run 17 | one_run: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Cancel Previous Runs 21 | uses: styfle/cancel-workflow-action@0.11.0 22 | with: 23 | access_token: ${{ secrets.GITHUB_TOKEN }} 24 | 25 | # update npm tags 26 | npm_tag_update: 27 | runs-on: ubuntu-latest 28 | needs: one_run 29 | steps: 30 | - uses: actions/checkout@v3 31 | - uses: actions/cache@v3 32 | - name: get-npm-version 33 | id: package-version 34 | uses: martinbeentjes/npm-get-version-action@v1.3.1 35 | - run: | 36 | npm config set registry https://registry.npmjs.org/ 37 | npm config set //registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }} 38 | npm dist-tag add ng2-file-upload@${{ steps.package-version.outputs.current-version }} latest 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023 Valor Labs 4 | Copyright (c) 2015 Valor Software 5 | Copyright (c) 2015 Dmitriy Shekhovtsov 6 | 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/file-upload/file-select.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, EventEmitter, ElementRef, Input, HostListener, Output, inject } from '@angular/core'; 2 | 3 | import { FileUploader, FileUploaderOptions } from './file-uploader.class'; 4 | 5 | @Directive({ selector: '[ng2FileSelect]', standalone: false }) 6 | export class FileSelectDirective { 7 | @Input() uploader?: FileUploader; 8 | // eslint-disable-next-line @angular-eslint/no-output-on-prefix 9 | @Output() onFileSelected: EventEmitter = new EventEmitter(); 10 | 11 | protected element: ElementRef= inject(ElementRef); 12 | 13 | getOptions(): FileUploaderOptions | undefined { 14 | return this.uploader?.options; 15 | } 16 | 17 | getFilters(): string { 18 | return ''; 19 | } 20 | 21 | isEmptyAfterSelection(): boolean { 22 | return !!this.element.nativeElement.attributes.multiple; 23 | } 24 | 25 | @HostListener('change') 26 | onChange(): void { 27 | const files = this.element.nativeElement.files; 28 | const options = this.getOptions(); 29 | const filters = this.getFilters(); 30 | this.uploader?.addToQueue(files, options, filters); 31 | 32 | this.onFileSelected.emit(files); 33 | if (this.isEmptyAfterSelection()) { 34 | this.element.nativeElement.value = ''; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /apps/demo/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Angular File Upload 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 30 | 31 | 32 | 33 | Loading... 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /apps/demo/server/file-catcher.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | var express = require('express'); 3 | var multer = require('multer'); 4 | var fs = require('fs'); 5 | var app = express(); 6 | 7 | var DIR = './uploads/'; 8 | 9 | var upload = multer({dest: DIR}); 10 | 11 | app.use(function (req, res, next) { 12 | res.setHeader('Access-Control-Allow-Origin', 'http://valor-software.github.io'); 13 | res.setHeader('Access-Control-Allow-Methods', 'POST'); 14 | res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); 15 | res.setHeader('Access-Control-Allow-Credentials', true); 16 | next(); 17 | }); 18 | 19 | app.use(multer({ 20 | dest: DIR, 21 | rename: function (fieldname, filename) { 22 | return filename + Date.now(); 23 | }, 24 | onFileUploadStart: function (file) { 25 | console.log(file.originalname + ' is starting ...'); 26 | }, 27 | onFileUploadComplete: function (file) { 28 | console.log(file.fieldname + ' uploaded to ' + file.path); 29 | } 30 | })); 31 | 32 | app.get('/api', function (req, res) { 33 | res.end('file catcher example'); 34 | }); 35 | 36 | app.post('/api', function (req, res) { 37 | upload(req, res, function (err) { 38 | if (err) { 39 | return res.end(err.toString()); 40 | } 41 | 42 | res.end('File is uploaded'); 43 | }); 44 | }); 45 | 46 | var PORT = process.env.PORT || 3000; 47 | 48 | app.listen(PORT, function () { 49 | console.log('Working on port ' + PORT); 50 | }); 51 | -------------------------------------------------------------------------------- /apps/demo/src/app/components/file-upload/file-catcher.js: -------------------------------------------------------------------------------- 1 | /*eslint-disable*/ 2 | var express = require('express'); 3 | var multer = require('multer'); 4 | var fs = require('fs'); 5 | var app = express(); 6 | 7 | var DIR = './uploads/'; 8 | 9 | var upload = multer({dest: DIR}); 10 | 11 | app.use(function (req, res, next) { 12 | res.setHeader('Access-Control-Allow-Origin', 'http://valor-software.github.io'); 13 | res.setHeader('Access-Control-Allow-Methods', 'POST'); 14 | res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); 15 | res.setHeader('Access-Control-Allow-Credentials', true); 16 | next(); 17 | }); 18 | 19 | app.use(multer({ 20 | dest: DIR, 21 | rename: function (fieldname, filename) { 22 | return filename + Date.now(); 23 | }, 24 | onFileUploadStart: function (file) { 25 | console.log(file.originalname + ' is starting ...'); 26 | }, 27 | onFileUploadComplete: function (file) { 28 | console.log(file.fieldname + ' uploaded to ' + file.path); 29 | } 30 | })); 31 | 32 | app.get('/api', function (req, res) { 33 | res.end('file catcher example'); 34 | }); 35 | 36 | app.post('/api', function (req, res) { 37 | upload(req, res, function (err) { 38 | if (err) { 39 | return res.end(err.toString()); 40 | } 41 | 42 | res.end('File is uploaded'); 43 | }); 44 | }); 45 | 46 | var PORT = process.env.PORT || 3000; 47 | 48 | app.listen(PORT, function () { 49 | console.log('Working on port ' + PORT); 50 | }); 51 | -------------------------------------------------------------------------------- /apps/demo/src/app/components/file-upload/simple-demo.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { FileUploader } from 'ng2-file-upload'; 3 | 4 | // const URL = '/api/'; 5 | const URL = 'https://evening-anchorage-3159.herokuapp.com/api/'; 6 | 7 | @Component({ 8 | selector: 'simple-demo', 9 | templateUrl: './simple-demo.html', 10 | standalone: false 11 | }) 12 | export class SimpleDemoComponent { 13 | 14 | uploader: FileUploader; 15 | hasBaseDropZoneOver: boolean; 16 | hasAnotherDropZoneOver: boolean; 17 | response: string; 18 | 19 | constructor() { 20 | this.uploader = new FileUploader({ 21 | url: URL, 22 | disableMultipart: true, // 'DisableMultipart' must be 'true' for formatDataFunction to be called. 23 | formatDataFunctionIsAsync: true, 24 | formatDataFunction: async item => { 25 | return new Promise((resolve, ) => { 26 | resolve({ 27 | name: item._file.name, 28 | length: item._file.size, 29 | contentType: item._file.type, 30 | date: new Date() 31 | }); 32 | }); 33 | } 34 | }); 35 | 36 | this.hasBaseDropZoneOver = false; 37 | this.hasAnotherDropZoneOver = false; 38 | 39 | this.response = ''; 40 | 41 | this.uploader.response.subscribe(res => this.response = res ); 42 | } 43 | 44 | fileOverBase(e: any): void { 45 | this.hasBaseDropZoneOver = e; 46 | } 47 | 48 | fileOverAnother(e: any): void { 49 | this.hasAnotherDropZoneOver = e; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-file-upload", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "libs/ng2-file-upload/", 5 | "projectType": "library", 6 | "tags": [ 7 | "lib" 8 | ], 9 | "targets": { 10 | "build": { 11 | "executor": "@nx/angular:package", 12 | "outputs": [ 13 | "{workspaceRoot}/dist/libs/ng2-file-upload" 14 | ], 15 | "options": { 16 | "tsConfig": "libs/ng2-file-upload/tsconfig.lib.json", 17 | "project": "libs/ng2-file-upload/ng-package.json" 18 | }, 19 | "configurations": { 20 | "production": { 21 | "tsConfig": "libs/ng2-file-upload/tsconfig.lib.prod.json" 22 | } 23 | } 24 | }, 25 | "lint": { 26 | "executor": "@nx/eslint:lint", 27 | "outputs": [ 28 | "{options.outputFile}" 29 | ] 30 | }, 31 | "test": { 32 | "executor": "@nx/jest:jest", 33 | "outputs": [ 34 | "{workspaceRoot}/coverage/libs/ng2-file-upload" 35 | ], 36 | "options": { 37 | "jestConfig": "libs/ng2-file-upload/jest.config.ts" 38 | } 39 | }, 40 | "version": { 41 | "executor": "nx:run-commands", 42 | "outputs": [], 43 | "options": { 44 | "commands": [ 45 | "ts-node ./scripts/set-version.ts", 46 | "conventional-changelog -i CHANGELOG.md -s -p angular", 47 | "git add -A" 48 | ], 49 | "parallel": false 50 | }, 51 | "configurations": { 52 | "production": {} 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": [ 4 | "**/*" 5 | ], 6 | "plugins": [ 7 | "@nx" 8 | ], 9 | "overrides": [ 10 | { 11 | "files": [ 12 | "*.ts", 13 | "*.tsx", 14 | "*.js", 15 | "*.jsx" 16 | ], 17 | "rules": { 18 | "@nx/enforce-module-boundaries": [ 19 | "error", 20 | { 21 | "enforceBuildableLibDependency": true, 22 | "allow": [], 23 | "depConstraints": [ 24 | { 25 | "sourceTag": "*", 26 | "onlyDependOnLibsWithTags": [ 27 | "*" 28 | ] 29 | } 30 | ] 31 | } 32 | ], 33 | "@angular-eslint/prefer-standalone": [ 34 | "off" 35 | ] 36 | } 37 | }, 38 | { 39 | "files": [ 40 | "*.ts", 41 | "*.tsx" 42 | ], 43 | "extends": [ 44 | "plugin:@nx/typescript" 45 | ], 46 | "parserOptions": { 47 | "project": "./tsconfig.*?.json" 48 | }, 49 | "rules": { 50 | "semi": [ 51 | "error", 52 | "always" 53 | ], 54 | "@typescript-eslint/no-explicit-any": "off", 55 | "@typescript-eslint/ban-ts-comment": "off", 56 | "@angular-eslint/prefer-standalone": [ 57 | "off" 58 | ] 59 | } 60 | }, 61 | { 62 | "files": [ 63 | "*.js", 64 | "*.jsx" 65 | ], 66 | "extends": [ 67 | "plugin:@nx/javascript" 68 | ], 69 | "rules": {} 70 | } 71 | ] 72 | } 73 | -------------------------------------------------------------------------------- /apps/demo/src/app/components/file-upload-section.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | @for (desc of tabs; track desc) { 5 | 6 |
7 | 8 |
9 |
10 |
11 | 12 | 13 |
14 |
{{desc.html}}
15 |
16 |
17 | 18 |
19 |
{{desc.ts}}
20 |
21 |
22 |
23 | 24 |
25 |
{{desc.js}}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | } 34 |
35 |
36 | 37 |
38 |
39 |

API

40 |
41 |
42 |
43 |
44 | -------------------------------------------------------------------------------- /apps/demo/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-file-upload-demo", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "apps/demo/src", 5 | "projectType": "application", 6 | "tags": [], 7 | "implicitDependencies": [ 8 | "ng2-file-upload" 9 | ], 10 | "targets": { 11 | "build": { 12 | "executor": "@angular-devkit/build-angular:browser", 13 | "options": { 14 | "outputPath": "dist/apps/demo", 15 | "index": "apps/demo/src/index.html", 16 | "main": "apps/demo/src/main.ts", 17 | "tsConfig": "apps/demo/tsconfig.json", 18 | "assets": [ 19 | "apps/demo/src/assets" 20 | ], 21 | "styles": [], 22 | "scripts": [], 23 | "aot": false, 24 | "vendorChunk": true, 25 | "extractLicenses": false, 26 | "buildOptimizer": false, 27 | "sourceMap": true, 28 | "optimization": false, 29 | "namedChunks": true 30 | }, 31 | "dependsOn": [ 32 | { 33 | "target": "build", 34 | "dependencies": true 35 | } 36 | ], 37 | "configurations": { 38 | "production": { 39 | "optimization": true, 40 | "outputHashing": "all", 41 | "sourceMap": false, 42 | "namedChunks": false, 43 | "aot": true, 44 | "extractLicenses": true, 45 | "vendorChunk": false, 46 | "buildOptimizer": true, 47 | "fileReplacements": [ 48 | { 49 | "replace": "apps/demo/src/environments/environment.ts", 50 | "with": "apps/demo/src/environments/environment.prod.ts" 51 | } 52 | ] 53 | } 54 | }, 55 | "defaultConfiguration": "production" 56 | }, 57 | "serve": { 58 | "executor": "@angular-devkit/build-angular:dev-server", 59 | "options": { 60 | "buildTarget": "ng2-file-upload-demo:build:production" 61 | }, 62 | "configurations": { 63 | "production": { 64 | "buildTarget": "ng2-file-upload-demo:build" 65 | } 66 | }, 67 | "continuous": true 68 | }, 69 | "lint": { 70 | "executor": "@nx/eslint:lint", 71 | "options": { 72 | "lintFilePatterns": [ 73 | "apps/demo/**/*.ts" 74 | ] 75 | }, 76 | "outputs": [ 77 | "{options.outputFile}" 78 | ] 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /apps/demo/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | // eslint-disable-next-line @typescript-eslint/no-var-requires 3 | const gettingStarted = require('html-loader!markdown-loader!../getting-started.md'); 4 | 5 | @Component({ 6 | selector: 'app', 7 | template: ` 8 |
9 |
10 |
11 |

ng2-file-upload

12 |

The Angular2 File Upload directives

13 |

14 | View on GitHub 15 |

16 |
17 |
18 |
19 | 20 | npm latest version 21 | 22 | 23 | npm next version 24 | 25 | 26 | 27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 | 35 | 36 |
37 | 38 | 43 | `, 44 | standalone: false 45 | }) 46 | export class AppComponent { 47 | public gettingStarted:string = gettingStarted; 48 | public ngAfterContentInit(): any { 49 | setTimeout(()=>{ 50 | if (typeof PR !== 'undefined') { 51 | // google code-prettify 52 | PR.prettyPrint(); 53 | } 54 | }, 150); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /apps/demo/src/doc.md: -------------------------------------------------------------------------------- 1 | ### Usage 2 | ```typescript 3 | import { FileSelectDirective, FileDropDirective, FileUploader } from 'ng2-file-upload/ng2-file-upload'; 4 | ``` 5 | 6 | ### Annotations 7 | ```typescript 8 | // class FileSelectDirective 9 | @Directive({ selector: '[ng2FileSelect]', standalone: false }) 10 | ``` 11 | 12 | ```typescript 13 | // class FileDropDirective 14 | @Directive({ selector: '[ng2FileDrop]', standalone: false }) 15 | ``` 16 | 17 | ## FileSelect API 18 | 19 | ### Properties 20 | 21 | - `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) 22 | 23 | Parameters supported by this object: 24 | 25 | 1. `url` - URL of File Uploader's route 26 | 2. `authToken` - auth token that will be applied as 'Authorization' header during file send. 27 | 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. 28 | 4. `itemAlias` - item alias (form name redefenition) 29 | 5. `formatDataFunction` - Function to modify the request body. 'DisableMultipart' must be 'true' for this function to be called. 30 | 6. `formatDataFunctionIsAsync` - Informs if the function sent in 'formatDataFunction' is asynchronous. Defaults to false. 31 | 7. `parametersBeforeFiles` - States if additional parameters should be appended before or after the file. Defaults to false. 32 | 33 | ### Events 34 | - `onFileSelected` - fires when files are selected and added to the uploader queue 35 | 36 | ## FileDrop API 37 | 38 | ### Properties 39 | 40 | - `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) 41 | 42 | ### Events 43 | 44 | - `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. 45 | See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and 46 | [html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html) 47 | - `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)"` 48 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/file-upload/file-drop.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, EventEmitter, ElementRef, HostListener, Input, Output, inject } from '@angular/core'; 2 | 3 | import { FileUploader, FileUploaderOptions } from './file-uploader.class'; 4 | 5 | @Directive({ selector: '[ng2FileDrop]', standalone: false }) 6 | export class FileDropDirective { 7 | @Input() uploader?: FileUploader; 8 | @Output() fileOver: EventEmitter = new EventEmitter(); 9 | // eslint-disable-next-line @angular-eslint/no-output-on-prefix 10 | @Output() onFileDrop: EventEmitter = new EventEmitter(); 11 | 12 | protected element: ElementRef= inject(ElementRef); 13 | 14 | getOptions(): FileUploaderOptions | void { 15 | return this.uploader?.options; 16 | } 17 | 18 | getFilters(): string { 19 | return ''; 20 | } 21 | 22 | @HostListener('drop', [ '$event' ]) 23 | onDrop(event: MouseEvent): void { 24 | const transfer = this._getTransfer(event); 25 | if (!transfer) { 26 | return; 27 | } 28 | 29 | const options = this.getOptions(); 30 | const filters = this.getFilters(); 31 | this._preventAndStop(event); 32 | if (options) { 33 | this.uploader?.addToQueue(transfer.files, options, filters); 34 | } 35 | this.fileOver.emit(false); 36 | this.onFileDrop.emit(transfer.files); 37 | } 38 | 39 | @HostListener('dragover', [ '$event' ]) 40 | onDragOver(event: MouseEvent): void { 41 | const transfer = this._getTransfer(event); 42 | if (!this._haveFiles(transfer.types)) { 43 | return; 44 | } 45 | 46 | transfer.dropEffect = 'copy'; 47 | this._preventAndStop(event); 48 | this.fileOver.emit(true); 49 | } 50 | 51 | @HostListener('dragleave', [ '$event' ]) 52 | onDragLeave(event: MouseEvent): void { 53 | if ((this as any).element) { 54 | if (event.currentTarget === (this as any).element[ 0 ]) { 55 | return; 56 | } 57 | } 58 | 59 | this._preventAndStop(event); 60 | this.fileOver.emit(false); 61 | } 62 | 63 | protected _getTransfer(event: any): any { 64 | return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix; 65 | } 66 | 67 | protected _preventAndStop(event: MouseEvent): void { 68 | event.preventDefault(); 69 | event.stopPropagation(); 70 | } 71 | 72 | protected _haveFiles(types: any): boolean { 73 | if (!types) { 74 | return false; 75 | } 76 | 77 | if (types.indexOf) { 78 | return types.indexOf('Files') !== -1; 79 | } else if (types.contains) { 80 | return types.contains('Files'); 81 | } else { 82 | return false; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultProject": "ng2-file-upload-demo", 3 | "generators": { 4 | "@schematics/angular:component": { 5 | "prefix": "", 6 | "styleext": "css", 7 | "type": "component" 8 | }, 9 | "@schematics/angular:directive": { 10 | "prefix": "", 11 | "type": "directive" 12 | }, 13 | "@nx/angular:component": { 14 | "type": "component" 15 | }, 16 | "@nx/angular:directive": { 17 | "type": "directive" 18 | }, 19 | "@nx/angular:service": { 20 | "type": "service" 21 | }, 22 | "@schematics/angular:service": { 23 | "type": "service" 24 | }, 25 | "@nx/angular:scam": { 26 | "type": "component" 27 | }, 28 | "@nx/angular:scam-directive": { 29 | "type": "directive" 30 | }, 31 | "@nx/angular:guard": { 32 | "typeSeparator": "." 33 | }, 34 | "@schematics/angular:guard": { 35 | "typeSeparator": "." 36 | }, 37 | "@nx/angular:interceptor": { 38 | "typeSeparator": "." 39 | }, 40 | "@schematics/angular:interceptor": { 41 | "typeSeparator": "." 42 | }, 43 | "@nx/angular:module": { 44 | "typeSeparator": "." 45 | }, 46 | "@schematics/angular:module": { 47 | "typeSeparator": "." 48 | }, 49 | "@nx/angular:pipe": { 50 | "typeSeparator": "." 51 | }, 52 | "@schematics/angular:pipe": { 53 | "typeSeparator": "." 54 | }, 55 | "@nx/angular:resolver": { 56 | "typeSeparator": "." 57 | }, 58 | "@schematics/angular:resolver": { 59 | "typeSeparator": "." 60 | } 61 | }, 62 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 63 | "targetDefaults": { 64 | "build": { 65 | "inputs": [ 66 | "production", 67 | "^production" 68 | ], 69 | "cache": true 70 | }, 71 | "@nx/jest:jest": { 72 | "inputs": [ 73 | "default", 74 | "^default", 75 | "{workspaceRoot}/jest.preset.js" 76 | ], 77 | "cache": true, 78 | "options": { 79 | "passWithNoTests": true 80 | }, 81 | "configurations": { 82 | "ci": { 83 | "ci": true, 84 | "codeCoverage": true 85 | } 86 | } 87 | }, 88 | "@nx/eslint:lint": { 89 | "inputs": [ 90 | "default", 91 | "{workspaceRoot}/.eslintrc.json" 92 | ], 93 | "cache": true 94 | } 95 | }, 96 | "namedInputs": { 97 | "default": [ 98 | "{projectRoot}/**/*", 99 | "sharedGlobals" 100 | ], 101 | "sharedGlobals": [ 102 | "{workspaceRoot}/angular.json", 103 | "{workspaceRoot}/tsconfig.json", 104 | "{workspaceRoot}/tslint.json", 105 | "{workspaceRoot}/nx.json" 106 | ], 107 | "production": [ 108 | "default", 109 | "!{projectRoot}/src/test-setup.[jt]s" 110 | ] 111 | }, 112 | "nxCloudAccessToken": "MmJkYThiZTUtNjUzMS00NzNmLWFiZTYtZjM5NDBlYWJlZTk4fHJlYWQtd3JpdGU=", 113 | "parallel": 1, 114 | "useInferencePlugins": false, 115 | "defaultBase": "master" 116 | } 117 | -------------------------------------------------------------------------------- /.github/workflows/on-push-or-pull.yml: -------------------------------------------------------------------------------- 1 | name: on-pull-request-or-push 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - development 8 | 9 | env: 10 | NX_BRANCH: ${{ github.event.number }} 11 | NX_RUN_GROUP: ${{ github.run_id }} 12 | NX_CLOUD_AUTH_TOKEN: ${{ secrets.NX_CLOUD_AUTH_TOKEN }} 13 | MOZ_HEALESS: 1 14 | SAUCE_USERNAME_PR: valorkinpr 15 | FIREBASE_CHANNEL: ${{ fromJSON('["", "live"]')[!github.base_ref] }} 16 | 17 | CACHE_NODE_MODULES_PATH: | 18 | ~/.npm 19 | node_modules 20 | 21 | CACHE_DIST_PATH: | 22 | dist 23 | 24 | jobs: 25 | # one run 26 | one_run: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Cancel Previous Runs 30 | uses: styfle/cancel-workflow-action@0.9.0 31 | with: 32 | access_token: ${{ secrets.GITHUB_TOKEN }} 33 | 34 | # install dependencies 35 | install: 36 | runs-on: ubuntu-latest 37 | needs: one_run 38 | steps: 39 | - uses: actions/checkout@v3 40 | - uses: actions/cache@v3 41 | id: cache 42 | with: 43 | path: ${{ env.CACHE_NODE_MODULES_PATH }} 44 | key: node_modules-${{ hashFiles('**/package-lock.json') }} 45 | - run: npm ci 46 | if: steps.cache.outputs.cache-hit != 'true' 47 | 48 | # build ng2-file-upload 49 | build: 50 | needs: install 51 | runs-on: ubuntu-latest 52 | steps: 53 | - uses: actions/checkout@v3 54 | - uses: actions/cache@v3 55 | with: 56 | path: ${{ env.CACHE_NODE_MODULES_PATH }} 57 | key: node_modules-${{ hashFiles('**/package-lock.json') }} 58 | - uses: actions/cache@v3 59 | with: 60 | path: ${{ env.CACHE_DIST_PATH }} 61 | key: dist-${{ github.run_id }} 62 | - run: npx nx run ng2-file-upload-demo:build 63 | 64 | # run unit tests 65 | unit_tests_with_coverage: 66 | runs-on: ubuntu-latest 67 | needs: build 68 | steps: 69 | - uses: actions/checkout@v3 70 | - uses: actions/cache@v3 71 | with: 72 | path: ${{ env.CACHE_NODE_MODULES_PATH }} 73 | key: node_modules-${{ hashFiles('**/package-lock.json') }} 74 | - uses: actions/cache@v3 75 | with: 76 | path: ${{ env.CACHE_DIST_PATH }} 77 | key: dist-${{ github.run_id }} 78 | - run: npm run test-coverage 79 | continue-on-error: true 80 | 81 | # run linting 82 | linting: 83 | runs-on: ubuntu-latest 84 | needs: install 85 | steps: 86 | - uses: actions/checkout@v3 87 | - uses: actions/cache@v3 88 | with: 89 | path: ${{ env.CACHE_NODE_MODULES_PATH }} 90 | key: node_modules-${{ hashFiles('**/package-lock.json') }} 91 | - run: npm run lint 92 | 93 | # firebase preview 94 | build_and_preview: 95 | runs-on: ubuntu-latest 96 | needs: build 97 | outputs: 98 | output_url: ${{ steps.firebase_hosting_preview.outputs.details_url }} 99 | steps: 100 | - uses: actions/checkout@v3 101 | - uses: actions/cache@v3 102 | with: 103 | path: ${{ env.CACHE_DIST_PATH }} 104 | key: dist-${{ github.run_id }} 105 | - uses: FirebaseExtended/action-hosting-deploy@v0 106 | continue-on-error: true 107 | id: firebase_hosting_preview 108 | with: 109 | repoToken: '${{ secrets.GITHUB_TOKEN }}' 110 | firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_NGX_FILE_UPLOAD }}' 111 | projectId: ngx-file-upload 112 | channelId: ${{ env.FIREBASE_CHANNEL }} 113 | expires: 7d 114 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/testing/spec/file-select.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, ComponentFixture } from '@angular/core/testing'; 2 | import { Component, DebugElement } from '@angular/core'; 3 | import { By } from '@angular/platform-browser'; 4 | 5 | import { FileUploadModule } from '../../file-upload/file-upload.module'; 6 | import { FileSelectDirective } from '../../file-upload/file-select.directive'; 7 | import { FileUploader } from '../../file-upload/file-uploader.class'; 8 | 9 | @Component({ 10 | selector: 'container', 11 | template: `` 15 | }) 16 | export class ContainerComponent { 17 | public get url(): string { return 'localhost:3000'; } 18 | public uploader: FileUploader = new FileUploader({ url: this.url }); 19 | } 20 | 21 | describe('Directive: FileSelectDirective', () => { 22 | let fixture: ComponentFixture; 23 | let hostComponent: ContainerComponent; 24 | let directiveElement: DebugElement; 25 | let fileSelectDirective: FileSelectDirective; 26 | 27 | beforeEach(() => { 28 | TestBed.configureTestingModule({ 29 | imports: [ FileUploadModule ], 30 | declarations: [ ContainerComponent ], 31 | providers: [ ContainerComponent ] 32 | }); 33 | }); 34 | 35 | beforeEach(() => { 36 | fixture = TestBed.createComponent(ContainerComponent); 37 | hostComponent = fixture.componentInstance; 38 | 39 | fixture.detectChanges(); 40 | 41 | directiveElement = fixture.debugElement.query(By.directive(FileSelectDirective)); 42 | fileSelectDirective = directiveElement.injector.get(FileSelectDirective) as FileSelectDirective; 43 | }); 44 | 45 | it('can be initialized', () => { 46 | expect(fixture).toBeDefined(); 47 | expect(hostComponent).toBeDefined(); 48 | expect(fileSelectDirective).toBeDefined(); 49 | }); 50 | 51 | it('can set file uploader', () => { 52 | expect(fileSelectDirective.uploader).toBe(hostComponent.uploader); 53 | }); 54 | 55 | it('can get uploader options', () => { 56 | const options = fileSelectDirective.getOptions(); 57 | expect(options).toBeTruthy(); 58 | if (options) { 59 | // Check url set through binding 60 | expect(options.url).toBe(hostComponent.url); 61 | 62 | // Check default options 63 | expect(options.autoUpload).toBeFalsy(); 64 | expect(options.isHTML5).toBeTruthy(); 65 | expect(options.removeAfterUpload).toBeFalsy(); 66 | expect(options.disableMultipart).toBeFalsy(); 67 | } 68 | 69 | }); 70 | 71 | it('can get filters', () => { 72 | const filters = fileSelectDirective.getFilters(); 73 | 74 | // TODO: Update test once implemented 75 | expect(filters).toEqual(''); 76 | }); 77 | 78 | it('can check if element is empty', () => { 79 | const isElementEmpty = fileSelectDirective.isEmptyAfterSelection(); 80 | 81 | expect(isElementEmpty).toBeFalsy(); 82 | }); 83 | 84 | it('can listed on change event', () => { 85 | const change = jest.spyOn(fileSelectDirective, 'onChange'); 86 | 87 | directiveElement.triggerEventHandler('change', {}); 88 | 89 | expect(change).toHaveBeenCalled(); 90 | }); 91 | 92 | it('handles change event', () => { 93 | let addToQueue; 94 | if (fileSelectDirective.uploader?.addToQueue) { 95 | addToQueue = jest.spyOn(fileSelectDirective.uploader, 'addToQueue'); 96 | } 97 | fileSelectDirective.onChange(); 98 | 99 | expect(addToQueue).toHaveBeenCalledWith(directiveElement.nativeElement.files, fileSelectDirective.getOptions(), fileSelectDirective.getFilters()); 100 | }); 101 | }); 102 | -------------------------------------------------------------------------------- /.github/workflows/on-publish.yml: -------------------------------------------------------------------------------- 1 | name: on-release 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | 7 | env: 8 | NX_BRANCH: ${{ github.event.number }} 9 | NX_RUN_GROUP: ${{ github.run_id }} 10 | NX_CLOUD_AUTH_TOKEN: ${{ secrets.NX_CLOUD_AUTH_TOKEN }} 11 | MOZ_HEADLESS: 1 12 | CONVENTIONAL_GITHUB_RELEASER_TOKEN: ${{ secrets.GITHUB_TOKEN }} 13 | 14 | jobs: 15 | # one run 16 | one_run: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Cancel Previous Runs 20 | uses: styfle/cancel-workflow-action@0.9.0 21 | with: 22 | access_token: ${{ secrets.GITHUB_TOKEN }} 23 | 24 | # install dependencies 25 | install: 26 | runs-on: ubuntu-latest 27 | needs: one_run 28 | steps: 29 | - uses: actions/checkout@v3 30 | - uses: actions/cache@v3 31 | id: cache 32 | with: 33 | path: node_modules 34 | key: node_modules-${{ hashFiles('**/package-lock.json') }} 35 | - run: npm ci 36 | if: steps.cache.outputs.cache-hit != 'true' 37 | 38 | # build ng2-file-upload 39 | build: 40 | needs: install 41 | runs-on: ubuntu-latest 42 | steps: 43 | - uses: actions/checkout@v3 44 | - uses: actions/cache@v3 45 | with: 46 | path: node_modules 47 | key: node_modules-${{ hashFiles('**/package-lock.json') }} 48 | - uses: actions/cache@v3 49 | with: 50 | path: | 51 | dist 52 | key: dist-${{ github.run_id }} 53 | - run: | 54 | npx nx run ng2-file-upload:build --configuration production 55 | npx nx run ng2-file-upload-demo:build --configuration production 56 | 57 | # update release notes in github 58 | update_release_draft: 59 | needs: install 60 | runs-on: ubuntu-latest 61 | steps: 62 | - uses: actions/checkout@v3 63 | - uses: actions/cache@v3 64 | with: 65 | path: node_modules 66 | key: node_modules-${{ hashFiles('**/package-lock.json') }} 67 | - run: npx conventional-github-releaser -p angular 68 | 69 | # update gh_pages 70 | gh_pages_deploy: 71 | runs-on: ubuntu-latest 72 | needs: build 73 | steps: 74 | - uses: actions/checkout@v3 75 | - uses: actions/checkout@v3 76 | with: 77 | ref: 'gh-pages' 78 | path: 'gh-pages' 79 | 80 | - uses: actions/cache@v3 81 | with: 82 | path: node_modules 83 | key: node_modules-${{ hashFiles('**/package-lock.json') }} 84 | - uses: actions/cache@v3 85 | with: 86 | path: | 87 | dist 88 | key: dist-${{ github.run_id }} 89 | - run: | 90 | cd gh-pages 91 | git config user.email gh-actions-${GITHUB_ACTOR}@github.com 92 | git config user.name $GITHUB_ACTOR 93 | git add -A 94 | git commit -am "ci: gh-pages update" 95 | continue-on-error: true 96 | - name: push to gh-pages 97 | uses: ad-m/github-push-action@v0.6.0 98 | continue-on-error: true 99 | with: 100 | github_token: ${{ secrets.GITHUB_TOKEN }} 101 | branch: 'gh-pages' 102 | directory: 'gh-pages' 103 | 104 | # publish to npm 105 | npm_publish: 106 | runs-on: ubuntu-latest 107 | needs: build 108 | steps: 109 | - uses: actions/checkout@v3 110 | - uses: actions/cache@v3 111 | with: 112 | path: node_modules 113 | key: node_modules-${{ hashFiles('**/package-lock.json') }} 114 | - uses: actions/cache@v3 115 | with: 116 | path: | 117 | dist 118 | key: dist-${{ github.run_id }} 119 | - uses: JS-DevTools/npm-publish@v1 120 | with: 121 | package: "dist/libs/ng2-file-upload/package.json" 122 | token: ${{ secrets.NPM_TOKEN }} 123 | 124 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng2-file-upload-demo", 3 | "version": "9.0.0", 4 | "private": true, 5 | "description": "Angular file upload directives", 6 | "scripts": { 7 | "start": "npx nx run ng2-file-upload-demo:serve", 8 | "demo.build": "ng build", 9 | "demo.build-prod": "ng build", 10 | "build": "nx run ng2-file-upload:build", 11 | "build-prod": "nx run ng2-file-upload:build", 12 | "lint": "nx run-many --target=lint --all", 13 | "test": "nx run-many --target=test --all", 14 | "version": "nx run ng2-file-upload:version", 15 | "pretest": "run-s lint build", 16 | "test-coverage": "nx run-many --all --target=test --codeCoverage", 17 | "demo.gh-pages": "run-s build demo.build demo.deploy", 18 | "demo.deploy": "gh-pages -d dist/apps/demo", 19 | "flow.github-release": "conventional-github-releaser -p angular" 20 | }, 21 | "keywords": [ 22 | "angular", 23 | "bootstrap", 24 | "twitter-bootstrap", 25 | "file-upload", 26 | "angular-file-upload" 27 | ], 28 | "author": "Dmitriy Shekhovtsov ", 29 | "license": "MIT", 30 | "repository": { 31 | "type": "git", 32 | "url": "git+ssh://git@github.com/valor-software/ng2-file-upload.git" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/valor-software/ng2-file-upload/issues" 36 | }, 37 | "homepage": "https://github.com/valor-software/ng2-file-upload#readme", 38 | "devDependencies": { 39 | "@angular-devkit/build-angular": "20.0.6", 40 | "@angular-devkit/core": "20.0.6", 41 | "@angular-devkit/schematics": "20.0.6", 42 | "@angular-eslint/eslint-plugin": "20.1.1", 43 | "@angular-eslint/eslint-plugin-template": "20.1.1", 44 | "@angular-eslint/template-parser": "20.1.1", 45 | "@angular/animations": "20.0.7", 46 | "@angular/cli": "~20.0.0", 47 | "@angular/common": "20.0.7", 48 | "@angular/compiler": "20.0.7", 49 | "@angular/compiler-cli": "20.0.7", 50 | "@angular/core": "20.0.7", 51 | "@angular/forms": "20.0.7", 52 | "@angular/platform-browser": "20.0.7", 53 | "@angular/platform-browser-dynamic": "20.0.7", 54 | "@nx/angular": "21.2.2", 55 | "@nx/eslint": "21.2.2", 56 | "@nx/eslint-plugin": "21.2.2", 57 | "@nx/jest": "21.2.2", 58 | "@nx/node": "21.2.2", 59 | "@schematics/angular": "20.0.6", 60 | "@types/fs-extra": "9.0.7", 61 | "@types/jest": "29.5.14", 62 | "@types/node": "^22.9.3", 63 | "@types/webpack": "^5.0.0", 64 | "@typescript-eslint/eslint-plugin": "8.36.0", 65 | "@typescript-eslint/parser": "8.36.0", 66 | "autoprefixer": "^10.4.0", 67 | "bootstrap": "5.2.3", 68 | "classlist-polyfill": "1.2.0", 69 | "codecov": "3.8.2", 70 | "conventional-changelog-cli": "2.1.1", 71 | "conventional-github-releaser": "3.1.5", 72 | "core-js": "^3.14.0", 73 | "eslint": "8.57.0", 74 | "eslint-config-prettier": "10.1.5", 75 | "fs-extra": "9.1.0", 76 | "gh-pages": "3.2.2", 77 | "google-code-prettify": "1.0.5", 78 | "html-loader": "^1.3.2", 79 | "jest": "29.7.0", 80 | "jest-preset-angular": "14.6.0", 81 | "markdown-loader": "^6.0.0", 82 | "ng-packagr": "20.0.1", 83 | "ngx-bootstrap": "^20.0.0", 84 | "npm-run-all": "^4.1.5", 85 | "postcss": "^8.3.9", 86 | "postcss-import": "14.1.0", 87 | "postcss-preset-env": "7.5.0", 88 | "postcss-url": "10.1.3", 89 | "raw-loader": "^4.0.2", 90 | "rxjs": "^6.6.0", 91 | "ts-helpers": "^1.1.2", 92 | "ts-jest": "29.1.1", 93 | "ts-node": "10.9.1", 94 | "typescript": "5.8.3", 95 | "zone.js": "0.15.0" 96 | }, 97 | "contributors": [ 98 | { 99 | "name": "Vyacheslav Chub", 100 | "email": "vyacheslav.chub@valor-software.com", 101 | "url": "https://github.com/buchslava" 102 | }, 103 | { 104 | "name": "Dmitriy Shekhovtsov", 105 | "email": "valorkin@gmail.com", 106 | "url": "https://github.com/valorkin" 107 | }, 108 | { 109 | "name": "Adrian Faciu", 110 | "email": "adrian.faciu@gmail.com", 111 | "url": "https://github.com/adrianfaciu" 112 | }, 113 | { 114 | "name": "Oleksandr Telnov", 115 | "email": "otelnov@gmail.com", 116 | "url": "https://github.com/otelnov" 117 | } 118 | ], 119 | "dependencies": { 120 | "@nx/workspace": "21.2.2", 121 | "nx": "21.2.2", 122 | "tslib": "^2.3.1" 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/file-upload/file-item.class.ts: -------------------------------------------------------------------------------- 1 | import { FileLikeObject } from './file-like-object.class'; 2 | import { FileUploader, ParsedResponseHeaders, FileUploaderOptions } from './file-uploader.class'; 3 | 4 | export class FileItem { 5 | file: FileLikeObject; 6 | _file: File; 7 | alias?: string; 8 | url = '/'; 9 | method?: string; 10 | headers: any = []; 11 | withCredentials = true; 12 | formData: any = []; 13 | isReady = false; 14 | isUploading = false; 15 | isUploaded = false; 16 | isSuccess = false; 17 | isCancel = false; 18 | isError = false; 19 | progress = 0; 20 | index?: number; 21 | _xhr?: XMLHttpRequest; 22 | _form: any; 23 | 24 | protected uploader: FileUploader; 25 | protected some: File; 26 | protected options: FileUploaderOptions; 27 | 28 | constructor(uploader: FileUploader, some: File, options: FileUploaderOptions) { 29 | this.uploader = uploader; 30 | this.some = some; 31 | this.options = options; 32 | this.file = new FileLikeObject(some); 33 | this._file = some; 34 | if (uploader.options) { 35 | this.method = uploader.options.method || 'POST'; 36 | this.alias = uploader.options.itemAlias || 'file'; 37 | } 38 | this.url = uploader.options.url; 39 | } 40 | 41 | upload(): void { 42 | try { 43 | this.uploader.uploadItem(this); 44 | } catch (e) { 45 | this.uploader._onCompleteItem(this, '', 0, {}); 46 | this.uploader._onErrorItem(this, '', 0, {}); 47 | } 48 | } 49 | 50 | cancel(): void { 51 | this.uploader.cancelItem(this); 52 | } 53 | 54 | remove(): void { 55 | this.uploader.removeFromQueue(this); 56 | } 57 | 58 | onBeforeUpload(): void { 59 | return void 0; 60 | } 61 | 62 | onBuildForm(form: any): any { 63 | return { form }; 64 | } 65 | 66 | onProgress(progress: number): any { 67 | return { progress }; 68 | } 69 | 70 | onSuccess(response: string, status: number, headers: ParsedResponseHeaders): any { 71 | return { response, status, headers }; 72 | } 73 | 74 | onError(response: string, status: number, headers: ParsedResponseHeaders): any { 75 | return { response, status, headers }; 76 | } 77 | 78 | onCancel(response: string, status: number, headers: ParsedResponseHeaders): any { 79 | return { response, status, headers }; 80 | } 81 | 82 | onComplete(response: string, status: number, headers: ParsedResponseHeaders): any { 83 | return { response, status, headers }; 84 | } 85 | 86 | _onBeforeUpload(): void { 87 | this.isReady = true; 88 | this.isUploading = true; 89 | this.isUploaded = false; 90 | this.isSuccess = false; 91 | this.isCancel = false; 92 | this.isError = false; 93 | this.progress = 0; 94 | this.onBeforeUpload(); 95 | } 96 | 97 | _onBuildForm(form: any): void { 98 | this.onBuildForm(form); 99 | } 100 | 101 | _onProgress(progress: number): void { 102 | this.progress = progress; 103 | this.onProgress(progress); 104 | } 105 | 106 | _onSuccess(response: string, status: number, headers: ParsedResponseHeaders): void { 107 | this.isReady = false; 108 | this.isUploading = false; 109 | this.isUploaded = true; 110 | this.isSuccess = true; 111 | this.isCancel = false; 112 | this.isError = false; 113 | this.progress = 100; 114 | this.index = undefined; 115 | this.onSuccess(response, status, headers); 116 | } 117 | 118 | _onError(response: string, status: number, headers: ParsedResponseHeaders): void { 119 | this.isReady = false; 120 | this.isUploading = false; 121 | this.isUploaded = true; 122 | this.isSuccess = false; 123 | this.isCancel = false; 124 | this.isError = true; 125 | this.progress = 0; 126 | this.index = undefined; 127 | this.onError(response, status, headers); 128 | } 129 | 130 | _onCancel(response: string, status: number, headers: ParsedResponseHeaders): void { 131 | this.isReady = false; 132 | this.isUploading = false; 133 | this.isUploaded = false; 134 | this.isSuccess = false; 135 | this.isCancel = true; 136 | this.isError = false; 137 | this.progress = 0; 138 | this.index = undefined; 139 | this.onCancel(response, status, headers); 140 | } 141 | 142 | _onComplete(response: string, status: number, headers: ParsedResponseHeaders): void { 143 | this.onComplete(response, status, headers); 144 | 145 | if (this.uploader.options.removeAfterUpload) { 146 | this.remove(); 147 | } 148 | } 149 | 150 | _prepareToUploading(): void { 151 | this.index = this.index || ++this.uploader._nextIndex; 152 | this.isReady = true; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 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) 2 | Easy to use Angular2 directives for files upload ([demo](http://valor-software.github.io/ng2-file-upload/)) 3 | 4 | [![Angular 2 Style Guide](https://mgechev.github.io/angular2-style-guide/images/badge.svg)](https://github.com/mgechev/angular2-style-guide) 5 | [![Build Status](https://travis-ci.org/valor-software/ng2-file-upload.svg?branch=development)](https://travis-ci.org/valor-software/ng2-file-upload) 6 | 7 | ## Quick start 8 | 9 | 1. A recommended way to install ***ng2-file-upload*** is through [npm](https://www.npmjs.com/search?q=ng2-file-upload) package manager using the following command: 10 | 11 | `npm i ng2-file-upload` 12 | 13 | Alternatively, you can [download it in a ZIP file](https://github.com/valor-software/ng2-file-upload/archive/master.zip). 14 | 15 | 2. Currently `ng2-file-upload` contains two directives: `ng2-file-select` and `ng2-file-drop`. `ng2-file-select` is used for 'file-input' field of form and 16 | `ng2-file-drop` is used for area that will be used for dropping of file or files. 17 | 18 | 3. More information regarding using of ***ng2-file-upload*** is located in 19 | [demo](http://valor-software.github.io/ng2-file-upload/) and [demo sources](https://github.com/valor-software/ng2-file-upload/tree/master/demo). 20 | 21 | ## Using ***ng2-file-upload*** in a project 22 | 23 | 1. Install as shown in the above section. 24 | 25 | 2. Import `FileUploadModule` into the module that declares the component using ***ng2-file-upload***: 26 | 27 | ```import { FileUploadModule } from 'ng2-file-upload';``` 28 | 29 | 3. Add it to `[imports]` under `@NgModule`: 30 | 31 | ```imports: [ ... FileUploadModule, ... ]``` 32 | 33 | 4. Import `FileUploader` into the component: 34 | 35 | ```import { FileUploader } from 'ng2-file-upload';``` 36 | 37 | 5. Create a variable for the API url: 38 | 39 | ```const URL = 'path_to_api';``` 40 | 41 | 6. Initialize it: 42 | 43 | ```public uploader:FileUploader = new FileUploader({url: URL}); ``` 44 | 45 | ## API for `ng2FileSelect` 46 | 47 | ### Properties 48 | 49 | - `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) 50 | 51 | ### Events 52 | - `onFileSelected` - fires when files are selected and added to the uploader queue 53 | 54 | ## API for `ng2FileDrop` 55 | 56 | ### Properties 57 | 58 | - `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) 59 | 60 | Parameters supported by this object: 61 | 62 | 1. `url` - URL of File Uploader's route 63 | 2. `authToken` - Auth token that will be applied as 'Authorization' header during file send. 64 | 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. 65 | 4. `itemAlias` - item alias (form name redefinition) 66 | 5. `formatDataFunction` - Function to modify the request body. 'DisableMultipart' must be 'true' for this function to be called. 67 | 6. `formatDataFunctionIsAsync` - Informs if the function sent in 'formatDataFunction' is asynchronous. Defaults to false. 68 | 7. `parametersBeforeFiles` - States if additional parameters should be appended before or after the file. Defaults to false. 69 | 70 | ### Events 71 | 72 | - `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. 73 | See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and 74 | [html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html) 75 | - `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)"` 76 | 77 | # Troubleshooting 78 | 79 | Please follow these guidelines when reporting bugs and feature requests: 80 | 81 | 1. Use [GitHub Issues](https://github.com/valor-software/ng2-file-upload/issues) board to report bugs and feature requests (not our email address) 82 | 2. Please **always** write steps to reproduce the error. That way we can focus on fixing the bug, not scratching our heads trying to reproduce it. 83 | 84 | Thanks for understanding! 85 | 86 | ### License 87 | 88 | The MIT License (see the [LICENSE](https://github.com/valor-software/ng2-file-upload/blob/master/LICENSE) file for the full text) 89 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/README.md: -------------------------------------------------------------------------------- 1 | # 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) 2 | Easy to use Angular2 directives for files upload ([demo](http://valor-software.github.io/ng2-file-upload/)) 3 | 4 | [![Angular 2 Style Guide](https://mgechev.github.io/angular2-style-guide/images/badge.svg)](https://github.com/mgechev/angular2-style-guide) 5 | [![Build Status](https://travis-ci.org/valor-software/ng2-file-upload.svg?branch=development)](https://travis-ci.org/valor-software/ng2-file-upload) 6 | 7 | 8 | ## Quick start 9 | 10 | 1. A recommended way to install ***ng2-file-upload*** is through [npm](https://www.npmjs.com/search?q=ng2-file-upload) package manager using the following command: 11 | 12 | `npm i ng2-file-upload` 13 | 14 | Alternatively, you can [download it in a ZIP file](https://github.com/valor-software/ng2-file-upload/archive/master.zip). 15 | 16 | 2. Currently `ng2-file-upload` contains two directives: `ng2-file-select` and `ng2-file-drop`. `ng2-file-select` is used for 'file-input' field of form and 17 | `ng2-file-drop` is used for area that will be used for dropping of file or files. 18 | 19 | 3. More information regarding using of ***ng2-file-upload*** is located in 20 | [demo](http://valor-software.github.io/ng2-file-upload/) and [demo sources](https://github.com/valor-software/ng2-file-upload/tree/master/demo). 21 | 22 | ## Using ***ng2-file-upload*** in a project 23 | 24 | 1. Install as shown in the above section. 25 | 26 | 2. Import `FileUploadModule` into the module that declares the component using ***ng2-file-upload***: 27 | 28 | ```import { FileUploadModule } from 'ng2-file-upload';``` 29 | 30 | 3. Add it to `[imports]` under `@NgModule`: 31 | 32 | ```imports: [ ... FileUploadModule, ... ]``` 33 | 34 | 4. Import `FileUploader` into the component: 35 | 36 | ```import { FileUploader } from 'ng2-file-upload';``` 37 | 38 | 5. Create a variable for the API url: 39 | 40 | ```const URL = 'path_to_api';``` 41 | 42 | 6. Initialize it: 43 | 44 | ```public uploader:FileUploader = new FileUploader({url: URL}); ``` 45 | 46 | ## API for `ng2FileSelect` 47 | 48 | ### Properties 49 | 50 | - `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) 51 | 52 | ### Events 53 | - `onFileSelected` - fires when files are selected and added to the uploader queue 54 | 55 | ## API for `ng2FileDrop` 56 | 57 | ### Properties 58 | 59 | - `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) 60 | 61 | Parameters supported by this object: 62 | 63 | 1. `url` - URL of File Uploader's route 64 | 2. `authToken` - Auth token that will be applied as 'Authorization' header during file send. 65 | 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. 66 | 4. `itemAlias` - item alias (form name redefinition) 67 | 5. `formatDataFunction` - Function to modify the request body. 'DisableMultipart' must be 'true' for this function to be called. 68 | 6. `formatDataFunctionIsAsync` - Informs if the function sent in 'formatDataFunction' is asynchronous. Defaults to false. 69 | 7. `parametersBeforeFiles` - States if additional parameters should be appended before or after the file. Defaults to false. 70 | 71 | ### Events 72 | 73 | - `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. 74 | See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and 75 | [html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html) 76 | - `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)"` 77 | 78 | # Troubleshooting 79 | 80 | Please follow these guidelines when reporting bugs and feature requests: 81 | 82 | 1. Use [GitHub Issues](https://github.com/valor-software/ng2-file-upload/issues) board to report bugs and feature requests (not our email address) 83 | 2. Please **always** write steps to reproduce the error. That way we can focus on fixing the bug, not scratching our heads trying to reproduce it. 84 | 85 | Thanks for understanding! 86 | 87 | ### License 88 | 89 | The MIT License (see the [LICENSE](https://github.com/valor-software/ng2-file-upload/blob/master/LICENSE) file for the full text) 90 | -------------------------------------------------------------------------------- /apps/demo/src/assets/css/prettify-angulario.css: -------------------------------------------------------------------------------- 1 | .prettyprint { 2 | white-space: pre-wrap; 3 | background: #F5F6F7; 4 | font-family: Monaco,"Lucida Console",monospace; 5 | color: #5C707A; 6 | width: auto; 7 | overflow: auto; 8 | position: relative; 9 | padding: 0; 10 | font-size: 13px; 11 | line-height: 24px; 12 | margin-bottom: 24px; 13 | border-radius: 4px; 14 | padding: 16px 32px 15 | } 16 | 17 | .prettyprint.linenums,.prettyprint[class^="linenums:"],.prettyprint[class*=" linenums:"] { 18 | padding: 0 19 | } 20 | 21 | .prettyprint.is-showcase { 22 | border: 4px solid #0273D4 23 | } 24 | 25 | .prettyprint code { 26 | background: none; 27 | font-size: 13px; 28 | padding: 0 29 | } 30 | 31 | .prettyprint ol { 32 | background: #F5F6F7; 33 | padding: 16px 32px 16px 56px; 34 | margin: 0; 35 | overflow: auto; 36 | font-size: 13px 37 | } 38 | 39 | .prettyprint ol li,.prettyprint .tag { 40 | color: #7a8b94; 41 | background: none; 42 | margin-bottom: 5px; 43 | line-height: normal; 44 | list-style-type: decimal; 45 | font-size: 12px 46 | } 47 | 48 | .prettyprint ol li:last-child { 49 | margin-bottom: 0 50 | } 51 | 52 | .prettyprint ol li code { 53 | background: none; 54 | font-size: 13px 55 | } 56 | 57 | .prettyprint .pnk,.prettyprint .blk { 58 | border-radius: 4px; 59 | padding: 2px 4px 60 | } 61 | 62 | .prettyprint .pnk { 63 | background: #CFD8DC; 64 | color: #5C707A 65 | } 66 | 67 | .prettyprint .blk { 68 | background: #E0E0E0 69 | } 70 | 71 | .prettyprint .otl { 72 | outline: 1px solid rgba(169,169,169,0.56) 73 | } 74 | 75 | .prettyprint .kwd { 76 | color: #D43669 77 | } 78 | 79 | .prettyprint .typ,.prettyprint .tag { 80 | color: #D43669 81 | } 82 | 83 | .prettyprint .str,.prettyprint .atv { 84 | color: #647f11 85 | } 86 | 87 | .prettyprint .atn { 88 | /*color: #647f11*/ 89 | color: #31708f 90 | } 91 | 92 | .prettyprint .com { 93 | color: #647f11 94 | } 95 | 96 | .prettyprint .lit { 97 | color: #647f11 98 | } 99 | 100 | .prettyprint .pun { 101 | color: #7a8b94 102 | } 103 | 104 | .prettyprint .pln { 105 | color: #5C707A 106 | /*color: #8a6d3b*/ 107 | } 108 | 109 | .prettyprint .dec { 110 | color: #647f11 111 | } 112 | 113 | @media print { 114 | .prettyprint { 115 | background: #F5F6F7; 116 | border: none; 117 | box-shadow: none 118 | } 119 | 120 | .prettyprint ol { 121 | background: #F5F6F7 122 | } 123 | 124 | .prettyprint .kwd { 125 | color: #D43669 126 | } 127 | 128 | .prettyprint .typ,.prettyprint .tag { 129 | color: #D43669 130 | } 131 | 132 | .prettyprint .str,.prettyprint .atv { 133 | color: #647f11 134 | } 135 | 136 | .prettyprint .atn { 137 | /*color: #647f11*/ 138 | color: #31708f 139 | } 140 | 141 | .prettyprint .com { 142 | color: #647f11 143 | } 144 | 145 | .prettyprint .lit { 146 | color: #647f11 147 | } 148 | 149 | .prettyprint .pun { 150 | color: #7a8b94 151 | } 152 | 153 | .prettyprint .pln { 154 | color: #5C707A 155 | } 156 | 157 | .prettyprint .dec { 158 | color: #647f11 159 | } 160 | } 161 | 162 | h1 .prettyprint,h2 .prettyprint,h3 .prettyprint,h4 .prettyprint { 163 | background: none; 164 | font-family: Monaco,"Lucida Console",monospace; 165 | color: #253238; 166 | overflow: hidden; 167 | position: relative; 168 | font-size: 15px; 169 | font-weight: 600; 170 | line-height: 24px; 171 | margin: 0; 172 | border: none; 173 | box-shadow: none; 174 | padding: 0 175 | } 176 | 177 | h1 .prettyprint code,h2 .prettyprint code,h3 .prettyprint code,h4 .prettyprint code { 178 | background: none; 179 | font-size: 15px; 180 | padding: 0 181 | } 182 | 183 | h1 .prettyprint .kwd,h2 .prettyprint .kwd,h3 .prettyprint .kwd,h4 .prettyprint .kwd { 184 | color: #253238 185 | } 186 | 187 | h1 .prettyprint .typ,h1 .prettyprint .tag,h2 .prettyprint .typ,h2 .prettyprint .tag,h3 .prettyprint .typ,h3 .prettyprint .tag,h4 .prettyprint .typ,h4 .prettyprint .tag { 188 | color: #B52E31 189 | } 190 | 191 | h1 .prettyprint .str,h1 .prettyprint .atv,h2 .prettyprint .str,h2 .prettyprint .atv,h3 .prettyprint .str,h3 .prettyprint .atv,h4 .prettyprint .str,h4 .prettyprint .atv { 192 | color: #9d8d00 193 | } 194 | 195 | h1 .prettyprint .atn,h2 .prettyprint .atn,h3 .prettyprint .atn,h4 .prettyprint .atn { 196 | color: #71a436 197 | } 198 | 199 | h1 .prettyprint .com,h2 .prettyprint .com,h3 .prettyprint .com,h4 .prettyprint .com { 200 | color: #AFBEC5 201 | } 202 | 203 | h1 .prettyprint .lit,h2 .prettyprint .lit,h3 .prettyprint .lit,h4 .prettyprint .lit { 204 | color: #9d8d00 205 | } 206 | 207 | h1 .prettyprint .pun,h2 .prettyprint .pun,h3 .prettyprint .pun,h4 .prettyprint .pun { 208 | color: #000 209 | } 210 | 211 | h1 .prettyprint .pln,h2 .prettyprint .pln,h3 .prettyprint .pln,h4 .prettyprint .pln { 212 | color: #000 213 | } 214 | 215 | h1 .prettyprint .dec,h2 .prettyprint .dec,h3 .prettyprint .dec,h4 .prettyprint .dec { 216 | color: #8762c6 217 | } 218 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/testing/spec/file-drop.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, DebugElement } from '@angular/core'; 2 | import { By } from '@angular/platform-browser'; 3 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 4 | 5 | import { FileUploader } from '../../file-upload/file-uploader.class'; 6 | import { FileUploadModule } from '../../file-upload/file-upload.module'; 7 | import { FileDropDirective } from '../../file-upload/file-drop.directive'; 8 | 9 | @Component({ 10 | selector: 'container', 11 | template: `
` 15 | }) 16 | export class ContainerComponent { 17 | public get url(): string { return 'localhost:3000'; } 18 | public uploader: FileUploader = new FileUploader({ url: this.url }); 19 | } 20 | 21 | describe('Directive: FileDropDirective', () => { 22 | 23 | let fixture: ComponentFixture; 24 | let hostComponent: ContainerComponent; 25 | let directiveElement: DebugElement; 26 | let fileDropDirective: FileDropDirective; 27 | 28 | beforeEach(() => { 29 | TestBed.configureTestingModule({ 30 | imports: [ FileUploadModule ], 31 | declarations: [ ContainerComponent, FileDropDirective ], 32 | providers: [ ContainerComponent ] 33 | }); 34 | }); 35 | 36 | beforeEach(() => { 37 | fixture = TestBed.createComponent(ContainerComponent); 38 | hostComponent = fixture.componentInstance; 39 | 40 | fixture.detectChanges(); 41 | 42 | directiveElement = fixture.debugElement.query(By.directive(FileDropDirective)); 43 | fileDropDirective = directiveElement.injector.get(FileDropDirective) as FileDropDirective; 44 | }); 45 | 46 | it('can be initialized', () => { 47 | expect(fixture).toBeDefined(); 48 | expect(hostComponent).toBeDefined(); 49 | expect(fileDropDirective).toBeDefined(); 50 | }); 51 | 52 | it('can set file uploader', () => { 53 | expect(fileDropDirective.uploader).toBe(hostComponent.uploader); 54 | }); 55 | 56 | it('can get uploader options', () => { 57 | const options = fileDropDirective.getOptions(); 58 | 59 | // Check url set through binding 60 | // Check default options 61 | expect(options).toBeTruthy(); 62 | if (options) { 63 | expect(options.url).toBe(hostComponent.url); 64 | expect(options.autoUpload).toBeFalsy(); 65 | expect(options.isHTML5).toBeTruthy(); 66 | expect(options.removeAfterUpload).toBeFalsy(); 67 | expect(options.disableMultipart).toBeFalsy(); 68 | } 69 | }); 70 | 71 | it('can get filters', () => { 72 | const filters = fileDropDirective.getFilters(); 73 | 74 | // TODO: Update test once implemented 75 | expect(filters).toBeFalsy(); 76 | }); 77 | 78 | it('handles drop event', () => { 79 | const drop = jest.spyOn(fileDropDirective, 'onDrop'); 80 | directiveElement.triggerEventHandler('drop', getFakeEventData()); 81 | 82 | expect(drop).toHaveBeenCalled(); 83 | }); 84 | 85 | it('adds file to upload', () => { 86 | let addToQueue; 87 | if (fileDropDirective.uploader?.addToQueue) { 88 | addToQueue = jest.spyOn(fileDropDirective.uploader, 'addToQueue'); 89 | } 90 | 91 | let fileOverData; 92 | fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); 93 | 94 | let fileDropData; 95 | fileDropDirective.onFileDrop.subscribe((data: File[]) => fileDropData = data); 96 | 97 | fileDropDirective.onDrop(getFakeEventData()); 98 | 99 | const uploadedFiles = getFakeEventData().dataTransfer.files; 100 | 101 | expect(addToQueue).toHaveBeenCalledWith(uploadedFiles, fileDropDirective.getOptions(), fileDropDirective.getFilters()); 102 | expect(fileOverData).toBeFalsy(); 103 | expect(fileDropData).toEqual(uploadedFiles); 104 | }); 105 | 106 | it('handles dragover event', () => { 107 | jest.spyOn(fileDropDirective, 'onDragOver'); 108 | 109 | directiveElement.triggerEventHandler('dragover', getFakeEventData()); 110 | 111 | expect(fileDropDirective.onDragOver).toHaveBeenCalled(); 112 | }); 113 | 114 | it('handles file over', () => { 115 | let fileOverData; 116 | fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); 117 | 118 | fileDropDirective.onDragOver(getFakeEventData()); 119 | 120 | expect(fileOverData).toBeTruthy(); 121 | }); 122 | 123 | it('handles dragleave event', () => { 124 | jest.spyOn(fileDropDirective, 'onDragLeave'); 125 | 126 | directiveElement.triggerEventHandler('dragleave', getFakeEventData()); 127 | 128 | expect(fileDropDirective.onDragLeave).toHaveBeenCalled(); 129 | }); 130 | 131 | it('handles file over leave', () => { 132 | let fileOverData; 133 | fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); 134 | 135 | fileDropDirective.onDragLeave(getFakeEventData()); 136 | 137 | expect(fileOverData).toBeFalsy(); 138 | }); 139 | }); 140 | 141 | function getFakeEventData(): any { 142 | return { 143 | dataTransfer: { 144 | files: [ 'foo.bar' ], 145 | types: [ 'Files' ] 146 | }, 147 | preventDefault: () => undefined, 148 | stopPropagation: () => undefined 149 | }; 150 | } 151 | -------------------------------------------------------------------------------- /apps/demo/src/app/components/file-upload/simple-demo.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 10 | 15 | 16 |
17 | 18 |
19 | 20 |

Select files

21 | 22 |
27 | Base drop zone 28 |
29 | 30 |
35 | Another drop zone 36 |
37 | 38 | Multiple
39 |
40 | 41 | Single
42 | 43 |
44 | 45 |
46 | 47 |

Upload queue

48 |

Queue length: {{ uploader?.queue?.length ? uploader?.queue?.length : 'Empty'}}

49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | @if (uploader?.queue?.length) { 61 | 62 | @for (item of uploader.queue; track item) { 63 | 64 | 65 | @if (uploader.options.isHTML5) { 66 | 67 | } 68 | @if (uploader.options.isHTML5) { 69 | 74 | } 75 | 86 | 100 | 101 | } 102 | 103 | } 104 |
NameSizeProgressStatusActions
{{ item?.file?.name }}{{ item?.file?.size/1024/1024 | number:'.2' }} MB 70 |
71 |
72 |
73 |
76 | @if (item.isSuccess) { 77 | 78 | } 79 | @if (item.isCancel) { 80 | 81 | } 82 | @if (item.isError) { 83 | 84 | } 85 | 87 | 91 | 95 | 99 |
105 | 106 |
107 |
108 | Queue progress: 109 |
110 |
111 |
112 |
113 | 117 | 121 | 125 |
126 | 127 |
128 | 129 |
130 | 131 |

132 | 133 |
134 |
135 |
136 |
Response
137 |
138 | {{ response }} 139 |
140 |
141 |
142 |
143 |
144 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/file-upload/file-type.class.ts: -------------------------------------------------------------------------------- 1 | import { FileLikeObject } from '../index'; 2 | 3 | export class FileType { 4 | /* MS office */ 5 | // tslint:disable-next-line:variable-name 6 | static mime_doc: string[] = [ 7 | 'application/msword', 8 | 'application/msword', 9 | 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 10 | 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 11 | 'application/vnd.ms-word.document.macroEnabled.12', 12 | 'application/vnd.ms-word.template.macroEnabled.12' 13 | ]; 14 | // tslint:disable-next-line:variable-name 15 | static mime_xsl: string[] = [ 16 | 'application/vnd.ms-excel', 17 | 'application/vnd.ms-excel', 18 | 'application/vnd.ms-excel', 19 | 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 20 | 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', 21 | 'application/vnd.ms-excel.sheet.macroEnabled.12', 22 | 'application/vnd.ms-excel.template.macroEnabled.12', 23 | 'application/vnd.ms-excel.addin.macroEnabled.12', 24 | 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' 25 | ]; 26 | // tslint:disable-next-line:variable-name 27 | static mime_ppt: string[] = [ 28 | 'application/vnd.ms-powerpoint', 29 | 'application/vnd.ms-powerpoint', 30 | 'application/vnd.ms-powerpoint', 31 | 'application/vnd.ms-powerpoint', 32 | 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 33 | 'application/vnd.openxmlformats-officedocument.presentationml.template', 34 | 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', 35 | 'application/vnd.ms-powerpoint.addin.macroEnabled.12', 36 | 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', 37 | 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', 38 | 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' 39 | ]; 40 | 41 | /* PSD */ 42 | // tslint:disable-next-line:variable-name 43 | static mime_psd: string[] = [ 44 | 'image/photoshop', 45 | 'image/x-photoshop', 46 | 'image/psd', 47 | 'application/photoshop', 48 | 'application/psd', 49 | 'zz-application/zz-winassoc-psd' 50 | ]; 51 | 52 | /* Compressed files */ 53 | // tslint:disable-next-line:variable-name 54 | static mime_compress: string[] = [ 55 | 'application/x-gtar', 56 | 'application/x-gcompress', 57 | 'application/compress', 58 | 'application/x-tar', 59 | 'application/x-rar-compressed', 60 | 'application/octet-stream', 61 | 'application/x-zip-compressed', 62 | 'application/zip-compressed', 63 | 'application/x-7z-compressed', 64 | 'application/gzip', 65 | 'application/x-bzip2' 66 | ]; 67 | 68 | static getMimeClass(file: FileLikeObject): string { 69 | let mimeClass = 'application'; 70 | if (file?.type && this.mime_psd.indexOf(file.type) !== -1) { 71 | mimeClass = 'image'; 72 | } else if (file?.type?.match('image.*')) { 73 | mimeClass = 'image'; 74 | } else if (file?.type?.match('video.*')) { 75 | mimeClass = 'video'; 76 | } else if (file?.type?.match('audio.*')) { 77 | mimeClass = 'audio'; 78 | } else if (file?.type === 'application/pdf') { 79 | mimeClass = 'pdf'; 80 | } else if (file?.type && this.mime_compress.indexOf(file.type) !== -1) { 81 | mimeClass = 'compress'; 82 | } else if (file?.type && this.mime_doc.indexOf(file.type) !== -1) { 83 | mimeClass = 'doc'; 84 | } else if (file?.type && this.mime_xsl.indexOf(file.type) !== -1) { 85 | mimeClass = 'xls'; 86 | } else if (file?.type && this.mime_ppt.indexOf(file.type) !== -1) { 87 | mimeClass = 'ppt'; 88 | } 89 | if (mimeClass === 'application' && file?.name) { 90 | mimeClass = this.fileTypeDetection(file.name); 91 | } 92 | 93 | return mimeClass; 94 | } 95 | 96 | static fileTypeDetection(inputFilename: string): string { 97 | const types: { [ key: string ]: string } = { 98 | jpg: 'image', 99 | jpeg: 'image', 100 | tif: 'image', 101 | psd: 'image', 102 | bmp: 'image', 103 | png: 'image', 104 | nef: 'image', 105 | tiff: 'image', 106 | cr2: 'image', 107 | dwg: 'image', 108 | cdr: 'image', 109 | ai: 'image', 110 | indd: 'image', 111 | pin: 'image', 112 | cdp: 'image', 113 | skp: 'image', 114 | stp: 'image', 115 | '3dm': 'image', 116 | mp3: 'audio', 117 | wav: 'audio', 118 | wma: 'audio', 119 | mod: 'audio', 120 | m4a: 'audio', 121 | compress: 'compress', 122 | zip: 'compress', 123 | rar: 'compress', 124 | '7z': 'compress', 125 | lz: 'compress', 126 | z01: 'compress', 127 | bz2: 'compress', 128 | gz: 'compress', 129 | pdf: 'pdf', 130 | xls: 'xls', 131 | xlsx: 'xls', 132 | ods: 'xls', 133 | mp4: 'video', 134 | avi: 'video', 135 | wmv: 'video', 136 | mpg: 'video', 137 | mts: 'video', 138 | flv: 'video', 139 | '3gp': 'video', 140 | vob: 'video', 141 | m4v: 'video', 142 | mpeg: 'video', 143 | m2ts: 'video', 144 | mov: 'video', 145 | doc: 'doc', 146 | docx: 'doc', 147 | eps: 'doc', 148 | txt: 'doc', 149 | odt: 'doc', 150 | rtf: 'doc', 151 | ppt: 'ppt', 152 | pptx: 'ppt', 153 | pps: 'ppt', 154 | ppsx: 'ppt', 155 | odp: 'ppt' 156 | }; 157 | 158 | const chunks = inputFilename.split('.'); 159 | if (chunks.length < 2) { 160 | return 'application'; 161 | } 162 | const extension = chunks[ chunks.length - 1 ].toLowerCase(); 163 | if (types[ extension ] === undefined) { 164 | return 'application'; 165 | } else { 166 | return types[ extension ]; 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /apps/demo/src/assets/css/style.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Docs (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under the Creative Commons Attribution 3.0 Unported License. For 5 | * details, see http://creativecommons.org/licenses/by/3.0/. 6 | */ 7 | 8 | .h1, .h2, .h3, h1, h2, h3 { 9 | margin-top: 20px; 10 | margin-bottom: 10px; 11 | } 12 | 13 | .h1, h1 { 14 | font-size: 36px; 15 | } 16 | 17 | td { 18 | vertical-align: middle; 19 | } 20 | 21 | a, .nav-tabs a.nav-link { 22 | text-decoration: none; 23 | color: #6f5499; 24 | } 25 | 26 | .btn-group-lg > .btn, .btn-lg { 27 | font-size: 18px; 28 | } 29 | 30 | section { 31 | padding-top: 30px; 32 | } 33 | 34 | .page-header { 35 | padding-bottom: 9px; 36 | margin: 40px 0 20px; 37 | border-bottom: 1px solid #eee; 38 | } 39 | 40 | .navbar-default .navbar-nav > li > a { 41 | color: #777; 42 | } 43 | 44 | .navbar { 45 | padding: 15px; 46 | background-color: #f8f8f8; 47 | border-color: #e7e7e7; 48 | } 49 | 50 | .navbar-nav .nav-item { 51 | margin-left: 0 !important; 52 | } 53 | 54 | .navbar-brand { 55 | color: #777; 56 | height: 50px; 57 | padding: 15px 15px; 58 | font-size: 18px; 59 | line-height: 20px; 60 | } 61 | 62 | .navbar-nav > li > a:focus, .navbar-default .navbar-nav > li > a:hover { 63 | color: #333; 64 | background-color: transparent; 65 | } 66 | 67 | .bd-pageheader, .bs-docs-masthead { 68 | position: relative; 69 | padding: 30px 0; 70 | color: #cdbfe3; 71 | text-align: center; 72 | text-shadow: 0 1px 0 rgba(0, 0, 0, .1); 73 | background-color: #6f5499; 74 | background-image: -webkit-gradient(linear, left top, left bottom, from(#563d7c), to(#6f5499)); 75 | background-image: -webkit-linear-gradient(top, #563d7c 0, #6f5499 100%); 76 | background-image: -o-linear-gradient(top, #563d7c 0, #6f5499 100%); 77 | background-image: linear-gradient(to bottom, #563d7c 0, #6f5499 100%); 78 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#563d7c', endColorstr='#6F5499', GradientType=0); 79 | background-repeat: repeat-x; 80 | } 81 | 82 | .bd-pageheader { 83 | margin-bottom: 40px; 84 | font-size: 20px; 85 | } 86 | 87 | .bd-pageheader h1 { 88 | margin-top: 0; 89 | color: #fff; 90 | } 91 | 92 | .bd-pageheader p { 93 | margin-bottom: 0; 94 | font-weight: 300; 95 | line-height: 1.4; 96 | } 97 | 98 | .bd-pageheader .btn { 99 | margin: 10px 0; 100 | } 101 | 102 | .card { 103 | border-radius: 0 0 .25rem .25rem; 104 | } 105 | 106 | @media (min-width: 992px) { 107 | .bd-pageheader h1, .bd-pageheader p { 108 | margin-right: 380px; 109 | } 110 | } 111 | 112 | @media (min-width: 768px) { 113 | .bd-pageheader { 114 | padding-top: 60px; 115 | padding-bottom: 60px; 116 | font-size: 24px; 117 | text-align: left; 118 | } 119 | 120 | .bd-pageheader h1 { 121 | font-size: 60px; 122 | line-height: 1; 123 | } 124 | 125 | .navbar-nav > li > a.nav-link { 126 | padding-top: 15px; 127 | padding-bottom: 15px; 128 | font-size: 14px; 129 | } 130 | 131 | .navbar > .container .navbar-brand, .navbar > .container-fluid .navbar-brand { 132 | margin-left: -15px; 133 | } 134 | } 135 | 136 | @media (max-width: 767px) { 137 | .hidden-xs { 138 | display: none !important; 139 | } 140 | 141 | .navbar .container { 142 | width: 100%; 143 | max-width: 100%; 144 | } 145 | .navbar .container, 146 | .navbar .container .navbar-header { 147 | padding: 0; 148 | margin: 0; 149 | } 150 | 151 | table { 152 | border: 0; 153 | } 154 | 155 | table caption { 156 | font-size: 1.3em; 157 | } 158 | 159 | table thead { 160 | border: none; 161 | clip: rect(0 0 0 0); 162 | height: 1px; 163 | margin: -1px; 164 | overflow: hidden; 165 | padding: 0; 166 | position: absolute; 167 | width: 1px; 168 | } 169 | 170 | table tr { 171 | border-bottom: 3px solid #ddd; 172 | display: block; 173 | margin-bottom: .625em; 174 | } 175 | 176 | table td { 177 | border-bottom: 1px solid #ddd; 178 | font-size: .8em; 179 | display: flex; 180 | justify-content: space-between; 181 | align-items: center; 182 | } 183 | 184 | table td::before { 185 | content: attr(data-label); 186 | font-weight: bold; 187 | text-transform: uppercase; 188 | } 189 | 190 | table td:last-child { 191 | border-bottom: 0; 192 | } 193 | 194 | td[data-label="Progress"] .progress { 195 | width: 75%; 196 | } 197 | } 198 | 199 | @media (max-width: 400px) { 200 | code, kbd { 201 | font-size: 60%; 202 | } 203 | } 204 | 205 | /** 206 | * VH and VW units can cause issues on iOS devices: http://caniuse.com/#feat=viewport-units 207 | * 208 | * To overcome this, create media queries that target the width, height, and orientation of iOS devices. 209 | * It isn't optimal, but there is really no other way to solve the problem. In this example, I am fixing 210 | * the height of element '.scrollable-menu' —which is a full width and height cover image. 211 | * 212 | * iOS Resolution Quick Reference: http://www.iosres.com/ 213 | */ 214 | 215 | /** 216 | * iPad with portrait orientation. 217 | */ 218 | @media all and (device-width: 768px) and (device-height: 1024px) and (orientation: portrait) { 219 | .scrollable-menu { 220 | height: 1024px !important; 221 | } 222 | } 223 | 224 | /** 225 | * iPad with landscape orientation. 226 | */ 227 | @media all and (device-width: 768px) and (device-height: 1024px) and (orientation: landscape) { 228 | .scrollable-menu { 229 | height: 768px !important; 230 | } 231 | } 232 | 233 | /** 234 | * iPhone 5 235 | * You can also target devices with aspect ratio. 236 | */ 237 | @media screen and (device-aspect-ratio: 40/71) { 238 | .scrollable-menu { 239 | height: 500px !important; 240 | } 241 | } 242 | 243 | pre { 244 | white-space: pre-wrap; /* CSS 3 */ 245 | white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ 246 | white-space: -pre-wrap; /* Opera 4-6 */ 247 | white-space: -o-pre-wrap; /* Opera 7 */ 248 | word-wrap: break-word; /* Internet Explorer 5.5+ */ 249 | line-height: 1.42857143; 250 | color: #333; 251 | background-color: #f5f5f5; 252 | border: 1px solid #ccc; 253 | border-radius: 4px; 254 | padding: 15px; 255 | } 256 | 257 | pre.prettyprint { 258 | margin-bottom: 0; 259 | } 260 | 261 | 262 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/testing/spec/file-uploader.class.spec.ts: -------------------------------------------------------------------------------- 1 | import { FileLikeObject } from '../../file-upload/file-like-object.class'; 2 | import { FileUploader, FilterFunction } from '../../file-upload/file-uploader.class'; 3 | 4 | describe('FileUploader: onWhenAddingFileFailed', () => { 5 | const fileName = 'file.jpg'; 6 | const fileSize = 1024; 7 | const fileMimeType = 'image/jpg'; 8 | let file: File; 9 | 10 | beforeEach(() => { 11 | file = new File([""], fileName, { type: fileMimeType }); 12 | Object.defineProperty(file, 'size', { value: fileSize }); 13 | }); 14 | 15 | it('does not fire when the file size is less than specified by the maxFileSize filter', () => { 16 | const filterFileSize = fileSize + 1; 17 | const uploader = new FileUploader({ url: '', maxFileSize: filterFileSize }); 18 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 19 | 20 | uploader.addToQueue([file]); 21 | 22 | expect(filterFileSize).toBeGreaterThan(file.size); 23 | expect(onWhenAddingFileFailed).toBeCalledTimes(0); 24 | }); 25 | 26 | it('fires when the file size is greater than specified by the maxFileSize filter', () => { 27 | const filterFileSize = fileSize - 1; 28 | const uploader = new FileUploader({ url: '', maxFileSize: filterFileSize }); 29 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 30 | 31 | uploader.addToQueue([file]); 32 | 33 | expect(filterFileSize).toBeLessThan(file.size); 34 | expect(onWhenAddingFileFailed).toBeCalledTimes(1); 35 | }); 36 | 37 | it('does not fire when the queue size is less than or equal to the specified by queueLimit filter', () => { 38 | const queueLimit = 2; 39 | const uploader = new FileUploader({ url: '', queueLimit: queueLimit }); 40 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 41 | const files = [file, file]; 42 | 43 | uploader.addToQueue([file, file]); 44 | 45 | expect(files.length).toBeLessThanOrEqual(queueLimit); 46 | expect(onWhenAddingFileFailed).toBeCalledTimes(0); 47 | }); 48 | 49 | it('fires when the queue size is greater than the specified by queueLimit filter', () => { 50 | const queueLimit = 1; 51 | const uploader = new FileUploader({ url: '', queueLimit: queueLimit }); 52 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 53 | const files = [file, file]; 54 | 55 | uploader.addToQueue([file, file]); 56 | 57 | expect(files.length).toBeGreaterThan(queueLimit); 58 | expect(onWhenAddingFileFailed).toBeCalledTimes(1); 59 | }); 60 | 61 | it('does not fire when file type matches expected by allowedFileType filter', () => { 62 | const uploader = new FileUploader({ url: '', allowedFileType: ["image"] }); 63 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 64 | 65 | uploader.addToQueue([file]); 66 | 67 | expect(onWhenAddingFileFailed).toBeCalledTimes(0); 68 | }); 69 | 70 | it('fires when file type does not match expected by allowedFileType filter', () => { 71 | const uploader = new FileUploader({ url: '', allowedFileType: ["doc"] }); 72 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 73 | 74 | uploader.addToQueue([file]); 75 | 76 | expect(onWhenAddingFileFailed).toBeCalledTimes(1); 77 | }); 78 | 79 | it('does not fire when file mime type matches expected by allowedMimeType filter', () => { 80 | const filterMimeType = fileMimeType; 81 | const uploader = new FileUploader({ url: '', allowedMimeType: [filterMimeType] }); 82 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 83 | 84 | uploader.addToQueue([file]); 85 | 86 | expect(file.type).toBe(filterMimeType); 87 | expect(onWhenAddingFileFailed).toBeCalledTimes(0); 88 | }); 89 | 90 | it('fires when file mime type does not match expected by allowedMimeType filter', () => { 91 | const filterMimeType = "application/msword"; 92 | const uploader = new FileUploader({ url: '', allowedMimeType: [filterMimeType] }); 93 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 94 | 95 | uploader.addToQueue([file]); 96 | 97 | expect(file.type).not.toBe(filterMimeType); 98 | expect(onWhenAddingFileFailed).toBeCalledTimes(1); 99 | }); 100 | 101 | it('does not fire when a file matches the specified custom filter', () => { 102 | const positiveFilter: FilterFunction = { name: 'positive filter', fn: () => true }; 103 | const uploader = new FileUploader({ url: '', filters: [positiveFilter] }); 104 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 105 | 106 | uploader.addToQueue([file]); 107 | 108 | expect(positiveFilter.fn(new FileLikeObject(file))).toBe(true); 109 | expect(onWhenAddingFileFailed).toBeCalledTimes(0); 110 | }); 111 | 112 | it('fires when a file does not match the specified custom filter', () => { 113 | const negativeFilter: FilterFunction = { name: 'negative filter', fn: () => false }; 114 | const uploader = new FileUploader({ url: '', filters: [negativeFilter] }); 115 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 116 | 117 | uploader.addToQueue([file]); 118 | 119 | expect(negativeFilter.fn(new FileLikeObject(file))).toBe(false); 120 | expect(onWhenAddingFileFailed).toBeCalledTimes(1); 121 | }); 122 | 123 | it('fires only once per file for multiple not matched filters', () => { 124 | const uploader = new FileUploader( 125 | { 126 | url: '', 127 | maxFileSize: fileSize - 1, 128 | queueLimit: 1, 129 | allowedFileType: ["doc"], 130 | allowedMimeType: ["application/msword"], 131 | filters: [{ name: 'positive filter', fn: () => false }] 132 | }); 133 | 134 | const onWhenAddingFileFailed = jest.spyOn(uploader, 'onWhenAddingFileFailed'); 135 | const files = [file, file]; 136 | 137 | uploader.addToQueue(files); 138 | 139 | expect(onWhenAddingFileFailed).toBeCalledTimes(files.length); 140 | }); 141 | }); -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [9.0.0](https://github.com/valor-software/ng2-file-upload/compare/v8.0.0...v9.0.0) (2025-09-04) 2 | 3 | 4 | * Added angular 20 support 5 | 6 | ## [8.0.0](https://github.com/valor-software/ng2-file-upload/compare/v7.0.1...v8.0.0) (2025-01-15) 7 | 8 | 9 | * Added angular 19 support 10 | 11 | 12 | ## [7.0.1](https://github.com/valor-software/ng2-file-upload/compare/v7.0.0...v7.0.1) (2024-07-17) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * **dependencies:** removed excessive parts from peerDependencies ([3a7d086](https://github.com/valor-software/ng2-file-upload/commit/3a7d086927e1ad1e95ee94d4ad7b09fa3834cfc1)) 18 | 19 | 20 | 21 | # [7.0.0](https://github.com/valor-software/ng2-file-upload/compare/v6.0.0...v7.0.0) (2024-07-15) 22 | 23 | 24 | ### Bug Fixes 25 | 26 | * **dependencies:** updated ngx-bootstrap and bootstrap ([bce773c](https://github.com/valor-software/ng2-file-upload/commit/bce773c2e3f2447caaa87d6992ff3e2f65d7c56c)) 27 | * **lint:** updated lint ([09d97db](https://github.com/valor-software/ng2-file-upload/commit/09d97dbb4a1267e9253ad1a0c8742f5256b7cdce)) 28 | * Added angular 18 support 29 | 30 | 31 | 32 | # [6.0.0](https://github.com/valor-software/ng2-file-upload/compare/v5.0.0...v6.0.0) (2024-07-02) 33 | * Added angular 17 support 34 | 35 | 36 | # [5.0.0](https://github.com/valor-software/ng2-file-upload/compare/v4.0.0...v5.0.0) (2023-07-21) 37 | 38 | 39 | ### Features 40 | 41 | * add angular 16 support([#1258](https://github.com/valor-software/ng2-file-upload/issues/1258)) ([1fe752d](https://github.com/valor-software/ng2-file-upload/commit/1fe752d9f0665568dee3340c47f7e0964635ab6a)) 42 | 43 | 44 | 45 | # [3.0.0](https://github.com/valor-software/ng2-file-upload/compare/v2.0.0-3...v3.0.0) (2022-12-12) 46 | 47 | 48 | ### Bug Fixes 49 | 50 | * **chore:** fixed build in yml file ([fc21870](https://github.com/valor-software/ng2-file-upload/commit/fc21870c827166da05307a6fe5f4fdd3808454eb)) 51 | * **chore:** updated publish yml file ([4ee0638](https://github.com/valor-software/ng2-file-upload/commit/4ee06384dd8ddf4097606c542d4c6326e6ee1433)) 52 | * **ci:** fixed release yml file ([6f5ac1c](https://github.com/valor-software/ng2-file-upload/commit/6f5ac1cb94a86540a5a44dd884ae9c4af8e40d00)) 53 | 54 | 55 | ### Features 56 | 57 | * **core:** updated version up to angular 14 and nx 14 ([#1205](https://github.com/valor-software/ng2-file-upload/issues/1205)) ([ad01e31](https://github.com/valor-software/ng2-file-upload/commit/ad01e31cf8258eeaaa3b18625bb0e46992972c1a)) 58 | * **package:** Added support for Angular 13. fixes [#1193](https://github.com/valor-software/ng2-file-upload/issues/1193) ([#1201](https://github.com/valor-software/ng2-file-upload/issues/1201)) ([6608960](https://github.com/valor-software/ng2-file-upload/commit/6608960cecd9f800aae27d8d4f4a21c418a3828a)) 59 | 60 | 61 | 62 | # [3.0.0]() 63 | 64 | Updated the library and test project to Angular 13 65 | 66 | # [2.0.0-3](https://github.com/valor-software/ng2-file-upload/compare/v2.0.0-2...v2.0.0-3) (2021-09-07) 67 | 68 | ### Features 69 | 70 | - **demo:** updated up to bootstrap 5 ([#1186](https://github.com/valor-software/ng2-file-upload/issues/1186)) ([02a1b2a](https://github.com/valor-software/ng2-file-upload/commit/02a1b2a53c331e2088ea05d2202be6eb2b1d051f)) 71 | 72 | # [2.0.0-2](https://github.com/valor-software/ng2-file-upload/compare/v2.0.0-1...v2.0.0-2) (2021-09-03) 73 | 74 | # [2.0.0-1](https://github.com/valor-software/ng2-file-upload/compare/v2.0.0-0...v2.0.0-1) (2021-09-03) 75 | 76 | ### Features 77 | 78 | - **version:** added npm versions ([#1183](https://github.com/valor-software/ng2-file-upload/issues/1183)) ([326e3ac](https://github.com/valor-software/ng2-file-upload/commit/326e3ac1a884f000f57b3fb6e30cd32f5ec4622c)) 79 | 80 | # [2.0.0-0](https://github.com/valor-software/ng2-file-upload/compare/v1.2.0...v2.0.0-0) (2021-09-03) 81 | 82 | ### Bug Fixes 83 | 84 | - **ci:** fix xvfb service issue ([33ac156](https://github.com/valor-software/ng2-file-upload/commit/33ac156208bfcf57851210f037719107e1ca9eb9)) 85 | - **typo:** fix grammatical mistake in readme ([#1119](https://github.com/valor-software/ng2-file-upload/issues/1119)) ([8171bc8](https://github.com/valor-software/ng2-file-upload/commit/8171bc831b69692d04b650be19ff82f04ff56662)) 86 | 87 | ### Features 88 | 89 | - **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/7704e0e970276ebcd8bfefe34bf153f82108a11e)) 90 | 91 | # [1.3.0](https://github.com/valor-software/ng2-file-upload/compare/v1.2.0...v1.3.0) (2021-08-31) 92 | 93 | ### Bug Fixes 94 | 95 | - **ci:** fix xvfb service issue ([33ac156](https://github.com/valor-software/ng2-file-upload/commit/33ac156208bfcf57851210f037719107e1ca9eb9)) 96 | - **style:** delete extra rule ([b5917b9](https://github.com/valor-software/ng2-file-upload/commit/b5917b9fa77e63c4c1b06598abc817b8033730c3)) 97 | - **typo:** fix grammatical mistake in readme ([#1119](https://github.com/valor-software/ng2-file-upload/issues/1119)) ([8171bc8](https://github.com/valor-software/ng2-file-upload/commit/8171bc831b69692d04b650be19ff82f04ff56662)) 98 | 99 | ### Features 100 | 101 | - **bump:** added strict mode, doesn't build in dist, should be resolved ([69cd64d](https://github.com/valor-software/ng2-file-upload/commit/69cd64dc287c9bdd1c35af1062e27ce32a47e977)) 102 | - **core:** added nx ([de738f7](https://github.com/valor-software/ng2-file-upload/commit/de738f7c63d7f37e07019bc596c02e9f4320f563)) 103 | - **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/7704e0e970276ebcd8bfefe34bf153f82108a11e)) 104 | - **upgrade:** updated up to angular 11 tests are failed ([ce9dc20](https://github.com/valor-software/ng2-file-upload/commit/ce9dc20056cc6c7cd58e502af05d7d97043c8f3a)) 105 | 106 | # [1.3.0](https://github.com/valor-software/ng2-file-upload/compare/v1.2.0...v1.3.0) (2021-08-31) 107 | 108 | ### Bug Fixes 109 | 110 | - **ci:** fix xvfb service issue ([33ac156](https://github.com/valor-software/ng2-file-upload/commit/33ac156208bfcf57851210f037719107e1ca9eb9)) 111 | - **style:** delete extra rule ([b5917b9](https://github.com/valor-software/ng2-file-upload/commit/b5917b9fa77e63c4c1b06598abc817b8033730c3)) 112 | - **typo:** fix grammatical mistake in readme ([#1119](https://github.com/valor-software/ng2-file-upload/issues/1119)) ([8171bc8](https://github.com/valor-software/ng2-file-upload/commit/8171bc831b69692d04b650be19ff82f04ff56662)) 113 | 114 | ### Features 115 | 116 | - **bump:** added strict mode, doesn't build in dist, should be resolved ([69cd64d](https://github.com/valor-software/ng2-file-upload/commit/69cd64dc287c9bdd1c35af1062e27ce32a47e977)) 117 | - **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/7704e0e970276ebcd8bfefe34bf153f82108a11e)) 118 | - **upgrade:** updated up to angular 11 tests are failed ([ce9dc20](https://github.com/valor-software/ng2-file-upload/commit/ce9dc20056cc6c7cd58e502af05d7d97043c8f3a)) 119 | 120 | 121 | 122 | # [1.3.0](https://github.com/valor-software/ng2-file-upload/compare/v1.2.0...v1.3.0) (2017-11-25) 123 | 124 | ### Features 125 | 126 | - **file-upload:** Add response and function to modify the request body ([#901](https://github.com/valor-software/ng2-file-upload/pull/901)) 127 | - **file-upload** add file type .zip ([#911](https://github.com/valor-software/ng2-file-upload/pull/911)) 128 | 129 | ### Bug Fixes 130 | 131 | - **file-uploader** Update: setOptions ([#904](https://github.com/valor-software/ng2-file-upload/pull/904)) 132 | - **docs** Fix correct path for isHTML5 option ([#844](https://github.com/valor-software/ng2-file-upload/pull/844)) 133 | - **docs** Added onFileDrop() event to documentation ([#857](https://github.com/valor-software/ng2-file-upload/pull/857)) 134 | 135 | 136 | 137 | ## [1.2.1](https://github.com/valor-software/ng2-file-upload/compare/v1.2.0...v1.2.1) (2017-04-10) 138 | 139 | ### Features 140 | 141 | - **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)) 142 | 143 | 144 | 145 | # [1.2.0](https://github.com/valor-software/ng2-file-upload/compare/v1.1.3-0...v1.2.0) (2017-01-17) 146 | 147 | ### Bug Fixes 148 | 149 | - **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) 150 | 151 | ### Features 152 | 153 | - **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)) 154 | - **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)) 155 | - **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)) 156 | 157 | 158 | 159 | ## [1.1.3-0](https://github.com/valor-software/ng2-file-upload/compare/v1.1.2...v1.1.3-0) (2016-10-19) 160 | 161 | ### Bug Fixes 162 | 163 | - **typing:** added authTokenHeader property to options and file upload class ([b55c852](https://github.com/valor-software/ng2-file-upload/commit/b55c852)) 164 | 165 | ### Features 166 | 167 | - **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) 168 | - **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)) 169 | 170 | 171 | 172 | ## [1.1.2](https://github.com/valor-software/ng2-file-upload/compare/v1.1.1...v1.1.2) (2016-10-17) 173 | 174 | ### Features 175 | 176 | - **package:** allow of ng2 v2.0._ and v2._.\* ([87395e6](https://github.com/valor-software/ng2-file-upload/commit/87395e6)) 177 | 178 | 179 | 180 | ## [1.1.1](https://github.com/valor-software/ng2-file-upload/compare/v1.0.3...v1.1.1) (2016-10-17) 181 | 182 | ### Bug Fixes 183 | 184 | - **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)) 185 | - **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)) 186 | 187 | ### Features 188 | 189 | - **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)) 190 | - **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)) 191 | - **package:** updated to typescript 2 ([4fef496](https://github.com/valor-software/ng2-file-upload/commit/4fef496)) 192 | 193 | 194 | 195 | # [1.1.0](https://github.com/valor-software/ng2-file-upload/compare/v1.0.3...v1.1.0) (2016-09-21) 196 | 197 | ### Bug Fixes 198 | 199 | - **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)) 200 | - **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)) 201 | 202 | ### Features 203 | 204 | - **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)) 205 | - **package:** updated to typescript 2 ([4fef496](https://github.com/valor-software/ng2-file-upload/commit/4fef496)) 206 | 207 | 208 | 209 | ## [1.0.3](https://github.com/valor-software/ng2-file-upload/compare/v1.0.2...v1.0.3) (2016-05-12) 210 | 211 | 212 | 213 | ## 1.0.2 (2016-05-12) 214 | 215 | ### Bug Fixes 216 | 217 | - **upload:** merge fix and get filters fix ([ef6091c](https://github.com/valor-software/ng2-file-upload/commit/ef6091c)) 218 | 219 | ### Chores 220 | 221 | - **build:** ng2 style guide applied ([aee69d8](https://github.com/valor-software/ng2-file-upload/commit/aee69d8)) 222 | 223 | ### Features 224 | 225 | - **package:** upgrade to angular 2.0.0-rc.1 ([#176](https://github.com/valor-software/ng2-file-upload/issues/176)) ([13c5c35](https://github.com/valor-software/ng2-file-upload/commit/13c5c35)), closes [#180](https://github.com/valor-software/ng2-file-upload/issues/180) 226 | 227 | ### BREAKING CHANGES 228 | 229 | - directives and selectors renamed to ng2FileSelect and ng2FileDrop 230 | -------------------------------------------------------------------------------- /apps/demo/src/assets/js/prettify.min.js: -------------------------------------------------------------------------------- 1 | !function () { var q = null; window.PR_SHOULD_USE_CONTINUATION = !0; 2 | (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 = 3 | 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])), 4 | 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 && 5 | (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 = { 6 | b: 8, t: 9, n: 10, v: 11, 7 | f: 12, r: 13 8 | }, 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] = 9 | 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)]; 10 | 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 = 11 | 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])*(?:`|$))/, 12 | 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', 13 | /^#[^\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' + 14 | 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]?/, 15 | 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 = 16 | 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'); 17 | 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*= 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'], 20 | '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'], 21 | 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'], 22 | 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/, 23 | 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', /^[^]*(?:>|$)/], ['com', /^<\!--[\S\s]*?(?:--\>|$)/], ['lang-', /^<\?([\S\s]+?)(?:\?>|$)/], ['lang-', /^<%([\S\s]+?)(?:%>|$)/], ['pun', /^(?:<[%?]|[%?]>)/], ['lang-', 24 | /^]*>([\S\s]+?)<\/xmp\b[^>]*>/i], ['lang-js', /^]*>([\S\s]*?)(<\/script\b[^>]*>)/i], ['lang-css', /^]*>([\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', /^[/<->]+/], 25 | ['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}), 26 | ['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({ 27 | keywords: Q, 28 | hashComments: !0, multiLineStrings: !0, regexLiterals: !0 29 | }), ['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']); 30 | p(C([], [['str', /^[\S\s]+/]]), ['regex']); var Y = D.PR = { 31 | 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 = '
' + a + '
'; b = b.firstChild; g && J(b, g, !0); K({h: d, j: g, c: b, i: 1}); 32 | 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) && 33 | 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 = 34 | {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, 35 | h = {}; g(); } 36 | }; typeof define === 'function' && define.amd && define('google-code-prettify', [], function () { return Y; }); })(); }(); 37 | -------------------------------------------------------------------------------- /libs/ng2-file-upload/file-upload/file-uploader.class.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from '@angular/core'; 2 | import { FileLikeObject } from './file-like-object.class'; 3 | import { FileItem } from './file-item.class'; 4 | import { FileType } from './file-type.class'; 5 | 6 | function isFile(value: any): boolean { 7 | return (File && value instanceof File); 8 | } 9 | 10 | export interface Headers { 11 | name: string; 12 | value: string; 13 | } 14 | 15 | export interface ParsedResponseHeaders { [ headerFieldName: string ]: string } 16 | 17 | export interface FilterFunction { 18 | name: string; 19 | fn(item: FileLikeObject, options?: FileUploaderOptions): boolean; 20 | } 21 | 22 | export interface FileUploaderOptions { 23 | allowedMimeType?: string[]; 24 | allowedFileType?: string[]; 25 | autoUpload?: boolean; 26 | isHTML5?: boolean; 27 | filters?: FilterFunction[]; 28 | headers?: Headers[]; 29 | method?: string; 30 | authToken?: string; 31 | maxFileSize?: number; 32 | queueLimit?: number; 33 | removeAfterUpload?: boolean; 34 | url: string; 35 | disableMultipart?: boolean; 36 | itemAlias?: string; 37 | authTokenHeader?: string; 38 | additionalParameter?: { [ key: string ]: any }; 39 | parametersBeforeFiles?: boolean; 40 | // eslint-disable-next-line 41 | formatDataFunction?: Function; 42 | formatDataFunctionIsAsync?: boolean; 43 | } 44 | 45 | export class FileUploader { 46 | 47 | authToken?: string; 48 | isUploading = false; 49 | queue: FileItem[] = []; 50 | progress = 0; 51 | _nextIndex = 0; 52 | autoUpload: any; 53 | authTokenHeader?: string; 54 | response: EventEmitter; 55 | 56 | options: FileUploaderOptions = { 57 | autoUpload: false, 58 | isHTML5: true, 59 | filters: [], 60 | removeAfterUpload: false, 61 | disableMultipart: false, 62 | formatDataFunction: (item: FileItem) => item._file, 63 | formatDataFunctionIsAsync: false, 64 | url: '' 65 | }; 66 | 67 | protected _failFilterIndex?: number; 68 | 69 | constructor(options: FileUploaderOptions) { 70 | this.setOptions(options); 71 | this.response = new EventEmitter(); 72 | } 73 | 74 | setOptions(options: FileUploaderOptions): void { 75 | this.options = Object.assign(this.options, options); 76 | 77 | this.authToken = this.options.authToken; 78 | this.authTokenHeader = this.options.authTokenHeader || 'Authorization'; 79 | this.autoUpload = this.options.autoUpload; 80 | this.options.filters?.unshift({ name: 'queueLimit', fn: this._queueLimitFilter }); 81 | 82 | if (this.options.maxFileSize) { 83 | this.options.filters?.unshift({ name: 'fileSize', fn: this._fileSizeFilter }); 84 | } 85 | 86 | if (this.options.allowedFileType) { 87 | this.options.filters?.unshift({ name: 'fileType', fn: this._fileTypeFilter }); 88 | } 89 | 90 | if (this.options.allowedMimeType) { 91 | this.options.filters?.unshift({ name: 'mimeType', fn: this._mimeTypeFilter }); 92 | } 93 | 94 | for (let i = 0; i < this.queue.length; i++) { 95 | this.queue[ i ].url = this.options.url; 96 | } 97 | } 98 | 99 | addToQueue(files: File[], _options?: FileUploaderOptions, filters?: [] | string): void { 100 | let options = _options; 101 | const list: File[] = []; 102 | for (const file of files) { 103 | list.push(file); 104 | } 105 | const arrayOfFilters = this._getFilters(filters); 106 | const count = this.queue.length; 107 | const addedFileItems: FileItem[] = []; 108 | list.map((some: File) => { 109 | if (!options) { 110 | options = this.options; 111 | } 112 | 113 | const temp = new FileLikeObject(some); 114 | if (this._isValidFile(temp, arrayOfFilters, options)) { 115 | const fileItem = new FileItem(this, some, options); 116 | addedFileItems.push(fileItem); 117 | this.queue.push(fileItem); 118 | this._onAfterAddingFile(fileItem); 119 | } else { 120 | if (typeof this._failFilterIndex === 'number' && this._failFilterIndex >= 0) { 121 | const filter = arrayOfFilters[ this._failFilterIndex ]; 122 | this._onWhenAddingFileFailed(temp, filter, options); 123 | } 124 | } 125 | }); 126 | if (this.queue.length !== count) { 127 | this._onAfterAddingAll(addedFileItems); 128 | this.progress = this._getTotalProgress(); 129 | } 130 | this._render(); 131 | if (this.options.autoUpload) { 132 | this.uploadAll(); 133 | } 134 | } 135 | 136 | removeFromQueue(value: FileItem): void { 137 | const index = this.getIndexOfItem(value); 138 | const item = this.queue[ index ]; 139 | if (item.isUploading) { 140 | item.cancel(); 141 | } 142 | this.queue.splice(index, 1); 143 | this.progress = this._getTotalProgress(); 144 | } 145 | 146 | clearQueue(): void { 147 | while (this.queue.length) { 148 | this.queue[ 0 ].remove(); 149 | } 150 | this.progress = 0; 151 | } 152 | 153 | uploadItem(value: FileItem): void { 154 | const index = this.getIndexOfItem(value); 155 | const item = this.queue[ index ]; 156 | const transport = this.options.isHTML5 ? '_xhrTransport' : '_iframeTransport'; 157 | item._prepareToUploading(); 158 | if (this.isUploading) { 159 | return; 160 | } 161 | this.isUploading = true; 162 | (this as any)[ transport ](item); 163 | } 164 | 165 | cancelItem(value: FileItem): void { 166 | const index = this.getIndexOfItem(value); 167 | const item = this.queue[ index ]; 168 | const prop = this.options.isHTML5 ? item._xhr : item._form; 169 | if (item && item.isUploading) { 170 | prop.abort(); 171 | } 172 | } 173 | 174 | uploadAll(): void { 175 | const items = this.getNotUploadedItems().filter((item: FileItem) => !item.isUploading); 176 | if (!items.length) { 177 | return; 178 | } 179 | items.map((item: FileItem) => item._prepareToUploading()); 180 | items[ 0 ].upload(); 181 | } 182 | 183 | cancelAll(): void { 184 | const items = this.getNotUploadedItems(); 185 | items.map((item: FileItem) => item.cancel()); 186 | } 187 | 188 | isFile(value: any): boolean { 189 | return isFile(value); 190 | } 191 | 192 | isFileLikeObject(value: any): boolean { 193 | return value instanceof FileLikeObject; 194 | } 195 | 196 | getIndexOfItem(value: any): number { 197 | return typeof value === 'number' ? value : this.queue.indexOf(value); 198 | } 199 | 200 | getNotUploadedItems(): any[] { 201 | return this.queue.filter((item: FileItem) => !item.isUploaded); 202 | } 203 | 204 | getReadyItems(): any[] { 205 | return this.queue 206 | .filter((item: FileItem) => (item.isReady && !item.isUploading)) 207 | .sort((item1: any, item2: any) => item1.index - item2.index); 208 | } 209 | 210 | onAfterAddingAll(fileItems: any): any { 211 | return { fileItems }; 212 | } 213 | 214 | onBuildItemForm(fileItem: FileItem, form: any): any { 215 | return { fileItem, form }; 216 | } 217 | 218 | onAfterAddingFile(fileItem: FileItem): any { 219 | return { fileItem }; 220 | } 221 | 222 | onWhenAddingFileFailed(item: FileLikeObject, filter: any, options: any): any { 223 | return { item, filter, options }; 224 | } 225 | 226 | onBeforeUploadItem(fileItem: FileItem): any { 227 | return { fileItem }; 228 | } 229 | 230 | onProgressItem(fileItem: FileItem, progress: any): any { 231 | return { fileItem, progress }; 232 | } 233 | 234 | onProgressAll(progress: any): any { 235 | return { progress }; 236 | } 237 | 238 | onSuccessItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any { 239 | return { item, response, status, headers }; 240 | } 241 | 242 | onErrorItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any { 243 | return { item, response, status, headers }; 244 | } 245 | 246 | onCancelItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any { 247 | return { item, response, status, headers }; 248 | } 249 | 250 | onCompleteItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any { 251 | return { item, response, status, headers }; 252 | } 253 | 254 | onCompleteAll(): any { 255 | return void 0; 256 | } 257 | 258 | _mimeTypeFilter(item: FileLikeObject): boolean { 259 | return !(item?.type && this.options.allowedMimeType && this.options.allowedMimeType?.indexOf(item.type) === -1); 260 | } 261 | 262 | _fileSizeFilter(item: FileLikeObject): boolean { 263 | return !(this.options.maxFileSize && item.size > this.options.maxFileSize); 264 | } 265 | 266 | _fileTypeFilter(item: FileLikeObject): boolean { 267 | return !(this.options.allowedFileType && 268 | this.options.allowedFileType.indexOf(FileType.getMimeClass(item)) === -1); 269 | } 270 | 271 | _onErrorItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void { 272 | item._onError(response, status, headers); 273 | this.onErrorItem(item, response, status, headers); 274 | } 275 | 276 | _onCompleteItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void { 277 | item._onComplete(response, status, headers); 278 | this.onCompleteItem(item, response, status, headers); 279 | const nextItem = this.getReadyItems()[ 0 ]; 280 | this.isUploading = false; 281 | if (nextItem) { 282 | nextItem.upload(); 283 | 284 | return; 285 | } 286 | this.onCompleteAll(); 287 | this.progress = this._getTotalProgress(); 288 | this._render(); 289 | } 290 | 291 | protected _headersGetter(parsedHeaders: ParsedResponseHeaders): any { 292 | return (name: any): any => { 293 | if (name) { 294 | return parsedHeaders[ name.toLowerCase() ] || undefined; 295 | } 296 | 297 | return parsedHeaders; 298 | }; 299 | } 300 | 301 | protected _xhrTransport(item: FileItem): any { 302 | // tslint:disable-next-line:no-this-assignment 303 | // eslint-disable-next-line @typescript-eslint/no-this-alias 304 | const that = this; 305 | const xhr = item._xhr = new XMLHttpRequest(); 306 | let sendable: any; 307 | this._onBeforeUploadItem(item); 308 | 309 | if (typeof item._file.size !== 'number') { 310 | throw new TypeError('The file specified is no longer valid'); 311 | } 312 | if (!this.options.disableMultipart) { 313 | sendable = new FormData(); 314 | this._onBuildItemForm(item, sendable); 315 | const appendFile = () => sendable.append(item.alias, item._file, item.file.name); 316 | if (!this.options.parametersBeforeFiles) { 317 | appendFile(); 318 | } 319 | 320 | // For AWS, Additional Parameters must come BEFORE Files 321 | if (this.options.additionalParameter !== undefined) { 322 | Object.keys(this.options.additionalParameter).forEach((key: string) => { 323 | let paramVal = this.options.additionalParameter?.[ key ]; 324 | // Allow an additional parameter to include the filename 325 | if (typeof paramVal === 'string' && paramVal.indexOf('{{file_name}}') >= 0 && item.file?.name) { 326 | paramVal = paramVal.replace('{{file_name}}', item.file.name); 327 | } 328 | sendable.append(key, paramVal); 329 | }); 330 | } 331 | 332 | if (appendFile && this.options.parametersBeforeFiles) { 333 | appendFile(); 334 | } 335 | } else { 336 | if (this.options.formatDataFunction) { 337 | sendable = this.options.formatDataFunction(item); 338 | } 339 | } 340 | 341 | xhr.upload.onprogress = (event: any) => { 342 | const progress = Math.round(event.lengthComputable ? event.loaded * 100 / event.total : 0); 343 | this._onProgressItem(item, progress); 344 | }; 345 | xhr.onload = () => { 346 | const headers = this._parseHeaders(xhr.getAllResponseHeaders()); 347 | const response = this._transformResponse(xhr.response); 348 | const gist = this._isSuccessCode(xhr.status) ? 'Success' : 'Error'; 349 | const method = `_on${gist}Item`; 350 | (this as any)[ method ](item, response, xhr.status, headers); 351 | this._onCompleteItem(item, response, xhr.status, headers); 352 | }; 353 | xhr.onerror = () => { 354 | const headers = this._parseHeaders(xhr.getAllResponseHeaders()); 355 | const response = this._transformResponse(xhr.response); 356 | this._onErrorItem(item, response, xhr.status, headers); 357 | this._onCompleteItem(item, response, xhr.status, headers); 358 | }; 359 | xhr.onabort = () => { 360 | const headers = this._parseHeaders(xhr.getAllResponseHeaders()); 361 | const response = this._transformResponse(xhr.response); 362 | this._onCancelItem(item, response, xhr.status, headers); 363 | this._onCompleteItem(item, response, xhr.status, headers); 364 | }; 365 | if (item.method && item.url) { 366 | xhr.open(item.method, item.url, true); 367 | } 368 | xhr.withCredentials = item.withCredentials; 369 | if (this.options.headers) { 370 | for (const header of this.options.headers) { 371 | xhr.setRequestHeader(header.name, header.value); 372 | } 373 | } 374 | if (item.headers.length) { 375 | for (const header of item.headers) { 376 | xhr.setRequestHeader(header.name, header.value); 377 | } 378 | } 379 | if (this.authToken && this.authTokenHeader) { 380 | xhr.setRequestHeader(this.authTokenHeader, this.authToken); 381 | } 382 | xhr.onreadystatechange = function () { 383 | if (xhr.readyState == XMLHttpRequest.DONE) { 384 | that.response.emit(xhr.responseText); 385 | } 386 | }; 387 | if (this.options.formatDataFunctionIsAsync) { 388 | sendable.then( 389 | (result: any) => xhr.send(JSON.stringify(result)) 390 | ); 391 | } else { 392 | xhr.send(sendable); 393 | } 394 | this._render(); 395 | } 396 | 397 | protected _getTotalProgress(value = 0): number { 398 | if (this.options.removeAfterUpload) { 399 | return value; 400 | } 401 | const notUploaded = this.getNotUploadedItems().length; 402 | const uploaded = notUploaded ? this.queue.length - notUploaded : this.queue.length; 403 | const ratio = 100 / this.queue.length; 404 | const current = value * ratio / 100; 405 | return Math.round(uploaded * ratio + current); 406 | } 407 | 408 | protected _getFilters(filters?: FilterFunction[] | string): FilterFunction[] | [] { 409 | if (!filters) { 410 | return this.options?.filters || []; 411 | } 412 | if (Array.isArray(filters)) { 413 | return filters; 414 | } 415 | if (typeof filters === 'string') { 416 | const names = filters.match(/[^\s,]+/g); 417 | 418 | return this.options?.filters || [] 419 | .filter((filter: any) => names?.indexOf(filter.name) !== -1); 420 | } 421 | 422 | return this.options?.filters || []; 423 | } 424 | 425 | protected _render(): any { 426 | return void 0; 427 | } 428 | 429 | protected _queueLimitFilter(): boolean { 430 | return this.options.queueLimit === undefined || this.queue.length < this.options.queueLimit; 431 | } 432 | 433 | protected _isValidFile(file: FileLikeObject, filters: FilterFunction[], options: FileUploaderOptions): boolean { 434 | this._failFilterIndex = -1; 435 | 436 | return !filters.length ? true : filters.every((filter: FilterFunction) => { 437 | if (typeof this._failFilterIndex === 'number') { 438 | this._failFilterIndex++; 439 | } 440 | 441 | return filter.fn.call(this, file, options); 442 | }); 443 | } 444 | 445 | protected _isSuccessCode(status: number): boolean { 446 | return (status >= 200 && status < 300) || status === 304; 447 | } 448 | 449 | protected _transformResponse(response: string): string { 450 | return response; 451 | } 452 | 453 | protected _parseHeaders(headers: string): ParsedResponseHeaders { 454 | const parsed: any = {}; 455 | let key: any; 456 | let val: any; 457 | let i: any; 458 | if (!headers) { 459 | return parsed; 460 | } 461 | headers.split('\n').map((line: any) => { 462 | i = line.indexOf(':'); 463 | key = line.slice(0, i).trim().toLowerCase(); 464 | val = line.slice(i + 1).trim(); 465 | if (key) { 466 | parsed[ key ] = parsed[ key ] ? parsed[ key ] + ', ' + val : val; 467 | } 468 | }); 469 | 470 | return parsed; 471 | } 472 | 473 | protected _onWhenAddingFileFailed(item: FileLikeObject, filter: any, options: any): void { 474 | this.onWhenAddingFileFailed(item, filter, options); 475 | } 476 | 477 | protected _onAfterAddingFile(item: FileItem): void { 478 | this.onAfterAddingFile(item); 479 | } 480 | 481 | protected _onAfterAddingAll(items: any): void { 482 | this.onAfterAddingAll(items); 483 | } 484 | 485 | protected _onBeforeUploadItem(item: FileItem): void { 486 | item._onBeforeUpload(); 487 | this.onBeforeUploadItem(item); 488 | } 489 | 490 | protected _onBuildItemForm(item: FileItem, form: any): void { 491 | item._onBuildForm(form); 492 | this.onBuildItemForm(item, form); 493 | } 494 | 495 | protected _onProgressItem(item: FileItem, progress: any): void { 496 | const total = this._getTotalProgress(progress); 497 | this.progress = total; 498 | item._onProgress(progress); 499 | this.onProgressItem(item, progress); 500 | this.onProgressAll(total); 501 | this._render(); 502 | } 503 | 504 | protected _onSuccessItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void { 505 | item._onSuccess(response, status, headers); 506 | this.onSuccessItem(item, response, status, headers); 507 | } 508 | 509 | protected _onCancelItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void { 510 | item._onCancel(response, status, headers); 511 | this.onCancelItem(item, response, status, headers); 512 | } 513 | } 514 | -------------------------------------------------------------------------------- /apps/demo/src/assets/css/glyphicons.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Glyphicons Halflings'; 3 | 4 | src: url('../fonts/glyphicons-halflings-regular.eot'); 5 | src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); 6 | } 7 | .glyphicon { 8 | position: relative; 9 | top: 1px; 10 | display: inline-block; 11 | font-family: 'Glyphicons Halflings'; 12 | font-style: normal; 13 | font-weight: normal; 14 | line-height: 1; 15 | 16 | -webkit-font-smoothing: antialiased; 17 | -moz-osx-font-smoothing: grayscale; 18 | } 19 | .glyphicon-asterisk:before { 20 | content: "\2a"; 21 | } 22 | .glyphicon-plus:before { 23 | content: "\2b"; 24 | } 25 | .glyphicon-euro:before, 26 | .glyphicon-eur:before { 27 | content: "\20ac"; 28 | } 29 | .glyphicon-minus:before { 30 | content: "\2212"; 31 | } 32 | .glyphicon-cloud:before { 33 | content: "\2601"; 34 | } 35 | .glyphicon-envelope:before { 36 | content: "\2709"; 37 | } 38 | .glyphicon-pencil:before { 39 | content: "\270f"; 40 | } 41 | .glyphicon-glass:before { 42 | content: "\e001"; 43 | } 44 | .glyphicon-music:before { 45 | content: "\e002"; 46 | } 47 | .glyphicon-search:before { 48 | content: "\e003"; 49 | } 50 | .glyphicon-heart:before { 51 | content: "\e005"; 52 | } 53 | .glyphicon-star:before { 54 | content: "\e006"; 55 | } 56 | .glyphicon-star-empty:before { 57 | content: "\e007"; 58 | } 59 | .glyphicon-user:before { 60 | content: "\e008"; 61 | } 62 | .glyphicon-film:before { 63 | content: "\e009"; 64 | } 65 | .glyphicon-th-large:before { 66 | content: "\e010"; 67 | } 68 | .glyphicon-th:before { 69 | content: "\e011"; 70 | } 71 | .glyphicon-th-list:before { 72 | content: "\e012"; 73 | } 74 | .glyphicon-ok:before { 75 | content: "\e013"; 76 | } 77 | .glyphicon-remove:before { 78 | content: "\e014"; 79 | } 80 | .glyphicon-zoom-in:before { 81 | content: "\e015"; 82 | } 83 | .glyphicon-zoom-out:before { 84 | content: "\e016"; 85 | } 86 | .glyphicon-off:before { 87 | content: "\e017"; 88 | } 89 | .glyphicon-signal:before { 90 | content: "\e018"; 91 | } 92 | .glyphicon-cog:before { 93 | content: "\e019"; 94 | } 95 | .glyphicon-trash:before { 96 | content: "\e020"; 97 | } 98 | .glyphicon-home:before { 99 | content: "\e021"; 100 | } 101 | .glyphicon-file:before { 102 | content: "\e022"; 103 | } 104 | .glyphicon-time:before { 105 | content: "\e023"; 106 | } 107 | .glyphicon-road:before { 108 | content: "\e024"; 109 | } 110 | .glyphicon-download-alt:before { 111 | content: "\e025"; 112 | } 113 | .glyphicon-download:before { 114 | content: "\e026"; 115 | } 116 | .glyphicon-upload:before { 117 | content: "\e027"; 118 | } 119 | .glyphicon-inbox:before { 120 | content: "\e028"; 121 | } 122 | .glyphicon-play-circle:before { 123 | content: "\e029"; 124 | } 125 | .glyphicon-repeat:before { 126 | content: "\e030"; 127 | } 128 | .glyphicon-refresh:before { 129 | content: "\e031"; 130 | } 131 | .glyphicon-list-alt:before { 132 | content: "\e032"; 133 | } 134 | .glyphicon-lock:before { 135 | content: "\e033"; 136 | } 137 | .glyphicon-flag:before { 138 | content: "\e034"; 139 | } 140 | .glyphicon-headphones:before { 141 | content: "\e035"; 142 | } 143 | .glyphicon-volume-off:before { 144 | content: "\e036"; 145 | } 146 | .glyphicon-volume-down:before { 147 | content: "\e037"; 148 | } 149 | .glyphicon-volume-up:before { 150 | content: "\e038"; 151 | } 152 | .glyphicon-qrcode:before { 153 | content: "\e039"; 154 | } 155 | .glyphicon-barcode:before { 156 | content: "\e040"; 157 | } 158 | .glyphicon-tag:before { 159 | content: "\e041"; 160 | } 161 | .glyphicon-tags:before { 162 | content: "\e042"; 163 | } 164 | .glyphicon-book:before { 165 | content: "\e043"; 166 | } 167 | .glyphicon-bookmark:before { 168 | content: "\e044"; 169 | } 170 | .glyphicon-print:before { 171 | content: "\e045"; 172 | } 173 | .glyphicon-camera:before { 174 | content: "\e046"; 175 | } 176 | .glyphicon-font:before { 177 | content: "\e047"; 178 | } 179 | .glyphicon-bold:before { 180 | content: "\e048"; 181 | } 182 | .glyphicon-italic:before { 183 | content: "\e049"; 184 | } 185 | .glyphicon-text-height:before { 186 | content: "\e050"; 187 | } 188 | .glyphicon-text-width:before { 189 | content: "\e051"; 190 | } 191 | .glyphicon-align-left:before { 192 | content: "\e052"; 193 | } 194 | .glyphicon-align-center:before { 195 | content: "\e053"; 196 | } 197 | .glyphicon-align-right:before { 198 | content: "\e054"; 199 | } 200 | .glyphicon-align-justify:before { 201 | content: "\e055"; 202 | } 203 | .glyphicon-list:before { 204 | content: "\e056"; 205 | } 206 | .glyphicon-indent-left:before { 207 | content: "\e057"; 208 | } 209 | .glyphicon-indent-right:before { 210 | content: "\e058"; 211 | } 212 | .glyphicon-facetime-video:before { 213 | content: "\e059"; 214 | } 215 | .glyphicon-picture:before { 216 | content: "\e060"; 217 | } 218 | .glyphicon-map-marker:before { 219 | content: "\e062"; 220 | } 221 | .glyphicon-adjust:before { 222 | content: "\e063"; 223 | } 224 | .glyphicon-tint:before { 225 | content: "\e064"; 226 | } 227 | .glyphicon-edit:before { 228 | content: "\e065"; 229 | } 230 | .glyphicon-share:before { 231 | content: "\e066"; 232 | } 233 | .glyphicon-check:before { 234 | content: "\e067"; 235 | } 236 | .glyphicon-move:before { 237 | content: "\e068"; 238 | } 239 | .glyphicon-step-backward:before { 240 | content: "\e069"; 241 | } 242 | .glyphicon-fast-backward:before { 243 | content: "\e070"; 244 | } 245 | .glyphicon-backward:before { 246 | content: "\e071"; 247 | } 248 | .glyphicon-play:before { 249 | content: "\e072"; 250 | } 251 | .glyphicon-pause:before { 252 | content: "\e073"; 253 | } 254 | .glyphicon-stop:before { 255 | content: "\e074"; 256 | } 257 | .glyphicon-forward:before { 258 | content: "\e075"; 259 | } 260 | .glyphicon-fast-forward:before { 261 | content: "\e076"; 262 | } 263 | .glyphicon-step-forward:before { 264 | content: "\e077"; 265 | } 266 | .glyphicon-eject:before { 267 | content: "\e078"; 268 | } 269 | .glyphicon-chevron-left:before { 270 | content: "\e079"; 271 | } 272 | .glyphicon-chevron-right:before { 273 | content: "\e080"; 274 | } 275 | .glyphicon-plus-sign:before { 276 | content: "\e081"; 277 | } 278 | .glyphicon-minus-sign:before { 279 | content: "\e082"; 280 | } 281 | .glyphicon-remove-sign:before { 282 | content: "\e083"; 283 | } 284 | .glyphicon-ok-sign:before { 285 | content: "\e084"; 286 | } 287 | .glyphicon-question-sign:before { 288 | content: "\e085"; 289 | } 290 | .glyphicon-info-sign:before { 291 | content: "\e086"; 292 | } 293 | .glyphicon-screenshot:before { 294 | content: "\e087"; 295 | } 296 | .glyphicon-remove-circle:before { 297 | content: "\e088"; 298 | } 299 | .glyphicon-ok-circle:before { 300 | content: "\e089"; 301 | } 302 | .glyphicon-ban-circle:before { 303 | content: "\e090"; 304 | } 305 | .glyphicon-arrow-left:before { 306 | content: "\e091"; 307 | } 308 | .glyphicon-arrow-right:before { 309 | content: "\e092"; 310 | } 311 | .glyphicon-arrow-up:before { 312 | content: "\e093"; 313 | } 314 | .glyphicon-arrow-down:before { 315 | content: "\e094"; 316 | } 317 | .glyphicon-share-alt:before { 318 | content: "\e095"; 319 | } 320 | .glyphicon-resize-full:before { 321 | content: "\e096"; 322 | } 323 | .glyphicon-resize-small:before { 324 | content: "\e097"; 325 | } 326 | .glyphicon-exclamation-sign:before { 327 | content: "\e101"; 328 | } 329 | .glyphicon-gift:before { 330 | content: "\e102"; 331 | } 332 | .glyphicon-leaf:before { 333 | content: "\e103"; 334 | } 335 | .glyphicon-fire:before { 336 | content: "\e104"; 337 | } 338 | .glyphicon-eye-open:before { 339 | content: "\e105"; 340 | } 341 | .glyphicon-eye-close:before { 342 | content: "\e106"; 343 | } 344 | .glyphicon-warning-sign:before { 345 | content: "\e107"; 346 | } 347 | .glyphicon-plane:before { 348 | content: "\e108"; 349 | } 350 | .glyphicon-calendar:before { 351 | content: "\e109"; 352 | } 353 | .glyphicon-random:before { 354 | content: "\e110"; 355 | } 356 | .glyphicon-comment:before { 357 | content: "\e111"; 358 | } 359 | .glyphicon-magnet:before { 360 | content: "\e112"; 361 | } 362 | .glyphicon-chevron-up:before { 363 | content: "\e113"; 364 | } 365 | .glyphicon-chevron-down:before { 366 | content: "\e114"; 367 | } 368 | .glyphicon-retweet:before { 369 | content: "\e115"; 370 | } 371 | .glyphicon-shopping-cart:before { 372 | content: "\e116"; 373 | } 374 | .glyphicon-folder-close:before { 375 | content: "\e117"; 376 | } 377 | .glyphicon-folder-open:before { 378 | content: "\e118"; 379 | } 380 | .glyphicon-resize-vertical:before { 381 | content: "\e119"; 382 | } 383 | .glyphicon-resize-horizontal:before { 384 | content: "\e120"; 385 | } 386 | .glyphicon-hdd:before { 387 | content: "\e121"; 388 | } 389 | .glyphicon-bullhorn:before { 390 | content: "\e122"; 391 | } 392 | .glyphicon-bell:before { 393 | content: "\e123"; 394 | } 395 | .glyphicon-certificate:before { 396 | content: "\e124"; 397 | } 398 | .glyphicon-thumbs-up:before { 399 | content: "\e125"; 400 | } 401 | .glyphicon-thumbs-down:before { 402 | content: "\e126"; 403 | } 404 | .glyphicon-hand-right:before { 405 | content: "\e127"; 406 | } 407 | .glyphicon-hand-left:before { 408 | content: "\e128"; 409 | } 410 | .glyphicon-hand-up:before { 411 | content: "\e129"; 412 | } 413 | .glyphicon-hand-down:before { 414 | content: "\e130"; 415 | } 416 | .glyphicon-circle-arrow-right:before { 417 | content: "\e131"; 418 | } 419 | .glyphicon-circle-arrow-left:before { 420 | content: "\e132"; 421 | } 422 | .glyphicon-circle-arrow-up:before { 423 | content: "\e133"; 424 | } 425 | .glyphicon-circle-arrow-down:before { 426 | content: "\e134"; 427 | } 428 | .glyphicon-globe:before { 429 | content: "\e135"; 430 | } 431 | .glyphicon-wrench:before { 432 | content: "\e136"; 433 | } 434 | .glyphicon-tasks:before { 435 | content: "\e137"; 436 | } 437 | .glyphicon-filter:before { 438 | content: "\e138"; 439 | } 440 | .glyphicon-briefcase:before { 441 | content: "\e139"; 442 | } 443 | .glyphicon-fullscreen:before { 444 | content: "\e140"; 445 | } 446 | .glyphicon-dashboard:before { 447 | content: "\e141"; 448 | } 449 | .glyphicon-paperclip:before { 450 | content: "\e142"; 451 | } 452 | .glyphicon-heart-empty:before { 453 | content: "\e143"; 454 | } 455 | .glyphicon-link:before { 456 | content: "\e144"; 457 | } 458 | .glyphicon-phone:before { 459 | content: "\e145"; 460 | } 461 | .glyphicon-pushpin:before { 462 | content: "\e146"; 463 | } 464 | .glyphicon-usd:before { 465 | content: "\e148"; 466 | } 467 | .glyphicon-gbp:before { 468 | content: "\e149"; 469 | } 470 | .glyphicon-sort:before { 471 | content: "\e150"; 472 | } 473 | .glyphicon-sort-by-alphabet:before { 474 | content: "\e151"; 475 | } 476 | .glyphicon-sort-by-alphabet-alt:before { 477 | content: "\e152"; 478 | } 479 | .glyphicon-sort-by-order:before { 480 | content: "\e153"; 481 | } 482 | .glyphicon-sort-by-order-alt:before { 483 | content: "\e154"; 484 | } 485 | .glyphicon-sort-by-attributes:before { 486 | content: "\e155"; 487 | } 488 | .glyphicon-sort-by-attributes-alt:before { 489 | content: "\e156"; 490 | } 491 | .glyphicon-unchecked:before { 492 | content: "\e157"; 493 | } 494 | .glyphicon-expand:before { 495 | content: "\e158"; 496 | } 497 | .glyphicon-collapse-down:before { 498 | content: "\e159"; 499 | } 500 | .glyphicon-collapse-up:before { 501 | content: "\e160"; 502 | } 503 | .glyphicon-log-in:before { 504 | content: "\e161"; 505 | } 506 | .glyphicon-flash:before { 507 | content: "\e162"; 508 | } 509 | .glyphicon-log-out:before { 510 | content: "\e163"; 511 | } 512 | .glyphicon-new-window:before { 513 | content: "\e164"; 514 | } 515 | .glyphicon-record:before { 516 | content: "\e165"; 517 | } 518 | .glyphicon-save:before { 519 | content: "\e166"; 520 | } 521 | .glyphicon-open:before { 522 | content: "\e167"; 523 | } 524 | .glyphicon-saved:before { 525 | content: "\e168"; 526 | } 527 | .glyphicon-import:before { 528 | content: "\e169"; 529 | } 530 | .glyphicon-export:before { 531 | content: "\e170"; 532 | } 533 | .glyphicon-send:before { 534 | content: "\e171"; 535 | } 536 | .glyphicon-floppy-disk:before { 537 | content: "\e172"; 538 | } 539 | .glyphicon-floppy-saved:before { 540 | content: "\e173"; 541 | } 542 | .glyphicon-floppy-remove:before { 543 | content: "\e174"; 544 | } 545 | .glyphicon-floppy-save:before { 546 | content: "\e175"; 547 | } 548 | .glyphicon-floppy-open:before { 549 | content: "\e176"; 550 | } 551 | .glyphicon-credit-card:before { 552 | content: "\e177"; 553 | } 554 | .glyphicon-transfer:before { 555 | content: "\e178"; 556 | } 557 | .glyphicon-cutlery:before { 558 | content: "\e179"; 559 | } 560 | .glyphicon-header:before { 561 | content: "\e180"; 562 | } 563 | .glyphicon-compressed:before { 564 | content: "\e181"; 565 | } 566 | .glyphicon-earphone:before { 567 | content: "\e182"; 568 | } 569 | .glyphicon-phone-alt:before { 570 | content: "\e183"; 571 | } 572 | .glyphicon-tower:before { 573 | content: "\e184"; 574 | } 575 | .glyphicon-stats:before { 576 | content: "\e185"; 577 | } 578 | .glyphicon-sd-video:before { 579 | content: "\e186"; 580 | } 581 | .glyphicon-hd-video:before { 582 | content: "\e187"; 583 | } 584 | .glyphicon-subtitles:before { 585 | content: "\e188"; 586 | } 587 | .glyphicon-sound-stereo:before { 588 | content: "\e189"; 589 | } 590 | .glyphicon-sound-dolby:before { 591 | content: "\e190"; 592 | } 593 | .glyphicon-sound-5-1:before { 594 | content: "\e191"; 595 | } 596 | .glyphicon-sound-6-1:before { 597 | content: "\e192"; 598 | } 599 | .glyphicon-sound-7-1:before { 600 | content: "\e193"; 601 | } 602 | .glyphicon-copyright-mark:before { 603 | content: "\e194"; 604 | } 605 | .glyphicon-registration-mark:before { 606 | content: "\e195"; 607 | } 608 | .glyphicon-cloud-download:before { 609 | content: "\e197"; 610 | } 611 | .glyphicon-cloud-upload:before { 612 | content: "\e198"; 613 | } 614 | .glyphicon-tree-conifer:before { 615 | content: "\e199"; 616 | } 617 | .glyphicon-tree-deciduous:before { 618 | content: "\e200"; 619 | } 620 | .glyphicon-cd:before { 621 | content: "\e201"; 622 | } 623 | .glyphicon-save-file:before { 624 | content: "\e202"; 625 | } 626 | .glyphicon-open-file:before { 627 | content: "\e203"; 628 | } 629 | .glyphicon-level-up:before { 630 | content: "\e204"; 631 | } 632 | .glyphicon-copy:before { 633 | content: "\e205"; 634 | } 635 | .glyphicon-paste:before { 636 | content: "\e206"; 637 | } 638 | .glyphicon-alert:before { 639 | content: "\e209"; 640 | } 641 | .glyphicon-equalizer:before { 642 | content: "\e210"; 643 | } 644 | .glyphicon-king:before { 645 | content: "\e211"; 646 | } 647 | .glyphicon-queen:before { 648 | content: "\e212"; 649 | } 650 | .glyphicon-pawn:before { 651 | content: "\e213"; 652 | } 653 | .glyphicon-bishop:before { 654 | content: "\e214"; 655 | } 656 | .glyphicon-knight:before { 657 | content: "\e215"; 658 | } 659 | .glyphicon-baby-formula:before { 660 | content: "\e216"; 661 | } 662 | .glyphicon-tent:before { 663 | content: "\26fa"; 664 | } 665 | .glyphicon-blackboard:before { 666 | content: "\e218"; 667 | } 668 | .glyphicon-bed:before { 669 | content: "\e219"; 670 | } 671 | .glyphicon-apple:before { 672 | content: "\f8ff"; 673 | } 674 | .glyphicon-erase:before { 675 | content: "\e221"; 676 | } 677 | .glyphicon-hourglass:before { 678 | content: "\231b"; 679 | } 680 | .glyphicon-lamp:before { 681 | content: "\e223"; 682 | } 683 | .glyphicon-duplicate:before { 684 | content: "\e224"; 685 | } 686 | .glyphicon-piggy-bank:before { 687 | content: "\e225"; 688 | } 689 | .glyphicon-scissors:before { 690 | content: "\e226"; 691 | } 692 | .glyphicon-bitcoin:before { 693 | content: "\e227"; 694 | } 695 | .glyphicon-btc:before { 696 | content: "\e227"; 697 | } 698 | .glyphicon-xbt:before { 699 | content: "\e227"; 700 | } 701 | .glyphicon-yen:before { 702 | content: "\00a5"; 703 | } 704 | .glyphicon-jpy:before { 705 | content: "\00a5"; 706 | } 707 | .glyphicon-ruble:before { 708 | content: "\20bd"; 709 | } 710 | .glyphicon-rub:before { 711 | content: "\20bd"; 712 | } 713 | .glyphicon-scale:before { 714 | content: "\e230"; 715 | } 716 | .glyphicon-ice-lolly:before { 717 | content: "\e231"; 718 | } 719 | .glyphicon-ice-lolly-tasted:before { 720 | content: "\e232"; 721 | } 722 | .glyphicon-education:before { 723 | content: "\e233"; 724 | } 725 | .glyphicon-option-horizontal:before { 726 | content: "\e234"; 727 | } 728 | .glyphicon-option-vertical:before { 729 | content: "\e235"; 730 | } 731 | .glyphicon-menu-hamburger:before { 732 | content: "\e236"; 733 | } 734 | .glyphicon-modal-window:before { 735 | content: "\e237"; 736 | } 737 | .glyphicon-oil:before { 738 | content: "\e238"; 739 | } 740 | .glyphicon-grain:before { 741 | content: "\e239"; 742 | } 743 | .glyphicon-sunglasses:before { 744 | content: "\e240"; 745 | } 746 | .glyphicon-text-size:before { 747 | content: "\e241"; 748 | } 749 | .glyphicon-text-color:before { 750 | content: "\e242"; 751 | } 752 | .glyphicon-text-background:before { 753 | content: "\e243"; 754 | } 755 | .glyphicon-object-align-top:before { 756 | content: "\e244"; 757 | } 758 | .glyphicon-object-align-bottom:before { 759 | content: "\e245"; 760 | } 761 | .glyphicon-object-align-horizontal:before { 762 | content: "\e246"; 763 | } 764 | .glyphicon-object-align-left:before { 765 | content: "\e247"; 766 | } 767 | .glyphicon-object-align-vertical:before { 768 | content: "\e248"; 769 | } 770 | .glyphicon-object-align-right:before { 771 | content: "\e249"; 772 | } 773 | .glyphicon-triangle-right:before { 774 | content: "\e250"; 775 | } 776 | .glyphicon-triangle-left:before { 777 | content: "\e251"; 778 | } 779 | .glyphicon-triangle-bottom:before { 780 | content: "\e252"; 781 | } 782 | .glyphicon-triangle-top:before { 783 | content: "\e253"; 784 | } 785 | .glyphicon-console:before { 786 | content: "\e254"; 787 | } 788 | .glyphicon-superscript:before { 789 | content: "\e255"; 790 | } 791 | .glyphicon-subscript:before { 792 | content: "\e256"; 793 | } 794 | .glyphicon-menu-left:before { 795 | content: "\e257"; 796 | } 797 | .glyphicon-menu-right:before { 798 | content: "\e258"; 799 | } 800 | .glyphicon-menu-down:before { 801 | content: "\e259"; 802 | } 803 | .glyphicon-menu-up:before { 804 | content: "\e260"; 805 | } 806 | --------------------------------------------------------------------------------