├── src
├── projects
│ ├── example
│ │ ├── assets
│ │ │ ├── .gitkeep
│ │ │ ├── fonts
│ │ │ │ ├── icomoon.eot
│ │ │ │ ├── icomoon.ttf
│ │ │ │ └── icomoon.woff
│ │ │ ├── scss
│ │ │ │ ├── _variables.scss
│ │ │ │ └── _icons.scss
│ │ │ └── img
│ │ │ │ ├── github.svg
│ │ │ │ └── Npm-01.svg
│ │ ├── libs
│ │ │ ├── ui
│ │ │ │ ├── index.ts
│ │ │ │ └── src
│ │ │ │ │ ├── header
│ │ │ │ │ ├── header.component.html
│ │ │ │ │ └── header.component.ts
│ │ │ │ │ ├── button
│ │ │ │ │ ├── button.component.html
│ │ │ │ │ └── button.component.ts
│ │ │ │ │ ├── header-menu
│ │ │ │ │ ├── header-menu.component.scss
│ │ │ │ │ ├── header-menu.component.ts
│ │ │ │ │ └── header-menu.component.html
│ │ │ │ │ ├── upload-toolbar
│ │ │ │ │ ├── upload-toolbar.component.html
│ │ │ │ │ └── upload-toolbar.component.ts
│ │ │ │ │ └── ui.module.ts
│ │ │ ├── utils
│ │ │ │ ├── http
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── fake-upload.ts
│ │ │ │ └── validators
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ ├── image.validator.ts
│ │ │ │ │ ├── is-zip.validator.ts
│ │ │ │ │ └── max-size.validator.ts
│ │ │ ├── pages
│ │ │ │ ├── drop-zone
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── drop-zone.ts
│ │ │ │ │ │ └── ui
│ │ │ │ │ │ ├── drop-zone.scss
│ │ │ │ │ │ ├── drop-zone.ts
│ │ │ │ │ │ └── drop-zone.html
│ │ │ │ ├── ngx-dropzone
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── page.ts
│ │ │ │ │ │ ├── ngx-dropzone.html
│ │ │ │ │ │ ├── ngx-dropzone-demo.scss
│ │ │ │ │ │ └── ngx-dropzone.ts
│ │ │ │ ├── auto-upload
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── demo
│ │ │ │ │ │ ├── demo.scss
│ │ │ │ │ │ ├── demo.ts
│ │ │ │ │ │ └── demo.html
│ │ │ │ │ │ └── demo.module.ts
│ │ │ │ ├── customize
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── routes.ts
│ │ │ │ │ │ ├── customize.module.ts
│ │ │ │ │ │ └── item-template
│ │ │ │ │ │ └── item-template.component.ts
│ │ │ │ ├── dashboard
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── dashboard
│ │ │ │ │ │ ├── dashboard.component.scss
│ │ │ │ │ │ ├── dashboard.component.html
│ │ │ │ │ │ └── dashboard.component.ts
│ │ │ │ │ │ └── dashboard.module.ts
│ │ │ │ └── validation
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ ├── validation-page
│ │ │ │ │ ├── validation-page.component.scss
│ │ │ │ │ ├── validation-page.component.ts
│ │ │ │ │ └── validation-page.component.html
│ │ │ │ │ ├── is-image
│ │ │ │ │ ├── is-image.component.ts
│ │ │ │ │ └── is-image.component.html
│ │ │ │ │ ├── group-or
│ │ │ │ │ ├── group-or.component.ts
│ │ │ │ │ └── group-or.component.html
│ │ │ │ │ ├── group-and
│ │ │ │ │ ├── group-and.component.ts
│ │ │ │ │ └── group-and.component.html
│ │ │ │ │ ├── group-multiple
│ │ │ │ │ ├── group-multiple.component.ts
│ │ │ │ │ └── group-multiple.component.html
│ │ │ │ │ └── validation.module.ts
│ │ │ └── data
│ │ │ │ ├── base
│ │ │ │ ├── upload-storage.ts
│ │ │ │ ├── data.ts
│ │ │ │ └── icons.ts
│ │ │ │ ├── code
│ │ │ │ ├── common
│ │ │ │ │ └── upload-storage.ts
│ │ │ │ ├── validation
│ │ │ │ │ ├── group-or.ts
│ │ │ │ │ ├── is-image.ts
│ │ │ │ │ ├── group-and.ts
│ │ │ │ │ └── group-multiple.ts
│ │ │ │ ├── auto-upload
│ │ │ │ │ └── auto-upload.ts
│ │ │ │ └── utils
│ │ │ │ │ └── validators.ts
│ │ │ │ └── ui
│ │ │ │ └── icons.ts
│ │ ├── favicon.ico
│ │ ├── environments
│ │ │ ├── environment.demo.ts
│ │ │ ├── environment.prod.ts
│ │ │ ├── environment.e2e.ts
│ │ │ └── environment.ts
│ │ ├── app
│ │ │ ├── app.component.html
│ │ │ ├── app.component.scss
│ │ │ ├── app.component.ts
│ │ │ └── app.module.ts
│ │ ├── tsconfig.app.json
│ │ ├── main.ts
│ │ ├── styles.scss
│ │ ├── index.html
│ │ ├── test.ts
│ │ └── polyfills.ts
│ ├── ui
│ │ ├── src
│ │ │ ├── lib
│ │ │ │ ├── i18n
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ └── i18n.ts
│ │ │ │ ├── progressbar
│ │ │ │ │ ├── main.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── ui
│ │ │ │ │ │ ├── progressbar.scss
│ │ │ │ │ │ ├── progressbar-circle.scss
│ │ │ │ │ │ ├── progressbar.html
│ │ │ │ │ │ └── progressbar-circle.html
│ │ │ │ │ │ └── progressbar.module.ts
│ │ │ │ ├── toolbar
│ │ │ │ │ ├── main.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── toolbar.html
│ │ │ │ │ │ ├── toolbar.scss
│ │ │ │ │ │ └── toolbar.ts
│ │ │ │ ├── file-browser
│ │ │ │ │ └── main.ts
│ │ │ │ ├── upload-item
│ │ │ │ │ ├── main.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ └── upload.control.ts
│ │ │ │ ├── common
│ │ │ │ │ ├── main.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── upload-view.html
│ │ │ │ │ │ ├── cancelable.pipe.ts
│ │ │ │ │ │ ├── state-to-string.pipe.ts
│ │ │ │ │ │ ├── upload-view.scss
│ │ │ │ │ │ └── file-size.pipe.ts
│ │ │ │ └── ui.module.ts
│ │ │ ├── assets
│ │ │ │ ├── fonts
│ │ │ │ │ ├── ngx-fileupload.eot
│ │ │ │ │ ├── ngx-fileupload.ttf
│ │ │ │ │ └── ngx-fileupload.woff
│ │ │ │ └── scss
│ │ │ │ │ ├── _animation.scss
│ │ │ │ │ ├── _variables.scss
│ │ │ │ │ └── _icons.scss
│ │ │ ├── test.ts
│ │ │ ├── tests
│ │ │ │ ├── utils
│ │ │ │ │ ├── i18n.spec.ts
│ │ │ │ │ ├── state-to-string.pipe.spec.ts
│ │ │ │ │ ├── upload.control.spec.ts
│ │ │ │ │ ├── cancelable.pipe.spec.ts
│ │ │ │ │ └── file-size.pipe.spec.ts
│ │ │ │ └── ui
│ │ │ │ │ └── upload-view.spec.ts
│ │ │ └── public-api.ts
│ │ ├── ng-package.json
│ │ ├── tsconfig.spec.json
│ │ ├── tsconfig.lib.json
│ │ ├── package.json
│ │ ├── .eslintrc.json
│ │ └── karma.conf.js
│ ├── core
│ │ ├── ng-package.json
│ │ ├── src
│ │ │ ├── lib
│ │ │ │ ├── validation
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── validation.builder.ts
│ │ │ │ │ │ ├── or.validator.ts
│ │ │ │ │ │ ├── and.validator.ts
│ │ │ │ │ │ └── grouped.validator.ts
│ │ │ │ ├── upload
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── src
│ │ │ │ │ │ ├── upload.model.ts
│ │ │ │ │ │ ├── upload.factory.ts
│ │ │ │ │ │ └── upload.request.model.ts
│ │ │ │ ├── core.ts
│ │ │ │ └── api
│ │ │ │ │ ├── src
│ │ │ │ │ └── validation.ts
│ │ │ │ │ └── index.ts
│ │ │ ├── public-api.ts
│ │ │ ├── test.ts
│ │ │ └── tests
│ │ │ │ ├── validation
│ │ │ │ ├── validation.builder.spec.ts
│ │ │ │ ├── or.validator.spec.ts
│ │ │ │ ├── grouped.validator.spec.ts
│ │ │ │ └── and.validator.spec.ts
│ │ │ │ ├── utils
│ │ │ │ └── factory.spec.ts
│ │ │ │ └── upload
│ │ │ │ ├── upload.headers.spec.ts
│ │ │ │ └── upload.queue.spec.ts
│ │ ├── tsconfig.spec.json
│ │ ├── tsconfig.lib.json
│ │ ├── package.json
│ │ ├── .eslintrc.json
│ │ └── karma.conf.js
│ └── testing
│ │ └── mockup
│ │ ├── index.ts
│ │ └── src
│ │ ├── factory.mock.ts
│ │ ├── upload-storage.mock.ts
│ │ ├── upload-model.ts
│ │ ├── validator.factory.ts
│ │ └── upload-request.mock.ts
├── e2e
│ ├── data
│ │ └── testfile.txt
│ ├── src
│ │ ├── data
│ │ │ ├── upload-file.txt
│ │ │ ├── upload-file.zip
│ │ │ └── upload-file2.zip
│ │ ├── support
│ │ │ ├── dashboard.po.ts
│ │ │ └── ngx-fileupload-ui
│ │ │ │ ├── file-browser.po.ts
│ │ │ │ ├── ngx-fileupload.po.ts
│ │ │ │ └── upload-toolbar.ts
│ │ ├── integration
│ │ │ └── file-browser.spec.ts
│ │ └── utils
│ │ │ └── drag-event.ts
│ ├── protractor-firefox.conf.js
│ ├── github-actions-firefox.conf.js
│ ├── tsconfig.json
│ ├── github-actions-chrome.conf.js
│ └── protractor.conf.js
├── .browserslistrc
├── .eslintrc.json
├── tsconfig.json
├── server
│ └── upload-server.js
└── package.json
├── docs
├── bin
│ ├── toolbar.png
│ ├── progressbar.png
│ ├── upload-item.png
│ └── progressbar-circle.png
├── ngx-fileupload.png
└── ui
│ ├── upload-component.md
│ ├── pipes.md
│ ├── upload-directive.md
│ └── i18n.md
├── .editorconfig
├── .renovaterc.json
├── .github
├── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
└── workflows
│ ├── ngx-file-upload-ui.yml
│ └── ngx-file-upload-core.yml
├── .gitignore
├── bin
└── youtube.badge.svg
└── LICENSE
/src/projects/example/assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/e2e/data/testfile.txt:
--------------------------------------------------------------------------------
1 | hello world
2 |
--------------------------------------------------------------------------------
/src/e2e/src/data/upload-file.txt:
--------------------------------------------------------------------------------
1 | hello angular
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/i18n/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/i18n";
2 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/ui.module";
2 |
--------------------------------------------------------------------------------
/src/projects/example/libs/utils/http/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./fake-upload";
2 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/drop-zone/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/drop-zone";
2 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/ngx-dropzone/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/page";
2 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/auto-upload/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/demo.module";
2 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/customize/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/customize.module";
2 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/dashboard/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/dashboard.module";
2 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/validation.module";
2 |
--------------------------------------------------------------------------------
/docs/bin/toolbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/docs/bin/toolbar.png
--------------------------------------------------------------------------------
/docs/bin/progressbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/docs/bin/progressbar.png
--------------------------------------------------------------------------------
/docs/bin/upload-item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/docs/bin/upload-item.png
--------------------------------------------------------------------------------
/docs/ngx-fileupload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/docs/ngx-fileupload.png
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/validation-page/validation-page.component.scss:
--------------------------------------------------------------------------------
1 | @import "variables";
2 |
--------------------------------------------------------------------------------
/docs/bin/progressbar-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/docs/bin/progressbar-circle.png
--------------------------------------------------------------------------------
/src/e2e/src/data/upload-file.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/src/e2e/src/data/upload-file.zip
--------------------------------------------------------------------------------
/src/projects/example/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/src/projects/example/favicon.ico
--------------------------------------------------------------------------------
/src/e2e/src/data/upload-file2.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/src/e2e/src/data/upload-file2.zip
--------------------------------------------------------------------------------
/src/projects/example/assets/fonts/icomoon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/src/projects/example/assets/fonts/icomoon.eot
--------------------------------------------------------------------------------
/src/projects/example/assets/fonts/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/src/projects/example/assets/fonts/icomoon.ttf
--------------------------------------------------------------------------------
/src/projects/example/assets/fonts/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/src/projects/example/assets/fonts/icomoon.woff
--------------------------------------------------------------------------------
/src/projects/example/environments/environment.demo.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | disableAnimations: false,
4 | demo: true
5 | };
6 |
--------------------------------------------------------------------------------
/src/projects/example/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | disableAnimations: false,
4 | demo: false
5 | };
6 |
--------------------------------------------------------------------------------
/src/projects/ui/src/assets/fonts/ngx-fileupload.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/src/projects/ui/src/assets/fonts/ngx-fileupload.eot
--------------------------------------------------------------------------------
/src/projects/ui/src/assets/fonts/ngx-fileupload.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/src/projects/ui/src/assets/fonts/ngx-fileupload.ttf
--------------------------------------------------------------------------------
/src/projects/ui/src/assets/fonts/ngx-fileupload.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-hannuschka/ngx-fileupload/HEAD/src/projects/ui/src/assets/fonts/ngx-fileupload.woff
--------------------------------------------------------------------------------
/src/projects/example/environments/environment.e2e.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: false,
3 | disableAnimations: true,
4 | demo: false
5 | };
6 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/progressbar/main.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/progressbar.module";
2 | export * from "./src/ui/progressbar";
3 | export * from "./src/ui/progressbar-circle";
4 |
--------------------------------------------------------------------------------
/src/e2e/protractor-firefox.conf.js:
--------------------------------------------------------------------------------
1 | const config = require("./protractor.conf").config;
2 |
3 | config.capabilities = {
4 | browserName: "firefox"
5 | };
6 |
7 | exports.config = config;
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/header/header.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/projects/example/libs/utils/validators/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/image.validator";
2 | export * from "./src/max-size.validator";
3 | export * from "./src/is-zip.validator";
4 |
--------------------------------------------------------------------------------
/src/projects/example/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/e2e/src/support/dashboard.po.ts:
--------------------------------------------------------------------------------
1 | import { browser } from "protractor";
2 |
3 | export class Dashboard {
4 |
5 | async navigateTo() {
6 | await browser.get(browser.baseUrl);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/projects/core/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist/core",
4 | "lib": {
5 | "entryFile": "src/public-api.ts"
6 | }
7 | }
--------------------------------------------------------------------------------
/src/projects/core/src/lib/validation/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/validation.builder";
2 | export * from "./src/grouped.validator";
3 | export * from "./src/and.validator";
4 | export * from "./src/or.validator";
5 |
--------------------------------------------------------------------------------
/src/projects/core/src/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of core
3 | */
4 | export * from "./lib/core";
5 | export * from "./lib/api";
6 | export * from "./lib/upload";
7 | export * from "./lib/validation";
8 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/upload/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/upload.factory";
2 | export * from "./src/upload.model";
3 | export * from "./src/upload.queue";
4 | export * from "./src/upload.request";
5 | export * from "./src/upload.storage";
6 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/core.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { HttpClientModule } from "@angular/common/http";
3 |
4 | @NgModule({
5 | imports: [ HttpClientModule ],
6 | })
7 | export class NgxFileUploadCoreModule {}
8 |
--------------------------------------------------------------------------------
/src/projects/testing/mockup/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/factory.mock";
2 | export * from "./src/upload-model";
3 | export * from "./src/upload-request.mock";
4 | export * from "./src/validator.factory";
5 | export * from "./src/upload-storage.mock";
6 |
--------------------------------------------------------------------------------
/src/projects/example/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "experimentalDecorators": true,
5 | "outDir": "../../out-tsc/app"
6 | },
7 | "include": [
8 | "./**/*.ts"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/button/button.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{label}}
4 |
--------------------------------------------------------------------------------
/src/e2e/github-actions-firefox.conf.js:
--------------------------------------------------------------------------------
1 | const config = require("./protractor.conf").config;
2 |
3 | config.capabilities = {
4 | browserName: "firefox",
5 | "moz:firefoxOptions": {
6 | args: ["-headless"]
7 | }
8 | };
9 |
10 | exports.config = config;
--------------------------------------------------------------------------------
/src/projects/ui/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist/ui",
4 | "lib": {
5 | "cssUrl": "inline",
6 | "entryFile": "src/public-api.ts",
7 | "styleIncludePaths": ["./src/assets"]
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/e2e",
5 | "module": "commonjs",
6 | "target": "es2018",
7 | "types": [
8 | "jasmine",
9 | "jasminewd2",
10 | "node"
11 | ]
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/header-menu/header-menu.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | width: 100%;
3 | display: flex;
4 | justify-content: space-between;
5 | align-items: baseline;
6 |
7 | a {
8 | color: inherit;
9 | text-decoration: none;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 4
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/toolbar/main.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 |
3 | import { UploadToolbarComponent } from "./src/toolbar";
4 |
5 | @NgModule({
6 | exports: [ UploadToolbarComponent ],
7 | declarations: [UploadToolbarComponent],
8 | })
9 | export class NgxFileUploadUiToolbarModule {
10 | }
11 |
--------------------------------------------------------------------------------
/src/e2e/github-actions-chrome.conf.js:
--------------------------------------------------------------------------------
1 | const config = require("./protractor.conf").config;
2 |
3 | config.capabilities = {
4 | browserName: "chrome",
5 | chromeOptions: {
6 | args: ["--headless", "--no-sandbox", "--disable-gpu"],
7 | binary: require("puppeteer").executablePath(),
8 | },
9 | };
10 |
11 | exports.config = config;
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/customize/src/routes.ts:
--------------------------------------------------------------------------------
1 | import { Routes } from "@angular/router";
2 | import { ItemTemplateComponent } from "./item-template/item-template.component";
3 |
4 | export const ItemTemplateRoutes: Routes = [
5 | {
6 | path: "customize",
7 | component: ItemTemplateComponent
8 | }
9 | ];
10 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/auto-upload/src/demo/demo.scss:
--------------------------------------------------------------------------------
1 | @import "variables";
2 |
3 | :host {
4 |
5 | .header {
6 |
7 | background: map-get($colors, darkBlue);
8 | color: map-get($colors, text);
9 |
10 | i {
11 | font-size: 12rem;
12 | margin: 0 1rem;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/projects/core/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/spec",
5 | "types": [
6 | "jasmine",
7 | "node"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts"
12 | ],
13 | "include": [
14 | "**/*.spec.ts",
15 | "**/*.d.ts"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/src/projects/ui/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/spec",
5 | "types": [
6 | "jasmine",
7 | "node"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts"
12 | ],
13 | "include": [
14 | "**/*.spec.ts",
15 | "**/*.d.ts"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/api/src/validation.ts:
--------------------------------------------------------------------------------
1 | export interface NgxFileUploadValidationErrors {
2 | [key: string]: any;
3 | }
4 |
5 | export type NgxFileUploadValidationFn = (file: File) => NgxFileUploadValidationErrors | null;
6 |
7 | export interface NgxFileUploadValidator {
8 | validate(file: File): NgxFileUploadValidationErrors | null;
9 | }
10 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/dashboard/src/dashboard/dashboard.component.scss:
--------------------------------------------------------------------------------
1 |
2 | @import "variables";
3 |
4 | :host {
5 |
6 | .header {
7 |
8 | background: map-get($colors, darkBlue);
9 | color: map-get($colors, text);
10 |
11 | i {
12 | font-size: 12rem;
13 | margin: 0 1rem;
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/validation-page/validation-page.component.ts:
--------------------------------------------------------------------------------
1 | import { Component} from "@angular/core";
2 |
3 | @Component({
4 | selector: "app-validation-page",
5 | templateUrl: "validation-page.component.html",
6 | styleUrls: ["./validation-page.component.scss"]
7 | })
8 | export class ValidationPageComponent {
9 | }
10 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/file-browser/main.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { FileBrowserDirective } from "./src/file-browser";
3 |
4 | @NgModule({
5 | imports: [],
6 | exports: [FileBrowserDirective],
7 | declarations: [FileBrowserDirective],
8 | providers: [],
9 | })
10 | export class NgxFileUploadUiFileBrowserModule { }
11 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/api/index.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadValidator, NgxFileUploadValidationFn } from "./src/validation";
2 |
3 | export interface IDataNode {
4 | [key: string]: any;
5 | }
6 |
7 | export type NgxFileUploadValidation = NgxFileUploadValidator | NgxFileUploadValidationFn;
8 |
9 | export * from "./src/upload";
10 | export * from "./src/validation";
11 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/validation-page/validation-page.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/projects/example/libs/utils/validators/src/image.validator.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadValidationErrors } from "@ngx-file-upload/core";
2 |
3 | export function isImage(file: File): NgxFileUploadValidationErrors | null {
4 |
5 | /** super simple checking */
6 | const valid = /\.(jpg|jpeg|gif|png)$/i.test(file.name);
7 |
8 | return !valid
9 | ? { isImage: "not a valid image file" }
10 | : null;
11 | }
12 |
--------------------------------------------------------------------------------
/src/e2e/src/integration/file-browser.spec.ts:
--------------------------------------------------------------------------------
1 | import { Dashboard } from "../support/dashboard.po";
2 |
3 | describe("Ngx Fileupload Upload File Browser", () => {
4 |
5 | const dashboard: Dashboard = new Dashboard();
6 |
7 | beforeAll(async () => {
8 | await dashboard.navigateTo();
9 | });
10 |
11 | it("add new file: enabled buttons upload and remove, disabled buttons clear", async () => {
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/src/projects/example/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from "@angular/core";
2 | import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
3 |
4 | import { AppModule } from "./app/app.module";
5 | import { environment } from "./environments/environment";
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule)
12 | .catch(err => console.error(err));
13 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/progressbar/src/ui/progressbar.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | display: block;
3 |
4 | .progressbar {
5 |
6 | width: 100%;
7 | height: 1rem;
8 |
9 | line {
10 | stroke-width: .5rem;
11 | }
12 |
13 | .background {
14 | stroke: darken(#006494, 10);
15 | }
16 |
17 | .progress {
18 | stroke: #0582CA;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/base/upload-storage.ts:
--------------------------------------------------------------------------------
1 | import { InjectionToken } from "@angular/core";
2 | import { NgxFileUploadStorage } from "@ngx-file-upload/core";
3 |
4 | export const ExampleUploadStorage = new InjectionToken("Example Upload Storage", {
5 | providedIn: "root",
6 | factory: () => {
7 | return new NgxFileUploadStorage({
8 | concurrentUploads: 3
9 | });
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/dashboard/src/dashboard/dashboard.component.html:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/projects/example/styles.scss:
--------------------------------------------------------------------------------
1 | $ngx-fileupload-example--font-path: "./example/assets/fonts";
2 |
3 | @import url('https://fonts.googleapis.com/icon?family=Material+Icons');
4 | @import '~highlight.js/styles/github.css';
5 | @import './assets/scss/variables';
6 |
7 | /* You can add global styles to this file, and also import other style files */
8 | body {
9 | padding: 4.5rem 0;
10 | }
11 |
12 | .error {
13 | color: map-get($colors, "red");
14 | }
15 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/header/header.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input } from "@angular/core";
2 | import { MenuItem } from "projects/example/libs/data/base/data";
3 |
4 | @Component({
5 | selector: "app-ui--header",
6 | templateUrl: "header.component.html"
7 | })
8 | export class HeaderComponent implements OnInit {
9 | constructor() { }
10 |
11 | @Input()
12 | menuItems: MenuItem[] = [];
13 |
14 | ngOnInit() { }
15 | }
16 |
--------------------------------------------------------------------------------
/src/.browserslistrc:
--------------------------------------------------------------------------------
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'.
--------------------------------------------------------------------------------
/src/projects/example/app/app.component.scss:
--------------------------------------------------------------------------------
1 | @import 'variables';
2 |
3 | :host {
4 |
5 | ::ng-deep {
6 | app-ui--header .navbar {
7 | background-color: map-get($colors, black);
8 | color: map-get($colors, text);
9 |
10 | .nav-link {
11 | color: map-get($colors, textDark);
12 | }
13 |
14 | .nav-link.route-link-active {
15 | color: inherit;
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/code/common/upload-storage.ts:
--------------------------------------------------------------------------------
1 | export const TS = `
2 | import { InjectionToken } from "@angular/core";
3 | import { NgxFileUploadStorage } from "@ngx-file-upload/core";
4 |
5 | export const ExampleUploadStorage = new InjectionToken("Customize Template Upload Storage", {
6 | providedIn: "root",
7 | factory: () => {
8 | return new NgxFileUploadStorage({
9 | concurrentUploads: 3
10 | });
11 | }
12 | });
13 | `;
14 |
--------------------------------------------------------------------------------
/.renovaterc.json:
--------------------------------------------------------------------------------
1 | {
2 | "packageRules": [
3 | {
4 | "packagePatterns": ["tslint", "prettier"],
5 | "groupName": "linters"
6 | }
7 | ],
8 | "ignoreDeps": ["typescript"],
9 | "baseBranches": [
10 | "development"
11 | ],
12 | "assignees": ["r-hannuschka"],
13 | "automerge": false,
14 | "schedule": [
15 | "after 10pm every weekday",
16 | "before 5am every weekday",
17 | "every weekend"
18 | ],
19 | "extends": [
20 | "config:base"
21 | ],
22 | "timezone": "Europe/Berlin"
23 | }
24 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/upload-item/main.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { CommonModule } from "@angular/common";
3 | import { NgxFileUploadUiCommonModule } from "../common/main";
4 | import { UploadItemComponent } from "./src/upload-item";
5 |
6 | @NgModule({
7 | imports: [
8 | CommonModule,
9 | NgxFileUploadUiCommonModule
10 | ],
11 | exports: [UploadItemComponent],
12 | declarations: [UploadItemComponent],
13 | providers: [],
14 | })
15 | export class NgxFileUploadUiItemModule { }
16 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/header-menu/header-menu.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input } from "@angular/core";
2 | import { MenuItem } from "projects/example/libs/data/base/data";
3 |
4 | @Component({
5 | selector: "app-ui--header-menu",
6 | templateUrl: "header-menu.component.html",
7 | styleUrls: ["./header-menu.component.scss"]
8 | })
9 | export class HeaderMenuComponent implements OnInit {
10 | constructor() { }
11 |
12 | @Input()
13 | public items: MenuItem[] = [];
14 |
15 | ngOnInit() { }
16 | }
17 |
--------------------------------------------------------------------------------
/src/e2e/src/support/ngx-fileupload-ui/file-browser.po.ts:
--------------------------------------------------------------------------------
1 | import { simulateDrop } from "../../utils/drag-event";
2 | import { by, element } from "protractor";
3 |
4 | export class FileBrowserPo {
5 |
6 | public get fileBrowser() {
7 | return element(by.css("[ngxfileupload]"));
8 | }
9 |
10 | public async dropFile(file: string) {
11 | await simulateDrop(this.fileBrowser, file);
12 | }
13 |
14 | public async dropFiles(files: string[]) {
15 | await simulateDrop(this.fileBrowser, files);
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/upload/src/upload.model.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadValidationErrors, INgxFileUploadFile } from "../../api";
2 |
3 | export class NgxFileUploadFile implements INgxFileUploadFile {
4 | readonly raw: File
5 | readonly size: number
6 | readonly name: string
7 | readonly type: string
8 | validationErrors: NgxFileUploadValidationErrors | null = null
9 |
10 | public constructor(file: File) {
11 | this.raw = file
12 | this.size = file.size
13 | this.type = file.type
14 | this.name = file.name
15 | }
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/progressbar/src/ui/progressbar-circle.scss:
--------------------------------------------------------------------------------
1 | :host {
2 |
3 | display: block;
4 | position: relative;
5 |
6 | svg {
7 | transform: rotate(-90deg);
8 |
9 | circle.mask {
10 | stroke: #FFF !important;
11 | }
12 |
13 | circle.mask.animate {
14 | transition: stroke-dashoffset .15s linear;
15 | }
16 | }
17 |
18 | span {
19 | position: absolute;
20 | top: 50%;
21 | left: 50%;
22 | transform: translate(-50%, -50%);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/projects/core/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import "zone.js";
4 | import "zone.js/testing";
5 | import { getTestBed } from "@angular/core/testing";
6 | import {
7 | BrowserDynamicTestingModule,
8 | platformBrowserDynamicTesting
9 | } from "@angular/platform-browser-dynamic/testing";
10 |
11 | // First, initialize the Angular testing environment.
12 | getTestBed().initTestEnvironment(
13 | BrowserDynamicTestingModule,
14 | platformBrowserDynamicTesting(), {
15 | teardown: { destroyAfterEach: false }
16 | }
17 | );
18 |
--------------------------------------------------------------------------------
/src/projects/ui/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import "zone.js";
4 | import "zone.js/testing";
5 | import { getTestBed } from "@angular/core/testing";
6 | import {
7 | BrowserDynamicTestingModule,
8 | platformBrowserDynamicTesting
9 | } from "@angular/platform-browser-dynamic/testing";
10 |
11 | // First, initialize the Angular testing environment.
12 | getTestBed().initTestEnvironment(
13 | BrowserDynamicTestingModule,
14 | platformBrowserDynamicTesting(), {
15 | teardown: { destroyAfterEach: false }
16 | }
17 | );
18 |
--------------------------------------------------------------------------------
/src/projects/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ngx file upload
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/projects/example/libs/utils/validators/src/is-zip.validator.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadValidationErrors } from "@ngx-file-upload/core";
2 |
3 | export function isZipFile(file: File): NgxFileUploadValidationErrors | null {
4 |
5 | const validMime = [
6 | "application/zip",
7 | "application/octet-stream",
8 | "application/x-zip-compressed",
9 | "multipart/x-zip"
10 | ];
11 |
12 | let valid = validMime.some((type) => type === file.type);
13 | valid = valid && /\.zip$/.test(file.name);
14 |
15 | return !valid
16 | ? { zipValidator: "not a valid zip file" }
17 | : null;
18 | }
19 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/dashboard/src/dashboard/dashboard.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Inject } from "@angular/core";
2 | import { NgxFileUploadStorage } from "@ngx-file-upload/core";
3 | import { ExampleUploadStorage } from "projects/example/libs/data/base/upload-storage";
4 |
5 | @Component({
6 | selector: "app-dashboard",
7 | templateUrl: "dashboard.component.html",
8 | styleUrls: ["./dashboard.component.scss"]
9 | })
10 | export class DashboardComponent implements OnInit {
11 |
12 | constructor(
13 | @Inject(ExampleUploadStorage) public storage: NgxFileUploadStorage
14 | ) { }
15 |
16 | ngOnInit() { }
17 | }
18 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/progressbar/src/progressbar.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { CommonModule } from "@angular/common";
3 | import { ProgressbarComponent } from "./ui/progressbar";
4 | import { ProgressbarCircleComponent } from "./ui/progressbar-circle";
5 |
6 | @NgModule({
7 | imports: [
8 | CommonModule
9 | ],
10 | exports: [
11 | ProgressbarComponent,
12 | ProgressbarCircleComponent
13 | ],
14 | declarations: [
15 | ProgressbarComponent,
16 | ProgressbarCircleComponent
17 | ],
18 | providers: [],
19 | })
20 | export class NgxFileUploadUiProgressbarModule { }
21 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/common/main.ts:
--------------------------------------------------------------------------------
1 | export * from "./src/upload-view";
2 |
3 | import { NgModule } from "@angular/core";
4 | import { CancelAblePipe } from "./src/cancelable.pipe";
5 | import { FileSizePipe } from "./src/file-size.pipe";
6 | import { StateToStringPipe } from "./src/state-to-string.pipe";
7 |
8 | @NgModule({
9 | imports: [],
10 | exports: [
11 | StateToStringPipe,
12 | FileSizePipe,
13 | CancelAblePipe
14 | ],
15 | declarations: [
16 | StateToStringPipe,
17 | FileSizePipe,
18 | CancelAblePipe
19 | ],
20 | providers: [],
21 | })
22 | export class NgxFileUploadUiCommonModule { }
23 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/common/src/upload-view.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ i18n?.SELECT_FILES || "Drag/Drop files here or click"}}
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/projects/core/src/tests/validation/validation.builder.spec.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadValidationBuilder, NgxFileUploadOrValidator, NgxFileUploadAndValidator} from "@ngx-file-upload/dev/core/public-api";
2 |
3 | describe("@ngx-file-upload/core/validation/builder", () => {
4 |
5 | it ("it should create OR Group", () => {
6 | const group = NgxFileUploadValidationBuilder.or();
7 | expect(group instanceof NgxFileUploadOrValidator).toBeTruthy();
8 | });
9 |
10 | it ("it should create AND Group", () => {
11 | const group = NgxFileUploadValidationBuilder.and();
12 | expect(group instanceof NgxFileUploadAndValidator).toBeTruthy();
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/src/projects/ui/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/lib",
5 | "declaration": true,
6 | "inlineSources": true,
7 | "types": [],
8 | "lib": [
9 | "dom",
10 | "es2018"
11 | ]
12 | },
13 | "angularCompilerOptions": {
14 | "annotateForClosureCompiler": true,
15 | "compilationMode": "partial",
16 | "skipTemplateCodegen": true,
17 | "strictMetadataEmit": true,
18 | "fullTemplateTypeCheck": true,
19 | "strictInjectionParameters": true,
20 | "enableResourceInlining": true
21 | },
22 | "exclude": [
23 | "src/test.ts",
24 | "**/*.spec.ts"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/base/data.ts:
--------------------------------------------------------------------------------
1 | export interface ProgressbarCircle {
2 |
3 | /** svg height */
4 | height: number;
5 |
6 | /** svg width */
7 | width: number;
8 |
9 | /** circle radius */
10 | radius: number;
11 | }
12 |
13 | export interface MenuItem {
14 | label: string;
15 | route: string;
16 | }
17 |
18 | export const MainMenuItems: MenuItem[] = [
19 | {label: "Dashboard", route: "dashboard"},
20 | {label: "Customize", route: "customize"},
21 | {label: "Automatic NgxFileUpload", route: "auto-upload"},
22 | {label: "Validation", route: "validation"},
23 | {label: "Ngx File Drop", route: "drop-zone"},
24 | {label: "Ngx Dropzone", route: "ngx-dropzone"},
25 | ];
26 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/validation/src/validation.builder.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadGroupedvalidator } from "./grouped.validator";
2 | import { NgxFileUploadAndValidator } from "./and.validator";
3 | import { NgxFileUploadOrValidator } from "./or.validator";
4 | import { NgxFileUploadValidation } from "../../api";
5 |
6 | export class NgxFileUploadValidationBuilder {
7 |
8 | public static and(...validators: Array): NgxFileUploadGroupedvalidator {
9 | return new NgxFileUploadAndValidator(validators);
10 | }
11 |
12 | public static or(...validators: Array): NgxFileUploadGroupedvalidator {
13 | return new NgxFileUploadOrValidator(validators);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/projects/ui/src/tests/utils/i18n.spec.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadUiI18nProvider, NgxFileUploadUiI18nKey } from "../../lib/i18n";
2 |
3 | describe("ngx-fileupload/libs/upload/upload-control", () => {
4 |
5 | it("should have no labels", () => {
6 | const i18nProvider = new NgxFileUploadUiI18nProvider(void 0);
7 | expect(i18nProvider.getI18n(NgxFileUploadUiI18nKey.Common)).toBeUndefined();
8 | });
9 |
10 | it("should have no labels", () => {
11 | const i18nProvider = new NgxFileUploadUiI18nProvider({
12 | common: {SELECT_FILES: "select file"}
13 | });
14 | expect(i18nProvider.getI18n(NgxFileUploadUiI18nKey.Common)).toEqual({SELECT_FILES: "select file"});
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/auto-upload/src/demo/demo.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnDestroy } from "@angular/core";
2 | import { NgxFileUploadStorage } from "@ngx-file-upload/core";
3 | import * as ExampleCodeData from "projects/example/libs/data/code/auto-upload/auto-upload";
4 |
5 | @Component({
6 | selector: "app-auto-upload-demo",
7 | templateUrl: "demo.html",
8 | styleUrls: ["./demo.scss"]
9 | })
10 | export class DemoComponent implements OnDestroy {
11 |
12 | public storage: NgxFileUploadStorage = new NgxFileUploadStorage({
13 | concurrentUploads: 2,
14 | autoStart: true
15 | });
16 |
17 | public code = ExampleCodeData;
18 |
19 | ngOnDestroy() {
20 | this.storage.destroy();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/projects/core/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/lib",
5 | "declaration": true,
6 | "inlineSources": true,
7 | "types": [],
8 | "lib": [
9 | "dom",
10 | "es2018"
11 | ]
12 | },
13 | "angularCompilerOptions": {
14 | "annotateForClosureCompiler": true,
15 | "compilationMode": "partial",
16 | "skipTemplateCodegen": true,
17 | "strictMetadataEmit": true,
18 | "fullTemplateTypeCheck": true,
19 | "strictInjectionParameters": true,
20 | "enableResourceInlining": true
21 | },
22 | "exclude": [
23 | "src/test.ts",
24 | "src/tests/**/*.spec.ts",
25 | "src/mockup/**/*.ts",
26 | "node_modules"
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/code/validation/group-or.ts:
--------------------------------------------------------------------------------
1 | export * from "./is-image";
2 |
3 | export const validationGroupOr = `
4 | import { Component, OnInit } from "@angular/core";
5 | import { isImage, isZipFile } from "@ngx-fileupload-example/utils/validators";
6 | import { NgxFileUploadValidationBuilder, NgxFileUploadGroupedvalidator } from "@ngx-file-upload/core";
7 |
8 | @Component({
9 | selector: "app-validation--group-or",
10 | templateUrl: "group-or.component.html"
11 | })
12 | export class GroupOrComponent implements OnInit {
13 |
14 | public validator: NgxFileUploadGroupedvalidator;
15 |
16 | public ngOnInit() {
17 |
18 | this.validator = NgxFileUploadValidationBuilder.or(
19 | isImage, isZipFile
20 | );
21 | }
22 | }`;
23 |
--------------------------------------------------------------------------------
/src/projects/example/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import "zone.js/testing";
4 | import { getTestBed } from "@angular/core/testing";
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting
8 | } from "@angular/platform-browser-dynamic/testing";
9 |
10 | declare const require: any;
11 |
12 | // First, initialize the Angular testing environment.
13 | getTestBed().initTestEnvironment(
14 | BrowserDynamicTestingModule,
15 | platformBrowserDynamicTesting(), {
16 | teardown: { destroyAfterEach: false }
17 | }
18 | );
19 | // Then we find all the tests.
20 | const context = require.context("./", true, /\.spec\.ts$/);
21 | // And load the modules.
22 | context.keys().map(context);
23 |
--------------------------------------------------------------------------------
/src/projects/example/assets/scss/_variables.scss:
--------------------------------------------------------------------------------
1 | $icomoon-font-family: "icomoon" !default;
2 |
3 | $icomoon-font-family: "icomoon" !default;
4 | $icomoon-font-path: "fonts" !default;
5 |
6 | $icon-connect: "\f07e";
7 | $icon-upload: "\e900";
8 | $icon-pending: "\e94e";
9 | $icon-reload: "\e984";
10 | $icon-warning: "\ea07";
11 | $icon-cancel: "\ea0d";
12 | $icon-canceled: "\ea0e";
13 | $icon-success: "\ea10";
14 | $icon-progress: "\ea2e";
15 | $icon-toggle-open: "\ea41";
16 | $icon-toggle-close: "\ea43";
17 | $icon-github: "\eab0";
18 | $icon-npm: "\eab1";
19 |
20 | $colors : (
21 | text: #E2E2E2,
22 | white: #E2E2E2,
23 | textDark: darken(#E2E2E2, 20%),
24 | darkBlue: #006494,
25 | blue: #0582Ca,
26 | lightBlue: #00A6FB,
27 | black: #0D1F2D,
28 | red: #ED4337
29 | );
30 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/upload-toolbar/upload-toolbar.component.html:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/src/projects/example/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false,
7 | disableAnimations: false,
8 | demo: false
9 | };
10 |
11 | /*
12 | * For easier debugging in development mode, you can import the following file
13 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
14 | *
15 | * This import should be commented out in production mode because it will have a negative impact
16 | * on performance if an error is thrown.
17 | */
18 | // import "zone.js/plugins/zone-error"; // Included with Angular CLI.
19 |
--------------------------------------------------------------------------------
/src/projects/testing/mockup/src/factory.mock.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadFactory, NgxFileUploadOptions, NgxFileUploadValidation } from "@ngx-file-upload/core";
2 | import { UploadRequestMock } from "./upload-request.mock";
3 | import { NgxFileUploadRequestModel } from "./upload-model";
4 |
5 | export class NgxFileuploadFactoryMock implements NgxFileUploadFactory {
6 |
7 | createUploadRequest(file: File, options: NgxFileUploadOptions, validator?: NgxFileUploadValidation): UploadRequestMock;
8 | createUploadRequest(file: File[], options: NgxFileUploadOptions, validator?: NgxFileUploadValidation): UploadRequestMock[];
9 | createUploadRequest(): UploadRequestMock | UploadRequestMock[] {
10 | const model = new NgxFileUploadRequestModel();
11 | return new UploadRequestMock(model);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/e2e/src/support/ngx-fileupload-ui/ngx-fileupload.po.ts:
--------------------------------------------------------------------------------
1 | import { by, element, ElementArrayFinder } from "protractor";
2 |
3 | export class NgxFileuploadPO {
4 |
5 | public get ngxFileUpload() {
6 | return element(by.tagName("ngx-file-upload"));
7 | }
8 |
9 | public getFileBrowser() {
10 | return this.ngxFileUpload.element(by.css(".fileupload"));
11 | }
12 |
13 | public getUploadList() {
14 | return this.ngxFileUpload.element(by.css(".file-upload--list"));
15 | }
16 |
17 | public getUploadItems(): ElementArrayFinder {
18 | return this.ngxFileUpload.all(by.tagName("ngx-file-upload-ui--item"));
19 | }
20 |
21 | public getUploadActionsFromItem(): ElementArrayFinder {
22 | return this.ngxFileUpload.all(by.css(".item-action--cancel"));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/validation/src/or.validator.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadValidationErrors } from "../../api";
2 | import { NgxFileUploadGroupedvalidator } from "./grouped.validator";
3 |
4 | export class NgxFileUploadOrValidator extends NgxFileUploadGroupedvalidator {
5 |
6 | public validate(file: File): NgxFileUploadValidationErrors | null {
7 |
8 | let validationResult: NgxFileUploadValidationErrors | null = {};
9 |
10 | for (const validator of this.validators) {
11 | const result = this.execValidator(validator, file);
12 |
13 | if (result === null) {
14 | validationResult = null;
15 | break;
16 | }
17 |
18 | Object.assign(validationResult, result);
19 | }
20 |
21 | return validationResult;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/header-menu/header-menu.component.html:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/validation/src/and.validator.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadGroupedvalidator } from "./grouped.validator";
2 | import { NgxFileUploadValidationErrors } from "../../api";
3 |
4 | export class NgxFileUploadAndValidator extends NgxFileUploadGroupedvalidator {
5 |
6 | public validate(file: File): NgxFileUploadValidationErrors | null {
7 |
8 | const validationResult: NgxFileUploadValidationErrors = {};
9 | let hasErrors = false;
10 |
11 | for (const validator of this.validators) {
12 | const result = this.execValidator(validator, file);
13 |
14 | if (result !== null) {
15 | Object.assign(validationResult, result);
16 | hasErrors = true;
17 | }
18 | }
19 | return hasErrors ? validationResult : null;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/projects/example/assets/img/github.svg:
--------------------------------------------------------------------------------
1 | GitHub icon
--------------------------------------------------------------------------------
/src/projects/ui/src/assets/scss/_animation.scss:
--------------------------------------------------------------------------------
1 | /** safari chrome */
2 | @-webkit-keyframes rotating {
3 | from {
4 | -webkit-transform: rotate(0deg);
5 | -o-transform: rotate(0deg);
6 | transform: rotate(0deg);
7 | }
8 |
9 | to {
10 | -webkit-transform: rotate(360deg);
11 | -o-transform: rotate(360deg);
12 | transform: rotate(360deg);
13 | }
14 | }
15 |
16 | @keyframes rotating {
17 | from {
18 | -ms-transform: rotate(0deg);
19 | -moz-transform: rotate(0deg);
20 | -webkit-transform: rotate(0deg);
21 | -o-transform: rotate(0deg);
22 | transform: rotate(0deg);
23 | }
24 |
25 | to {
26 | -ms-transform: rotate(360deg);
27 | -moz-transform: rotate(360deg);
28 | -webkit-transform: rotate(360deg);
29 | -o-transform: rotate(360deg);
30 | transform: rotate(360deg);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/progressbar/src/ui/progressbar.html:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
14 |
15 |
16 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/code/auto-upload/auto-upload.ts:
--------------------------------------------------------------------------------
1 | export const TS = `
2 | import { Component, OnInit } from "@angular/core";
3 | import { NgxFileUploadStorage } from "@ngx-file-upload/core";
4 |
5 | @Component({
6 | selector: "app-auto-upload-demo",
7 | templateUrl: "demo.html",
8 | styleUrls: ["./demo.scss"]
9 | })
10 | export class DemoComponent implements OnInit, OnDestroy {
11 |
12 | public storage: NgxFileUploadStorage;
13 |
14 | ngOnInit() {
15 | this.storage = new NgxFileUploadStorage({
16 | concurrentUploads: 2,
17 | enableAutoStart: true
18 | });
19 | }
20 |
21 | ngOnDestroy() {
22 | this.storage.destroy();
23 | }
24 | }
25 | `;
26 |
27 | export const HTML = `
28 |
29 | `;
30 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/code/validation/is-image.ts:
--------------------------------------------------------------------------------
1 | export const HTML = `
2 |
8 |
9 | `;
10 |
11 | export const TYPESCRIPT = `
12 | import { Component } from "@angular/core";
13 | import { NgxFileUploadValidationFn } from "@ngx-file-upload/core";
14 | import { isImage } from "@ngx-fileupload-example/utils/validators";
15 |
16 | @Component({
17 | selector: "app-validation--is-image",
18 | templateUrl: "is-image.component.html"
19 | })
20 | export class BaseComponent {
21 | public validator: NgxFileUploadValidationFn = isImage;
22 | }
23 | `;
24 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/auto-upload/src/demo.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { RouterModule } from "@angular/router";
3 | import { IgxTabsModule } from "igniteui-angular";
4 | import { UiModule } from "projects/example/libs/ui";
5 | import { DemoComponent } from "./demo/demo";
6 | import { HighlightModule } from "ngx-highlightjs";
7 | import { NgxFileUploadUiModule } from "@ngx-file-upload/ui";
8 |
9 | @NgModule({
10 | imports: [
11 | NgxFileUploadUiModule,
12 | UiModule,
13 | RouterModule.forChild([{
14 | path: "auto-upload",
15 | component: DemoComponent
16 | }]),
17 | IgxTabsModule,
18 | HighlightModule
19 | ],
20 | exports: [RouterModule],
21 | declarations: [DemoComponent],
22 | providers: []
23 | })
24 | export class AutoUploadDemo { }
25 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/common/src/cancelable.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from "@angular/core";
2 | import { NgxFileUploadState } from "@ngx-file-upload/core";
3 |
4 | /**
5 | * returns true if an upload could be canceled
6 | * an upload could canceled if state is one of these: PENDING, START or PROGRESS
7 | *
8 | * @example
9 | * cancel
10 | */
11 | @Pipe({
12 | name: "isCancelAble"
13 | })
14 | export class CancelAblePipe implements PipeTransform {
15 |
16 | transform(state: NgxFileUploadState): boolean {
17 | let isCancelAble = state === NgxFileUploadState.PENDING;
18 | isCancelAble = isCancelAble || state === NgxFileUploadState.START;
19 | isCancelAble = isCancelAble || state === NgxFileUploadState.PROGRESS;
20 | return isCancelAble;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/is-image/is-image.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from "@angular/core";
2 | import { isImage } from "projects/example/libs/utils/validators";
3 | import { NgxFileUploadStorage, NgxFileUploadValidationFn } from "@ngx-file-upload/core";
4 | import * as ExampleCode from "projects/example/libs/data/code/validation/is-image";
5 | import * as Validators from "projects/example/libs/data/code/utils/validators";
6 |
7 | @Component({
8 | selector: "app-validation--is-image",
9 | templateUrl: "is-image.component.html"
10 | })
11 | export class IsImageValidationComponent {
12 |
13 | storage = new NgxFileUploadStorage({
14 | concurrentUploads: 2
15 | })
16 |
17 | public validator: NgxFileUploadValidationFn = isImage;
18 |
19 | public exampleCode = ExampleCode;
20 |
21 | public codeValidator = Validators.IMAGE_VALIDATOR;
22 | }
23 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/button/button.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input, HostListener, Output, EventEmitter } from "@angular/core";
2 |
3 | @Component({
4 | selector: "app-ui--button",
5 | templateUrl: "button.component.html"
6 | })
7 |
8 | export class ButtonComponent implements OnInit {
9 | constructor() { }
10 |
11 | @Input()
12 | public icon: string = "";
13 |
14 | @Input()
15 | public label: string = "";
16 |
17 | @Input()
18 | public disabled = false;
19 |
20 | @Input()
21 | public class = "";
22 |
23 | @Output()
24 | public dispatch: EventEmitter = new EventEmitter();
25 |
26 | ngOnInit() { }
27 |
28 | @HostListener("click", ["$event"])
29 | public handleClick(event: MouseEvent) {
30 | event.stopPropagation();
31 | event.preventDefault();
32 | this.dispatch.emit();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/projects/testing/mockup/src/upload-storage.mock.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadStorage } from "@ngx-file-upload/core";
2 | import { Observable, of } from "rxjs";
3 |
4 | export class UploadStorageMock extends NgxFileUploadStorage {
5 |
6 | public change(): Observable {
7 | return of([]);
8 | }
9 |
10 | /**
11 | * gets notified if queue changes
12 | */
13 | public get queueChange(): Observable {
14 | return of([]);
15 | }
16 |
17 | public destroy() {}
18 |
19 | /**
20 | * remove upload from store
21 | */
22 | public remove() {}
23 |
24 | /**
25 | * remove all uploads which has been invalid
26 | * canceled or upload has been completed even it is has an error
27 | */
28 | public purge() {
29 | }
30 |
31 | public startAll() {}
32 |
33 | public stopAll() {}
34 |
35 | public removeInvalid() {}
36 | }
37 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/dashboard/src/dashboard.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { DashboardComponent } from "./dashboard/dashboard.component";
3 | import { RouterModule } from "@angular/router";
4 | import { NgxFileUploadUiModule } from "@ngx-file-upload/ui";
5 | import { UiModule } from "projects/example/libs/ui";
6 |
7 | @NgModule({
8 | imports: [
9 | NgxFileUploadUiModule,
10 | UiModule,
11 | RouterModule.forChild([
12 | {
13 | path: "",
14 | redirectTo: "dashboard",
15 | pathMatch: "full"
16 | },
17 | {
18 | path: "dashboard",
19 | component: DashboardComponent
20 | }
21 | ])
22 | ],
23 | exports: [RouterModule],
24 | declarations: [DashboardComponent],
25 | providers: []
26 | })
27 | export class Dashboard { }
28 |
--------------------------------------------------------------------------------
/src/projects/ui/src/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of @ngx-file-upload/ui
3 | */
4 | export * from "./lib/ui.module";
5 |
6 | export * from "./lib/common/main";
7 | export * from "./lib/file-browser/main";
8 | export * from "./lib/file-browser/src/file-browser";
9 |
10 | export * from "./lib/progressbar/main";
11 | export * from "./lib/progressbar/src/ui/progressbar";
12 | export * from "./lib/progressbar/src/ui/progressbar-circle";
13 |
14 | export * from "./lib/toolbar/main";
15 | export * from "./lib/toolbar/src/toolbar";
16 |
17 | export * from "./lib/upload-item/main";
18 | export * from "./lib/upload-item/src/upload-item";
19 | export * from "./lib/upload-item/src/upload.control";
20 |
21 | export * from "./lib/common/src/cancelable.pipe"
22 | export * from "./lib/common/src/file-size.pipe"
23 | export * from "./lib/common/src/state-to-string.pipe"
24 |
25 | export { NgxFileUploadUiI18n, NGX_FILE_UPLOAD_UI_I18N } from "./lib/i18n";
26 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/code/validation/group-and.ts:
--------------------------------------------------------------------------------
1 | export * from "./is-image";
2 |
3 | export const validationGroupAnd = `
4 | import { Component, OnInit } from "@angular/core";
5 | import { isImage, MaxUploadSizeValidator } from "@ngx-fileupload-example/utils/validators";
6 | import { NgxFileUploadValidationBuilder, NgxFileUploadGroupedvalidator } from "@ngx-file-upload/core";
7 |
8 | @Component({
9 | selector: "app-validation--validation-group",
10 | templateUrl: "validation-group.component.html"
11 | })
12 | export class ValidationGroupComponent implements OnInit {
13 |
14 | public validator: NgxFileUploadGroupedvalidator;
15 |
16 | public ngOnInit() {
17 |
18 | /** set max file upload size to 512kb */
19 | const maxUploadSize: number = 512 * 1024;
20 |
21 | this.validator = NgxFileUploadValidationBuilder.and(
22 | isImage, new MaxUploadSizeValidator(maxUploadSize)
23 | );
24 | }
25 | }`;
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /src/dist
5 | /tmp
6 | /out-tsc
7 | /src/coverage
8 | /src/documentation
9 | /src/server/upload.log
10 | /src/__ivy_ngcc__
11 |
12 | # Only exists if Bazel was run
13 | /bazel-out
14 |
15 | # dependencies
16 | src/node_modules
17 |
18 | # profiling files
19 | chrome-profiler-events.json
20 | speed-measure-plugin.json
21 |
22 | # IDEs and editors
23 | /.idea
24 | .project
25 | .classpath
26 | .c9/
27 | *.launch
28 | .settings/
29 | *.sublime-workspace
30 |
31 | # IDE - VSCode
32 | .vscode/*
33 | !.vscode/settings.json
34 | !.vscode/tasks.json
35 | !.vscode/launch.json
36 | !.vscode/extensions.json
37 | .history/*
38 |
39 | # misc
40 | /.sass-cache
41 | /connect.lock
42 | /coverage
43 | /libpeerconnection.log
44 | npm-debug.log
45 | yarn-error.log
46 | testem.log
47 | /typings
48 |
49 | # System Files
50 | .DS_Store
51 | Thumbs.db
52 |
53 | # cache
54 | .angular
--------------------------------------------------------------------------------
/src/projects/ui/src/assets/scss/_variables.scss:
--------------------------------------------------------------------------------
1 | $ngx-fileupload-icons--font-family: "ngx-fileupload" !default;
2 | $ngx-fileupload-icons--font-path: "fonts" !default;
3 |
4 | $ngx-fileupload-icons--font-size: 1rem;
5 | $ngx-fileupload-icons--line-height: 1rem;
6 |
7 | $ngx-fileupload-icon--connect: "\f07e";
8 | $ngx-fileupload-icon--upload: "\e900";
9 | $ngx-fileupload-icon--pending: "\e94e";
10 | $ngx-fileupload-icon--idle: "\e979";
11 | $ngx-fileupload-icon--reload: "\e984";
12 | $ngx-fileupload-icon--error: "\ea07";
13 | $ngx-fileupload-icon--remove: "\ea0d";
14 | $ngx-fileupload-icon--canceled: "\ea0e";
15 | $ngx-fileupload-icon--success: "\ea10";
16 | $ngx-fileupload-icon--progress: "\ea2e";
17 | $ngx-fileupload-icon--plus: "\ea0a";
18 |
19 | $colors: (
20 | "success": #4BB543,
21 | "green": #4BB543,
22 | "progress": #0073B1,
23 | "red": #D8000C,
24 | "black": #222222,
25 | "dark": #37474f,
26 | "white": #FFFFFF,
27 | "light": #DEE4E7
28 | );
29 |
--------------------------------------------------------------------------------
/.github/workflows/ngx-file-upload-ui.yml:
--------------------------------------------------------------------------------
1 | name: ngx-file-upload/ui
2 |
3 | on: [push]
4 |
5 | jobs:
6 |
7 | install:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@v2
12 |
13 | - name: Setup NodeJS
14 | uses: actions/setup-node@v2
15 | with:
16 | node-version: '20.9.0'
17 |
18 | - name: install dependencies
19 | if: steps.npm-cache.outputs.cache-hit != 'true'
20 | run: |
21 | cd src
22 | npm i
23 | npm i puppeteer@chrome-78
24 | npm run webdriver:update
25 |
26 | - name: add @angular/cli global
27 | run: |
28 | npm i -g @angular/cli@17.3.4
29 | ng version
30 |
31 | - name: lint
32 | run: |
33 | cd src
34 | npm run lint -- ui
35 |
36 | - name: build packages
37 | run: |
38 | cd src
39 | npm run build -- core
40 | npm run build -- ui
41 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/code/validation/group-multiple.ts:
--------------------------------------------------------------------------------
1 | export * from "./is-image";
2 |
3 | export const validationGroupMultiple = `
4 | import { Component, OnInit } from "@angular/core";
5 | import { isImage, isZipFile, MaxUploadSizeValidator } from "@ngx-fileupload-example/utils/validators";
6 | import { NgxFileUploadValidationBuilder, NgxFileUploadGroupedvalidator } from "@ngx-file-upload/core";
7 |
8 | @Component({
9 | selector: "app-validation--group-multiple",
10 | templateUrl: "group-multiple.component.html"
11 | })
12 | export class GroupMultipleComponent implements OnInit {
13 |
14 | public validator: NgxFileUploadGroupedvalidator;
15 |
16 | public ngOnInit() {
17 | const zipOrImage = NgxFileUploadValidationBuilder.or(isImage, isZipFile);
18 | const maxSize = new MaxUploadSizeValidator(512 * 1024);
19 |
20 | /** bring all together */
21 | this.validator = NgxFileUploadValidationBuilder.and(zipOrImage, maxSize);
22 | }
23 | }`;
24 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/group-or/group-or.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from "@angular/core";
2 | import { isImage, isZipFile } from "projects/example/libs/utils/validators";
3 | import { NgxFileUploadValidationBuilder, NgxFileUploadGroupedvalidator } from "@ngx-file-upload/core";
4 | import * as ExampleCode from "projects/example/libs/data/code/validation/group-or";
5 | import * as Validators from "projects/example/libs/data/code/utils/validators";
6 |
7 | @Component({
8 | selector: "app-validation--group-or",
9 | templateUrl: "group-or.component.html"
10 | })
11 | export class GroupOrComponent implements OnInit {
12 |
13 | public validator: NgxFileUploadGroupedvalidator | undefined;
14 |
15 | public exampleCode = ExampleCode;
16 |
17 | public codeValidator = Validators;
18 |
19 | public ngOnInit() {
20 |
21 | this.validator = NgxFileUploadValidationBuilder.or(
22 | isImage, isZipFile
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/projects/ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@ngx-file-upload/ui",
3 | "version": "9.0.0",
4 | "description": "Angular 17 file upload components for @ngx-file-upload/core",
5 | "repository": {
6 | "url": "https://github.com/r-hannuschka/ngx-fileupload/tree/master/src/projects/ui",
7 | "type": "git"
8 | },
9 | "license": "MIT",
10 | "keywords": [
11 | "ngx",
12 | "async",
13 | "angular",
14 | "angular 17",
15 | "file",
16 | "upload",
17 | "fileupload",
18 | "progressbar",
19 | "upload queue",
20 | "queue"
21 | ],
22 | "peerDependencies": {
23 | "@ngx-file-upload/core": "^9.0.0",
24 | "@angular/common": "^17.0.0",
25 | "@angular/core": "^17.0.0"
26 | },
27 | "author": "Ralf Hannuschka (https://github.com/r-hannuschka)",
28 | "bugs": {
29 | "url": "https://github.com/r-hannuschka/ngx-fileupload/issues"
30 | },
31 | "dependencies": {
32 | "tslib": "2.3.1"
33 | },
34 | "homepage": "https://r-hannuschka.github.io/ngx-fileupload"
35 | }
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/src/projects/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@ngx-file-upload/core",
3 | "version": "9.0.0",
4 | "description": "Angular 17 file upload core package for async file uploads in angular containing validation, upload queue and async uploading.",
5 | "repository": {
6 | "url": "https://github.com/r-hannuschka/ngx-fileupload/tree/master/src/projects/core",
7 | "type": "git"
8 | },
9 | "license": "MIT",
10 | "keywords": [
11 | "ngx",
12 | "async",
13 | "angular",
14 | "angular 17",
15 | "file",
16 | "upload",
17 | "fileupload",
18 | "progressbar",
19 | "upload queue",
20 | "queue"
21 | ],
22 | "peerDependencies": {
23 | "@angular/common": "^17.0.0",
24 | "@angular/core": "^17.0.0"
25 | },
26 | "author": "Ralf Hannuschka (https://github.com/r-hannuschka)",
27 | "bugs": {
28 | "url": "https://github.com/r-hannuschka/ngx-fileupload/issues"
29 | },
30 | "dependencies": {
31 | "tslib": "2.3.1"
32 | },
33 | "homepage": "https://r-hannuschka.github.io/ngx-fileupload"
34 | }
35 |
--------------------------------------------------------------------------------
/src/projects/core/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../.eslintrc.json",
3 | "ignorePatterns": [
4 | "!**/*"
5 | ],
6 | "overrides": [
7 | {
8 | "files": [
9 | "*.ts"
10 | ],
11 | "parserOptions": {
12 | "project": [
13 | "projects/core/tsconfig.lib.json",
14 | "projects/core/tsconfig.spec.json"
15 | ],
16 | "createDefaultProgram": true
17 | },
18 | "rules": {
19 | "@angular-eslint/directive-selector": [
20 | "error",
21 | {
22 | "type": "attribute",
23 | "prefix": "lib",
24 | "style": "camelCase"
25 | }
26 | ],
27 | "@angular-eslint/component-selector": [
28 | "error",
29 | {
30 | "type": "element",
31 | "prefix": "lib",
32 | "style": "kebab-case"
33 | }
34 | ]
35 | }
36 | },
37 | {
38 | "files": [
39 | "*.html"
40 | ],
41 | "rules": {}
42 | }
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/src/projects/ui/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../.eslintrc.json",
3 | "ignorePatterns": [
4 | "!**/*"
5 | ],
6 | "overrides": [
7 | {
8 | "files": [
9 | "*.ts"
10 | ],
11 | "parserOptions": {
12 | "project": [
13 | "projects/ui/tsconfig.lib.json",
14 | "projects/ui/tsconfig.spec.json"
15 | ],
16 | "createDefaultProgram": true
17 | },
18 | "rules": {
19 | "@angular-eslint/directive-selector": [
20 | "error",
21 | {
22 | "type": "attribute",
23 | "prefix": "ngxFileUpload",
24 | "style": "camelCase"
25 | }
26 | ],
27 | "@angular-eslint/component-selector": [
28 | "error",
29 | {
30 | "type": "element",
31 | "prefix": "ngx-file-upload",
32 | "style": "kebab-case"
33 | }
34 | ]
35 | }
36 | },
37 | {
38 | "files": [
39 | "*.html"
40 | ],
41 | "rules": {}
42 | }
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/drop-zone/src/drop-zone.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from "@angular/common";
2 | import { NgModule } from "@angular/core";
3 | import { RouterModule } from "@angular/router";
4 | import { NgxFileUploadUiProgressbarModule, NgxFileUploadUiCommonModule, NgxFileUploadUiToolbarModule } from "@ngx-file-upload/ui";
5 | import { IgxTabsModule } from "igniteui-angular";
6 | import { HighlightModule } from "ngx-highlightjs";
7 |
8 | import { DropZoneComponent } from "./ui/drop-zone";
9 |
10 | @NgModule({
11 | imports: [
12 | CommonModule,
13 | NgxFileUploadUiToolbarModule,
14 | NgxFileUploadUiProgressbarModule,
15 | NgxFileUploadUiCommonModule,
16 | IgxTabsModule,
17 | HighlightModule,
18 | RouterModule.forChild([
19 | {
20 | path: "drop-zone",
21 | component: DropZoneComponent
22 | }
23 | ])
24 | ],
25 | exports: [RouterModule],
26 | declarations: [DropZoneComponent],
27 | providers: []
28 | })
29 | export class DropZone { }
30 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/ngx-dropzone/src/page.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from "@angular/common";
2 | import { NgModule } from "@angular/core";
3 | import { RouterModule } from "@angular/router";
4 | import { IgxTabsModule } from "igniteui-angular";
5 | import { HighlightModule } from "ngx-highlightjs";
6 |
7 | import { NgxDropZoneDemoComponent } from "./ngx-dropzone";
8 | import { NgxFileUploadUiProgressbarModule, NgxFileUploadUiCommonModule, NgxFileUploadUiToolbarModule } from "@ngx-file-upload/ui";
9 |
10 | @NgModule({
11 | imports: [
12 | CommonModule,
13 | IgxTabsModule,
14 | HighlightModule,
15 | NgxFileUploadUiCommonModule,
16 | NgxFileUploadUiToolbarModule,
17 | NgxFileUploadUiProgressbarModule,
18 | RouterModule.forChild([
19 | {
20 | path: "ngx-dropzone",
21 | component: NgxDropZoneDemoComponent
22 | }
23 | ])
24 | ],
25 | exports: [RouterModule],
26 | declarations: [NgxDropZoneDemoComponent],
27 | providers: []
28 | })
29 | export class Page { }
30 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/customize/src/customize.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { RouterModule } from "@angular/router";
3 | import { CommonModule } from "@angular/common";
4 | import { HighlightModule } from "ngx-highlightjs";
5 | import { NgxFileUploadUiProgressbarModule, NgxFileUploadUiCommonModule } from "@ngx-file-upload/ui";
6 | import { IgxTabsModule } from "igniteui-angular";
7 |
8 | import { UiModule } from "projects/example/libs/ui";
9 | import { ItemTemplateRoutes } from "./routes";
10 |
11 | import { ItemTemplateComponent } from "./item-template/item-template.component";
12 |
13 | @NgModule({
14 | imports: [
15 | CommonModule,
16 | RouterModule.forChild(ItemTemplateRoutes),
17 | NgxFileUploadUiProgressbarModule,
18 | NgxFileUploadUiCommonModule,
19 | UiModule,
20 | HighlightModule,
21 | IgxTabsModule
22 | ],
23 | exports: [
24 | RouterModule
25 | ],
26 | declarations: [
27 | ItemTemplateComponent
28 | ],
29 | providers: []
30 | })
31 | export class CustomizePage {}
32 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/is-image/is-image.component.html:
--------------------------------------------------------------------------------
1 | Add single NgxFileUploadValidator
2 |
3 |
4 |
5 |
6 | Demo
7 |
8 |
9 |
10 |
11 |
12 |
13 | Typescript
14 |
15 |
16 |
17 |
18 |
19 |
20 | Html
21 |
22 |
23 |
24 |
25 |
26 |
27 | NgxFileUploadValidator: isImage
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/common/src/state-to-string.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from "@angular/core";
2 | import { NgxFileUploadState } from "@ngx-file-upload/core";
3 |
4 | /**
5 | * converts upload state to string value
6 | *
7 | * @example
8 | * {{upload.state | stateToString}}
9 | * // prints one of these idle, pending, progress, completed, start, invalid, canceled
10 | */
11 | @Pipe({
12 | name: "stateToString"
13 | })
14 | export class StateToStringPipe implements PipeTransform {
15 |
16 | transform(state: NgxFileUploadState): string {
17 |
18 | switch (state) {
19 | case NgxFileUploadState.CANCELED: return "canceled";
20 | case NgxFileUploadState.PENDING: return "pending";
21 | case NgxFileUploadState.PROGRESS: return "progress";
22 | case NgxFileUploadState.COMPLETED: return "completed";
23 | case NgxFileUploadState.START: return "start";
24 | case NgxFileUploadState.INVALID: return "invalid";
25 | default: return "idle";
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/bin/youtube.badge.svg:
--------------------------------------------------------------------------------
1 | Howto: Youtube Howto Howto Youtube YouTube
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Ralf Hannuschka
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/group-and/group-and.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from "@angular/core";
2 | import { isImage, MaxUploadSizeValidator } from "projects/example/libs/utils/validators";
3 | import { NgxFileUploadValidationBuilder, NgxFileUploadGroupedvalidator } from "@ngx-file-upload/core";
4 | import * as ExampleCode from "projects/example/libs/data/code/validation/group-and";
5 | import * as Validators from "projects/example/libs/data/code/utils/validators";
6 |
7 | @Component({
8 | selector: "app-validation--group-and",
9 | templateUrl: "group-and.component.html"
10 | })
11 | export class GroupAndComponent implements OnInit {
12 |
13 | public validator: NgxFileUploadGroupedvalidator | undefined;
14 |
15 | public exampleCode = ExampleCode;
16 |
17 | public codeValidator = Validators;
18 |
19 | public ngOnInit() {
20 |
21 | /** set max file upload size to 512kb */
22 | const maxUploadSize: number = 512 * 1024;
23 |
24 | this.validator = NgxFileUploadValidationBuilder.and(
25 | isImage, new MaxUploadSizeValidator(maxUploadSize)
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/e2e/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // Protractor configuration file, see link for more information
3 | // https://github.com/angular/protractor/blob/master/lib/config.ts
4 |
5 | const { SpecReporter } = require("jasmine-spec-reporter");
6 |
7 | /**
8 | * @type { import("protractor").Config }
9 | */
10 | exports.config = {
11 | SELENIUM_PROMISE_MANAGER: false,
12 | allScriptsTimeout: 11000,
13 | specs: [
14 | "./src/integration/**/*.spec.ts"
15 | ],
16 | capabilities: {
17 | "browserName": "chrome",
18 | "chromeOptions": {
19 | args: [
20 | "--window-size=800,600",
21 | // set log level to error
22 | "--log-level=0"
23 | ]
24 | },
25 | },
26 |
27 | directConnect: true,
28 | baseUrl: "http://localhost:4201/",
29 | framework: "jasmine",
30 | jasmineNodeOpts: {
31 | showColors: true,
32 | defaultTimeoutInterval: 30000,
33 | print: () => {}
34 | },
35 | onPrepare() {
36 |
37 | require("ts-node").register({
38 | project: require("path").join(__dirname, "./tsconfig.json")
39 | });
40 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/group-multiple/group-multiple.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from "@angular/core";
2 | import { isImage, isZipFile, MaxUploadSizeValidator } from "projects/example/libs/utils/validators";
3 | import { NgxFileUploadValidationBuilder, NgxFileUploadGroupedvalidator } from "@ngx-file-upload/core";
4 | import * as ExampleCode from "projects/example/libs/data/code/validation/group-multiple";
5 | import * as Validators from "projects/example/libs/data/code/utils/validators";
6 |
7 | @Component({
8 | selector: "app-validation--group-multiple",
9 | templateUrl: "group-multiple.component.html"
10 | })
11 | export class GroupMultipleComponent implements OnInit {
12 |
13 | public validator: NgxFileUploadGroupedvalidator | undefined;
14 |
15 | public exampleCode = ExampleCode;
16 |
17 | public codeValidator = Validators;
18 |
19 | public ngOnInit() {
20 | const zipOrImage = NgxFileUploadValidationBuilder.or(isImage, isZipFile);
21 | const maxSize = new MaxUploadSizeValidator(512 * 1024);
22 |
23 | /** bring all together with and */
24 | this.validator = NgxFileUploadValidationBuilder.and(zipOrImage, maxSize);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/projects/example/assets/img/Npm-01.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
12 |
14 |
15 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "ignorePatterns": [
4 | "projects/**/*"
5 | ],
6 | "overrides": [
7 | {
8 | "files": [
9 | "*.ts"
10 | ],
11 | "parserOptions": {
12 | "project": [
13 | "tsconfig.json",
14 | "e2e/tsconfig.json"
15 | ],
16 | "createDefaultProgram": true
17 | },
18 | "extends": [
19 | "plugin:@angular-eslint/recommended",
20 | "plugin:@angular-eslint/template/process-inline-templates"
21 | ],
22 | "rules": {
23 | "@angular-eslint/component-selector": [
24 | "error",
25 | {
26 | "prefix": "lib",
27 | "style": "kebab-case",
28 | "type": "element"
29 | }
30 | ],
31 | "@angular-eslint/directive-selector": [
32 | "error",
33 | {
34 | "prefix": "lib",
35 | "style": "camelCase",
36 | "type": "attribute"
37 | }
38 | ]
39 | }
40 | },
41 | {
42 | "files": [
43 | "*.html"
44 | ],
45 | "extends": [
46 | "plugin:@angular-eslint/template/recommended"
47 | ],
48 | "rules": {}
49 | }
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/src/projects/example/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from "@angular/core";
2 | import { environment } from "../environments/environment";
3 | import { MenuItem, MainMenuItems } from "projects/example/libs/data/base/data";
4 | import { Router, NavigationEnd, ActivatedRoute } from "@angular/router";
5 | import { filter } from "rxjs/operators";
6 |
7 | @Component({
8 | selector: "app-root",
9 | templateUrl: "./app.component.html",
10 | styleUrls: ["./app.component.scss"]
11 | })
12 | export class AppComponent implements OnInit {
13 | title = "ngx-fileupload";
14 |
15 | public disableAnimations = false;
16 |
17 | public menuItems: MenuItem[] = MainMenuItems;
18 |
19 | public showUploadOverlay = false;
20 |
21 | constructor(
22 | private router: Router,
23 | private activatedRoute: ActivatedRoute
24 | ) {
25 | this.disableAnimations = environment.disableAnimations || false;
26 | }
27 |
28 | public ngOnInit() {
29 | this.router.events
30 | .pipe(filter((event) => event instanceof NavigationEnd))
31 | .subscribe({
32 | next: () => {
33 | this.showUploadOverlay = this.activatedRoute.snapshot.firstChild?.data.uploadOverlay || false;
34 | }
35 | });
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/toolbar/src/toolbar.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{i18n?.UPLOAD_ALL || "Upload all"}}
5 |
6 |
7 | {{i18n?.CLEAN_UP || "Clear"}}
8 |
9 |
10 | {{i18n?.REMOVE_ALL || "Remove"}}
11 |
12 |
13 |
14 |
15 | {{ i18n?.UPLOADS || "Uploads" }}:
16 |
17 |
18 |
19 | {{uploadInfo.progress}}
20 |
21 |
22 |
23 | {{uploadInfo.pending}}
24 |
25 |
26 |
27 | {{uploadInfo.idle}}
28 |
29 |
30 |
31 | {{uploadInfo.error}}
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.github/workflows/ngx-file-upload-core.yml:
--------------------------------------------------------------------------------
1 | name: ngx-file-upload/core
2 |
3 | on: [push]
4 |
5 | jobs:
6 |
7 | install:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@v2
12 |
13 | - name: Setup NodeJS
14 | uses: actions/setup-node@v2
15 | with:
16 | node-version: '20.9.0'
17 |
18 | - name: install dependencies
19 | run: |
20 | cd src
21 | npm i
22 | npm i puppeteer@chrome-78
23 | npm run webdriver:update
24 |
25 | - name: add @angular/cli global
26 | run: |
27 | npm i -g @angular/cli@17.3.4
28 | ng version
29 |
30 | - name: lint
31 | run: |
32 | cd src
33 | npm run lint -- core
34 |
35 | - name: build packages
36 | run: |
37 | cd src
38 | npm run build -- core
39 |
40 | - name: unit tests
41 | run: |
42 | cd src
43 | npm run github-actions:unit-tests-core
44 |
45 | - name: codecov
46 | uses: codecov/codecov-action@v2
47 | with:
48 | token: ${{ secrets.CODECOV_TOKEN }} #required
49 | file: ./src/coverage/core/report-lcov/lcov.info
50 | flags: core
51 |
--------------------------------------------------------------------------------
/src/projects/example/libs/utils/validators/src/max-size.validator.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadValidator, NgxFileUploadValidationErrors } from "@ngx-file-upload/core";
2 |
3 | export class MaxUploadSizeValidator implements NgxFileUploadValidator {
4 |
5 | private units = ["Byte", "kb", "mb", "gb"];
6 |
7 | /**
8 | * default maxupload size 1Mb as byte
9 | */
10 | private maxSize: number;
11 |
12 | /**
13 | * constructor pass max upload size in byte
14 | */
15 | public constructor(size: number) {
16 | this.maxSize = size || 1024 * 1024;
17 | }
18 |
19 | public validate(file: File): NgxFileUploadValidationErrors | null {
20 | if (file.size / this.maxSize > 1) {
21 | return {
22 | maxFileSizeValidator: `max file size ${this.toUnits(this.maxSize)}`
23 | };
24 | }
25 | return null;
26 | }
27 |
28 | private toUnits(size: number): string {
29 | let unitIndex = 0;
30 | let totalSize = size;
31 |
32 | while (totalSize > 1024 && unitIndex < this.units.length) {
33 | totalSize = totalSize / 1024;
34 | unitIndex++;
35 | }
36 |
37 | return `${totalSize.toFixed(2)} ${this.units[unitIndex]}`;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/ui.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { CommonModule } from "@angular/common";
3 |
4 | import { UploadViewComponent } from "./common/src/upload-view";
5 |
6 | import { NgxFileUploadUiToolbarModule } from "./toolbar/main";
7 | import { NgxFileUploadUiProgressbarModule } from "./progressbar/main";
8 | import { NgxFileUploadUiFileBrowserModule } from "./file-browser/main";
9 | import { NgxFileUploadUiItemModule } from "./upload-item/main";
10 | import { NgxFileUploadUiCommonModule } from "./common/main";
11 |
12 | @NgModule({
13 | declarations: [
14 | UploadViewComponent,
15 | ],
16 | imports: [
17 | CommonModule,
18 | NgxFileUploadUiProgressbarModule,
19 | NgxFileUploadUiCommonModule,
20 | NgxFileUploadUiToolbarModule,
21 | NgxFileUploadUiItemModule,
22 | NgxFileUploadUiFileBrowserModule
23 | ],
24 | exports: [
25 | NgxFileUploadUiCommonModule,
26 | NgxFileUploadUiProgressbarModule,
27 | NgxFileUploadUiCommonModule,
28 | NgxFileUploadUiToolbarModule,
29 | NgxFileUploadUiItemModule,
30 | NgxFileUploadUiFileBrowserModule,
31 | UploadViewComponent,
32 | ]
33 | })
34 | export class NgxFileUploadUiModule {}
35 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/drop-zone/src/ui/drop-zone.scss:
--------------------------------------------------------------------------------
1 | @import "variables";
2 |
3 | :host {
4 |
5 | .files {
6 | height: 30vh;
7 | overflow-y: auto;
8 | padding: 0 1rem;
9 | border: 1px solid map-get($colors, darkBlue);
10 | border-top-width: 0;
11 |
12 | .upload {
13 | margin: 0 0 1rem;
14 | &:last-child { margin: 0; }
15 | }
16 |
17 | .upload .data {
18 | display: flex;
19 |
20 | span:first-child:after {
21 | content: "";
22 | border: 1px solid map-get($colors, darkBlue);
23 | border-width: 0 1px 0 0;
24 | margin: 0 0 0 .5rem;
25 | }
26 |
27 | span:nth-child(2) {
28 | margin: 0 .5rem;
29 | }
30 |
31 | .uploaded {
32 | flex: 1;
33 | }
34 | }
35 | }
36 |
37 | ::ng-deep {
38 | .ngx-fileupload__ngx-file-drop {
39 | border: 1px solid map-get($colors, darkBlue);
40 |
41 | .ngx-file-drop__content {
42 | height: auto;
43 | padding: 1rem;
44 | }
45 | }
46 |
47 | .ngx-file-drop__drop-zone-label {
48 | margin-right: .4rem;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/ui/icons.ts:
--------------------------------------------------------------------------------
1 | export const GITHUB = `GitHub icon `;
2 | export const NPM = `
3 |
4 |
5 |
6 |
7 |
8 | `;
9 |
--------------------------------------------------------------------------------
/docs/ui/upload-component.md:
--------------------------------------------------------------------------------
1 | # Upload Component
2 |
3 | The Upload component is simply a default component to deliver a view and is not really required, you can allways use a complete diffrent view which implements fileupload core components [Upload Directive](./upload-directive.md) and [Upload Item](./upload-item.md).
4 |
5 | ## implement
6 |
7 | ```html
8 |
9 | ```
10 |
11 | ## @Input
12 |
13 | | name | type | description | mandatory |
14 | |---|---|---|---|
15 | | url | string | set url which should be used for http upload request | true |
16 | | formDataName | string | form data field name which will contain file, not used if useFormData is set to false ( default file ) | false |
17 | | template | TemplateRef | the template which should used to show upload informations | false |
18 | | useFormData | boolean | if set to false upload post request will add file into body (default true) instead of form data | false |
19 | | validator | Validator/ValidatorFn | pre validators for all files which will added | false |
20 | | storage | UploadStorage | UploadStorage which is used for all UploadRequests, if no one is passed it will create one | false |
21 |
22 | ## Further reading
23 |
24 | - [Upload Directive](./upload-directive.md)
25 | - [Upload Item](./upload-item.md)
26 | - [Validation](./validation.md)
--------------------------------------------------------------------------------
/src/projects/ui/src/tests/utils/state-to-string.pipe.spec.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadState } from "@ngx-file-upload/core";
2 | import { StateToStringPipe } from "@ngx-file-upload/dev/ui/lib/common/src/state-to-string.pipe";
3 |
4 | describe("ngx-file-upload/libs/utils/state-to-string.pipe", () => {
5 |
6 | let pipe: StateToStringPipe;
7 |
8 | beforeEach(() => {
9 | pipe = new StateToStringPipe();
10 | });
11 |
12 | it ("should return idle", () => {
13 | expect(pipe.transform(NgxFileUploadState.IDLE)).toBe("idle");
14 | });
15 |
16 | it ("should return pending", () => {
17 | expect(pipe.transform(NgxFileUploadState.PENDING)).toBe("pending");
18 | });
19 |
20 | it ("should return canceled", () => {
21 | expect(pipe.transform(NgxFileUploadState.CANCELED)).toBe("canceled");
22 | });
23 |
24 | it ("should return invalid", () => {
25 | expect(pipe.transform(NgxFileUploadState.INVALID)).toBe("invalid");
26 | });
27 |
28 | it ("should return progress", () => {
29 | expect(pipe.transform(NgxFileUploadState.PROGRESS)).toBe("progress");
30 | });
31 |
32 | it ("should return start", () => {
33 | expect(pipe.transform(NgxFileUploadState.START)).toBe("start");
34 | });
35 |
36 | it ("should return completed", () => {
37 | expect(pipe.transform(NgxFileUploadState.COMPLETED)).toBe("completed");
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/src/projects/ui/src/tests/utils/upload.control.spec.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadRequest } from "@ngx-file-upload/core";
2 | import { Control } from "@ngx-file-upload/dev/ui/public-api";
3 |
4 | import { fakeAsync, tick } from "@angular/core/testing";
5 | describe("ngx-fileupload/libs/upload/upload-control", () => {
6 |
7 | let fileUpload: NgxFileUploadRequest;
8 | let uploadCtrl: Control;
9 |
10 | beforeEach(() => {
11 | fileUpload = jasmine.createSpyObj("NgxFileUploadRequest", {
12 | retry: () => {},
13 | start: () => {},
14 | cancel: () => {},
15 | destroy: () => {}
16 | });
17 | uploadCtrl = new Control(fileUpload);
18 | });
19 |
20 | it ("should call retry", () => {
21 | uploadCtrl.retry();
22 | expect(fileUpload.retry).toHaveBeenCalled();
23 | });
24 |
25 | it ("should call start", () => {
26 | uploadCtrl.start();
27 | expect(fileUpload.start).toHaveBeenCalled();
28 | });
29 |
30 | it ("should call stop", fakeAsync(() => {
31 | uploadCtrl.stop();
32 | tick(0);
33 | expect(fileUpload.cancel).toHaveBeenCalled();
34 | }));
35 |
36 | it ("should call remove", fakeAsync(() => {
37 | const event = new MouseEvent("click");
38 | uploadCtrl.remove(event);
39 | tick(0);
40 | expect(fileUpload.destroy).toHaveBeenCalled();
41 | }));
42 | });
43 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/auto-upload/src/demo/demo.html:
--------------------------------------------------------------------------------
1 | Automatic Upload
2 |
3 |
4 | To enable uploads starts automatically if added to storage, you have to set StorageConfiguration.enableAutoUpload to true. Default value is false.
5 |
6 |
7 |
13 |
14 |
15 |
16 |
17 |
18 | Demo
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | Typescript
28 |
29 |
30 |
31 |
32 |
33 |
34 | Html
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/validation/src/grouped.validator.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadValidationErrors, NgxFileUploadValidation, NgxFileUploadValidator } from "../../api";
2 |
3 | export abstract class NgxFileUploadGroupedvalidator implements NgxFileUploadValidator {
4 |
5 | protected validators: Array;
6 |
7 | public constructor(
8 | validators?: Array
9 | ) {
10 | this.validators = Array.isArray(validators) ? validators : [];
11 | }
12 |
13 | public abstract validate(file: File): NgxFileUploadValidationErrors | null;
14 |
15 | /**
16 | * add validators
17 | */
18 | public add(...validators: Array): void {
19 | this.validators = this.validators.concat(validators);
20 | }
21 |
22 | /**
23 | * clean up all validators
24 | */
25 | public clean() {
26 | this.validators = [];
27 | }
28 |
29 | /**
30 | * executes validator and returns validation result
31 | */
32 | protected execValidator(
33 | validator: NgxFileUploadValidation,
34 | file: File
35 | ): NgxFileUploadValidationErrors | null {
36 | /** we handle a validator class directly */
37 | if ("validate" in validator) {
38 | return validator.validate(file);
39 | }
40 | /** we handle a validation function */
41 | return validator(file);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/ui.module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from "@angular/common";
2 | import { NgModule } from "@angular/core";
3 |
4 | import { HeaderComponent } from "./header/header.component";
5 | import { HeaderMenuComponent } from "./header-menu/header-menu.component";
6 | import { RouterModule } from "@angular/router";
7 | import { ButtonComponent } from "./button/button.component";
8 | import { UploadToolbarComponent } from "./upload-toolbar/upload-toolbar.component";
9 | import { IgxIconModule, IgxIconService } from "igniteui-angular";
10 |
11 | import * as Icons from "projects/example/libs/data/ui/icons";
12 | import { NgxFileUploadUiModule } from "@ngx-file-upload/ui";
13 |
14 | @NgModule({
15 | imports: [
16 | CommonModule,
17 | RouterModule,
18 | IgxIconModule,
19 | NgxFileUploadUiModule,
20 | ],
21 | exports: [
22 | ButtonComponent,
23 | HeaderComponent,
24 | UploadToolbarComponent,
25 | ],
26 | declarations: [
27 | ButtonComponent,
28 | HeaderComponent,
29 | HeaderMenuComponent,
30 | UploadToolbarComponent,
31 | ],
32 | providers: [],
33 | })
34 | export class UiModule {
35 |
36 | public constructor(iconService: IgxIconService) {
37 | iconService.addSvgIconFromText("github", Icons.GITHUB, "ngx-fileupload-icons");
38 | iconService.addSvgIconFromText("npm", Icons.NPM, "ngx-fileupload-icons");
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/projects/ui/src/tests/utils/cancelable.pipe.spec.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadState } from "@ngx-file-upload/core";
2 | import { CancelAblePipe } from "@ngx-file-upload/dev/ui/lib/common/src/cancelable.pipe";
3 |
4 | describe("ngx-file-upload/libs/utils/cancelable.pipe", () => {
5 |
6 | let pipe: CancelAblePipe;
7 |
8 | beforeEach(() => {
9 | pipe = new CancelAblePipe();
10 | });
11 |
12 | it ("it should be cancelable if state is pending", () => {
13 | const result = pipe.transform(NgxFileUploadState.PENDING);
14 | expect(result).toBeTruthy();
15 | });
16 |
17 | it ("it should be cancelable if state is progress", () => {
18 | const result = pipe.transform(NgxFileUploadState.PROGRESS);
19 | expect(result).toBeTruthy();
20 | });
21 |
22 | it ("it should be cancelable if state is start", () => {
23 | const result = pipe.transform(NgxFileUploadState.START);
24 | expect(result).toBeTruthy();
25 | });
26 |
27 | it ("it should not be cancelable on state canceled, completed, invalid and idle", () => {
28 | const states = [NgxFileUploadState.CANCELED, NgxFileUploadState.COMPLETED, NgxFileUploadState.INVALID, NgxFileUploadState.IDLE];
29 | const result: boolean[] = states.map((state: NgxFileUploadState) => {
30 | return pipe.transform(state);
31 | });
32 |
33 | expect(result).toEqual([false, false, false, false]);
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/group-or/group-or.component.html:
--------------------------------------------------------------------------------
1 | Combine Multiple Validators (OR)
2 |
3 | Add 2 validators as group where at least one has to validate (OR), accept zip OR image files
4 |
5 |
6 |
7 |
8 | Demo
9 |
10 |
11 |
12 |
13 |
14 |
15 | Typescript
16 |
17 |
18 |
19 |
20 |
21 |
22 | Html
23 |
24 |
25 |
26 |
27 |
28 |
29 | NgxFileUploadValidator: isImage
30 |
31 |
32 |
33 |
34 |
35 |
36 | NgxFileUploadValidator: isZip
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/projects/testing/mockup/src/upload-model.ts:
--------------------------------------------------------------------------------
1 | import { INgxFileUploadFile, INgxFileUploadRequestData, INgxFileUploadRequestModel, NgxFileUploadFile, NgxFileUploadResponse, NgxFileUploadState, NgxFileUploadValidationErrors } from "@ngx-file-upload/core";
2 |
3 | const file = new File(["ngx file upload unit tests"], "upload-file.txt", {type: "plain/text"});
4 |
5 | export class NgxFileUploadRequestModel implements INgxFileUploadRequestModel {
6 |
7 | files: INgxFileUploadFile[] = [new NgxFileUploadFile(file)];
8 |
9 | validation: NgxFileUploadValidationErrors | null = null;
10 |
11 | isInvalid = false;
12 |
13 | size = 0;
14 |
15 | name = [""];
16 |
17 | type = "plain/text";
18 |
19 | response: NgxFileUploadResponse | null = null;
20 |
21 | isPending = false;
22 |
23 | state: NgxFileUploadState = NgxFileUploadState.IDLE;
24 |
25 | uploaded = 0;
26 |
27 | validationErrors: NgxFileUploadValidationErrors | null = null;
28 |
29 | progress = 0;
30 |
31 | isUploadAble = true;
32 |
33 | hasError = false;
34 |
35 | toJson(): INgxFileUploadRequestData {
36 | const jsonedObject: Record = {};
37 | for (const x in this) {
38 | if (x === "toJson" || x === "constructor") {
39 | continue;
40 | }
41 | jsonedObject[x] = this[x];
42 | }
43 | return jsonedObject as unknown as INgxFileUploadRequestData;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/group-and/group-and.component.html:
--------------------------------------------------------------------------------
1 | Combine Multiple Validators (and)
2 |
3 | Add 2 validators as group which have to validate both (AND), max file size are 512kb and it have to be an image.
4 |
5 |
6 |
7 |
8 | Demo
9 |
10 |
11 |
12 |
13 |
14 |
15 | Typescript
16 |
17 |
18 |
19 |
20 |
21 |
22 | Html
23 |
24 |
25 |
26 |
27 |
28 |
29 | NgxFileUploadValidator: isImage
30 |
31 |
32 |
33 |
34 |
35 |
36 | NgxFileUploadValidator: MaxSize
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/validation.module.ts:
--------------------------------------------------------------------------------
1 |
2 | import { NgModule } from "@angular/core";
3 | import { RouterModule } from "@angular/router";
4 | import { CommonModule } from "@angular/common";
5 | import { HighlightModule } from "ngx-highlightjs";
6 | import { IgxTabsModule } from "igniteui-angular";
7 |
8 | import { ValidationPageComponent } from "./validation-page/validation-page.component";
9 | import { IsImageValidationComponent } from "./is-image/is-image.component";
10 | import { GroupAndComponent } from "./group-and/group-and.component";
11 | import { GroupOrComponent } from "./group-or/group-or.component";
12 | import { GroupMultipleComponent } from "./group-multiple/group-multiple.component";
13 | import { NgxFileUploadUiModule } from "@ngx-file-upload/ui";
14 |
15 | @NgModule({
16 | imports: [
17 | CommonModule,
18 | RouterModule.forChild([{
19 | path: "validation",
20 | component: ValidationPageComponent,
21 | data: {
22 | uploadOverlay: true
23 | }
24 | }]),
25 | NgxFileUploadUiModule,
26 | HighlightModule,
27 | IgxTabsModule
28 | ],
29 | exports: [
30 | RouterModule
31 | ],
32 | declarations: [
33 | ValidationPageComponent,
34 | IsImageValidationComponent,
35 | GroupAndComponent,
36 | GroupOrComponent,
37 | GroupMultipleComponent
38 | ],
39 | providers: []
40 | })
41 | export class ValidationPage {}
42 |
--------------------------------------------------------------------------------
/src/projects/ui/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: "",
7 | frameworks: ["jasmine", "@angular-devkit/build-angular"],
8 | plugins: [
9 | require("karma-jasmine"),
10 | require("karma-chrome-launcher"),
11 | require("karma-jasmine-html-reporter"),
12 | require("karma-coverage-istanbul-reporter"),
13 | require("@angular-devkit/build-angular/plugins/karma"),
14 | require("karma-mocha-reporter")
15 | ],
16 | client: {
17 | clearContext: false // leave Jasmine Spec Runner output visible in browser
18 | },
19 | coverageIstanbulReporter: {
20 | dir: require("path").join(__dirname, "../../coverage/ui"),
21 | reports: ["html", "lcovonly", "text-summary"],
22 | fixWebpackSourcePaths: true
23 | },
24 | reporters: ["mocha"],
25 | port: 9876,
26 | colors: true,
27 | logLevel: config.LOG_INFO,
28 | autoWatch: true,
29 | browsers: ["ChromeHeadless"],
30 | customLaunchers: {
31 | ChromeHeadless: {
32 | base: "Chrome",
33 | flags: [
34 | "--headless",
35 | "--disable-gpu",
36 | "--no-sandbox",
37 | "--remote-debugging-port=9222"
38 | ]
39 | }
40 | },
41 | singleRun: false,
42 | restartOnFileChange: true
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/common/src/upload-view.scss:
--------------------------------------------------------------------------------
1 | $ngx-fileupload-icons--font-path: '../../../assets/fonts' !default;
2 |
3 | @import 'scss/variables';
4 | @import 'scss/icons';
5 |
6 | :host {
7 |
8 | display: flex;
9 | flex-direction: column;
10 |
11 | .fileupload {
12 | overflow: auto;
13 | display: flex;
14 | flex-direction: row-reverse;
15 | flex: 1;
16 | border: 1px solid #D2D2D2;
17 | }
18 |
19 | .file-upload--list {
20 | box-sizing: border-box;
21 | flex: 1;
22 | overflow-x: hidden;
23 | flex-shrink: 0;
24 | flex-grow: 0;
25 | flex-basis: 100%;
26 | padding: .5rem 1rem;
27 |
28 | max-height: 50vh;
29 | overflow-y: auto;
30 | }
31 |
32 | ngx-file-upload-ui--item:not(:last-child) {
33 | margin-bottom: .5rem;
34 | }
35 |
36 | .file-browser {
37 | padding: 1rem 0;
38 | cursor: pointer;
39 | display: flex;
40 | flex: 1;
41 | align-items: center;
42 | justify-content: center;
43 | flex-direction: column;
44 | color: map-get($colors, "dark");
45 |
46 | .ngx-fileupload-icon--add {
47 | font-size: 2.5rem;
48 | border: 1px dashed lighten(map-get($colors, "dark"), 40%);
49 | width: 4rem;
50 | line-height: 4rem;
51 | text-align: center;
52 | border-radius: 50%;
53 | margin-bottom: .5rem;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/projects/core/src/tests/validation/or.validator.spec.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadOrValidator } from "@ngx-file-upload/dev/core/public-api";
2 | import { ValidatorMockFactory } from "@ngx-file-upload/testing";
3 |
4 | describe("@ngx-file-upload/core/validation/or", () => {
5 |
6 | const uploadFile = new File([""], "or-validator-test.txt", { type: "text/plain"});
7 | let orValidationGroup: NgxFileUploadOrValidator;
8 |
9 | beforeAll(() => {
10 | orValidationGroup = new NgxFileUploadOrValidator();
11 | });
12 |
13 | beforeEach(() => {
14 | orValidationGroup.clean();
15 | });
16 |
17 | it ("it should validate", () => {
18 | orValidationGroup.add(ValidatorMockFactory.invalid(), ValidatorMockFactory.valid());
19 | expect(orValidationGroup.validate(uploadFile)).toBeNull();
20 | });
21 |
22 | it ("it should not validate", () => {
23 | orValidationGroup.add(ValidatorMockFactory.invalid(), ValidatorMockFactory.invalid());
24 | expect(orValidationGroup.validate(uploadFile)).not.toBeNull();
25 | });
26 |
27 | it ("should contain 2 errors", () => {
28 | orValidationGroup.add(
29 | ValidatorMockFactory.invalidFile(),
30 | ValidatorMockFactory.invalidFileSize()
31 | );
32 |
33 | const validationResult = orValidationGroup.validate(uploadFile);
34 | const validationKeys = Object.keys(validationResult ?? {});
35 |
36 | expect(validationKeys.length).toBe(2);
37 | expect(validationKeys).toEqual(["invalidFile", "invalidFileSize"]);
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/src/projects/core/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: "",
7 | frameworks: ["jasmine", "@angular-devkit/build-angular"],
8 | plugins: [
9 | require("karma-jasmine"),
10 | require("karma-chrome-launcher"),
11 | require("karma-jasmine-html-reporter"),
12 | require("karma-mocha-reporter"),
13 | require('karma-coverage'),
14 | require('@angular-devkit/build-angular/plugins/karma')
15 | ],
16 | client: {
17 | clearContext: false // leave Jasmine Spec Runner output visible in browser
18 | },
19 | coverageReporter: {
20 | dir: require("path").join(__dirname, "../../coverage/core"),
21 | reporters: [
22 | { type: 'html', subdir: 'report-html' },
23 | { type: 'lcov', subdir: 'report-lcov' },
24 | { type: 'text-summary', subdir: "text-summary"}
25 | ]
26 | },
27 | reporters: ["mocha"],
28 | port: 9876,
29 | colors: true,
30 | logLevel: config.LOG_INFO,
31 | autoWatch: true,
32 | browsers: ["ChromeHeadless"],
33 | customLaunchers: {
34 | ChromeHeadless: {
35 | base: "Chrome",
36 | flags: [
37 | "--headless",
38 | "--disable-gpu",
39 | "--no-sandbox",
40 | "--remote-debugging-port=9222"
41 | ]
42 | }
43 | },
44 | singleRun: false,
45 | restartOnFileChange: true
46 | });
47 | };
48 |
--------------------------------------------------------------------------------
/src/projects/example/libs/ui/src/upload-toolbar/upload-toolbar.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, Inject } from "@angular/core";
2 | import { NgxFileUploadValidator, NgxFileUploadStorage, NgxFileUploadOptions, NgxFileUploadFactory } from "@ngx-file-upload/core";
3 |
4 | @Component({
5 | selector: "app-ui--upload-toolbar",
6 | templateUrl: "upload-toolbar.component.html"
7 | })
8 | export class UploadToolbarComponent {
9 |
10 | @Input()
11 | validator: NgxFileUploadValidator | undefined;
12 |
13 | @Input()
14 | url: string | undefined;
15 |
16 | @Input()
17 | public storage: NgxFileUploadStorage | undefined;
18 |
19 | public constructor(
20 | @Inject(NgxFileUploadFactory) private uploadFactory: NgxFileUploadFactory
21 | ) {}
22 |
23 | public uploadAll() {
24 | if (this.storage) {
25 | this.storage.startAll();
26 | }
27 | }
28 |
29 | public purge() {
30 | if (this.storage) {
31 | this.storage.purge();
32 | }
33 | }
34 |
35 | public stop() {
36 | if (this.storage) {
37 | this.storage.stopAll();
38 | }
39 | }
40 |
41 | public drop(files: File[]) {
42 |
43 | if (this.url && this.storage) {
44 | const uploadOptions: NgxFileUploadOptions = { url: this.url, headers: { authorization: {token: "foofoo"}} };
45 | const uploads = this.uploadFactory.createUploadRequest(files, uploadOptions, this.validator)
46 |
47 | if (uploads) {
48 | this.storage.add(uploads);
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/projects/ui/src/tests/utils/file-size.pipe.spec.ts:
--------------------------------------------------------------------------------
1 | import { FileSizePipe } from "@ngx-file-upload/dev/ui/lib/common/src/file-size.pipe";
2 |
3 | describe("ngx-file-upload/libs/utils/file-size.pipe", () => {
4 |
5 | let pipe: FileSizePipe;
6 |
7 | beforeEach(() => {
8 | pipe = new FileSizePipe();
9 | });
10 |
11 | it ("should convert 1024 into 1 Kb", () => {
12 | const num = pipe.transform(1024);
13 | expect(num).toBe("1 Kb");
14 | });
15 |
16 | it ("should convert 1024 * 364 into 364 Kb", () => {
17 | const num = pipe.transform(1024 * 364);
18 | expect(num).toBe("364 Kb");
19 | });
20 |
21 | it ("should convert 1024 ^ 2 into 1 Mb", () => {
22 | const num = pipe.transform(Math.pow(1024, 2));
23 | expect(num).toBe("1 Mb");
24 | });
25 |
26 | it ("should convert 1024 ^ 3 into 1 Gb", () => {
27 | const num = pipe.transform(Math.pow(1024, 3));
28 | expect(num).toBe("1 Gb");
29 | });
30 |
31 | it ("should convert 1024 ^ 3 + 512 * 1024 * 1024 into 1.5 GiB", () => {
32 | const mb = Math.pow(1024, 2) * 512; // 1MB * 512 = 512MB
33 | const gb = Math.pow(1024, 3); // 1 GB
34 | expect(pipe.transform(gb + mb)).toBe("1.5 Gb");
35 | });
36 |
37 | it ("should get max 2 precision", () => {
38 | expect(pipe.transform((.5 * 1024 * 1024) / 3)).toEqual(`170.66 Kb`);
39 | });
40 |
41 | it ("should convert string to 1MByte", () => {
42 | const num = Math.pow(1024, 2).toString().concat("e") as any;
43 | expect(pipe.transform(num)).toEqual(`1 Mb`);
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/common/src/file-size.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from "@angular/core";
2 |
3 | /**
4 | * format byte value into human readable value
5 | *
6 | * @example
7 | * {{1024 | fileSize}}
8 | * // prints out 1Kb
9 | *
10 | */
11 | @Pipe({
12 | name: "fileSize"
13 | })
14 | export class FileSizePipe implements PipeTransform {
15 |
16 | private units = ["Byte", "Kb", "Mb", "Gb"];
17 |
18 | transform(size: number): string {
19 | let bytes = isNaN(size as number) ? parseFloat(size.toString()) : size;
20 | let unit = 0;
21 |
22 | while (bytes >= 1024 && this.units.length > unit) {
23 | bytes = bytes / 1024;
24 | unit++;
25 | }
26 |
27 | /**
28 | * sets a max precision to 2, remove trailing zeros, toFixed was not working
29 | * since this will fill up number with trailing zeros.
30 | *
31 | * steps:
32 | * 1. find all until this is not a .
33 | * 2. only match . if this is not followed by 2 zeros
34 | * 3. match any number
35 | * 4. match any char which is not a zero (0,1)
36 | *
37 | * will only works with numbers which will converted to string
38 | * and not with string
39 | *
40 | * @example
41 | * 123.001 becomes 123
42 | * 123.10 becomes 123.1
43 | * 123.01 becomes 123.01
44 | * 123.01231 becomes 123.01
45 | */
46 | const formatter = /^[^\.]+(\.(?!0{2})\d[^0]?)?/g;
47 | const total = bytes.toString().match(formatter)?.[0] ?? bytes.toString();
48 | return `${total} ${this.units[unit]}`;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/ngx-dropzone/src/ngx-dropzone.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | ngx dropzone is dead
4 |
5 |
6 |
7 | For this example we use ngx-dropzone
8 | library .
9 | We want only upload images and this library could also preview images which are uploaded very easy.
10 |
11 |
12 | upload only images
13 | start upload automaticalls
14 | remove upload if completed after 5 seconds
15 | concurrent uploads 2
16 |
17 |
18 |
19 |
20 | Demo
21 |
22 |
23 |
24 |
25 |
26 |
27 | Module
28 |
29 |
30 |
31 |
32 |
33 |
34 | Component
35 |
36 |
37 |
38 |
39 |
40 |
41 | Html
42 |
43 |
44 |
45 |
46 |
47 |
48 | Scss
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/ngx-dropzone/src/ngx-dropzone-demo.scss:
--------------------------------------------------------------------------------
1 |
2 | @import "variables";
3 |
4 | :host {
5 |
6 | ngx-dropzone {
7 | border-style: solid;
8 | border-width: 0 2px 2px;
9 | border-radius: 0;
10 | padding: .2rem .5rem .2rem 0;
11 | }
12 |
13 | ngx-dropzone-image-preview {
14 | height: 100%;
15 | position: relative;
16 | margin: 0 .5rem 0 0;
17 | }
18 |
19 | ngx-dropzone-label {
20 | top: 0;
21 | right: 0;
22 | left: 0;
23 | bottom: 0;
24 | display: flex;
25 | flex-direction: column;
26 | justify-content: space-between;
27 |
28 | span {
29 | color: #FFF;
30 | padding: 0 .3rem;
31 | text-align: left;
32 | }
33 |
34 | span.label {
35 | white-space: nowrap;
36 | overflow: hidden;
37 | text-overflow: ellipsis;
38 | }
39 | }
40 |
41 | ngx-file-upload-ui--progressbar-circle {
42 |
43 | ::ng-deep {
44 |
45 | svg {
46 | opacity: .8;
47 | height: 72px;
48 | width: 72px;
49 | }
50 |
51 | svg circle {
52 | stroke: darken(#FFF, 50%);
53 | stroke-width: .5rem;
54 |
55 | &.progress {
56 | stroke-width: .5rem;
57 | stroke: #FFF;
58 | }
59 | }
60 |
61 | span {
62 | font-size: .7rem;
63 | color: #FFF;
64 | }
65 | }
66 | }
67 |
68 | ::ng-deep {
69 |
70 | ngx-dropzone-remove-badge {
71 | z-index: 10;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/toolbar/src/toolbar.scss:
--------------------------------------------------------------------------------
1 | $ngx-fileupload-icons--font-path: '../../../assets/fonts' !default;
2 |
3 | @import 'scss/variables';
4 | @import 'scss/icons';
5 |
6 | :host {
7 | display: flex;
8 | background: map-get($colors, "dark");
9 | justify-content: space-between;
10 |
11 | .info {
12 | padding: 0 1rem;
13 | color: darken(map-get($colors, "light"), 10);
14 | display: flex;
15 | align-items: center;
16 |
17 | ul {
18 | margin: 0;
19 | padding: 0;
20 | list-style-type: none;
21 | display: flex;
22 | flex-direction: row;
23 | }
24 |
25 | li {
26 | display: flex;
27 | align-items: center;
28 | }
29 |
30 | i {
31 | color: inherit;
32 | margin: 0 .25rem 0 .5rem;
33 | align-self: stretch;
34 | line-height: 1.4rem;
35 |
36 | &[class$="upload"] {
37 | font-size: 1.1rem;
38 | }
39 | }
40 | }
41 |
42 | .actions {
43 | display: flex;
44 |
45 | button {
46 | display: flex;
47 | padding: .25rem .5rem;
48 | border: 0;
49 | align-items: center;
50 | color: map-get($map: $colors, $key: "light");
51 | background: transparent;
52 | cursor: pointer;
53 | outline: none;
54 |
55 | i {
56 | margin-right: .5rem;
57 | }
58 |
59 | &:last-child {
60 | margin: 0;
61 | }
62 |
63 | &[disabled] {
64 | color: darken(map-get($map: $colors, $key: "light"), 40);
65 | cursor: default;
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/i18n/src/i18n.ts:
--------------------------------------------------------------------------------
1 | import { InjectionToken, Inject, Optional, Injectable } from "@angular/core";
2 |
3 | export enum NgxFileUploadUiI18nKey {
4 | Common = "common",
5 | UploadItem = "item",
6 | ToolBar = "toolbar"
7 | }
8 |
9 | interface Labels {
10 | [key: string]: string;
11 | }
12 |
13 | export interface NgxFileUploadUiI18nCommon extends Labels {
14 | SELECT_FILES: string;
15 | }
16 |
17 | export interface NgxFileUploadUiI18nToolbar extends Labels {
18 | CLEAN_UP: string;
19 | REMOVE_ALL: string;
20 | UPLOAD_ALL: string;
21 | UPLOADS: string;
22 | }
23 |
24 | export interface NgxFileUploadUiI18nItem extends Labels {
25 | UPLOADED: string;
26 | }
27 |
28 | declare type NgxFileuploadI18nValue = NgxFileUploadUiI18nCommon | NgxFileUploadUiI18nItem | NgxFileUploadUiI18nToolbar | undefined;
29 |
30 | /** all labels which exists */
31 | export interface NgxFileUploadUiI18n {
32 | [key: string]: NgxFileUploadUiI18nCommon | NgxFileUploadUiI18nItem | NgxFileUploadUiI18nToolbar | undefined;
33 | common?: NgxFileUploadUiI18nCommon;
34 | item?: NgxFileUploadUiI18nItem;
35 | toolbar?: NgxFileUploadUiI18nToolbar;
36 | }
37 |
38 | /**
39 | * injection token
40 | */
41 | export const NGX_FILE_UPLOAD_UI_I18N = new InjectionToken("NgxFileUpload UI I18n labels");
42 |
43 | @Injectable({providedIn: "root"})
44 | export class NgxFileUploadUiI18nProvider {
45 |
46 | private labels: NgxFileUploadUiI18n;
47 |
48 | public constructor(
49 | @Optional() @Inject(NGX_FILE_UPLOAD_UI_I18N) labels: NgxFileUploadUiI18n
50 | ) {
51 | this.labels = labels || {};
52 | }
53 |
54 | public getI18n(k: NgxFileUploadUiI18nKey): T {
55 | return this.labels[k.toString()] as T;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/validation/src/group-multiple/group-multiple.component.html:
--------------------------------------------------------------------------------
1 | Nested Validation Groups
2 |
3 | Combine multiple groups, First Group will validate zip OR image. This result will combined with a third validator
4 | maxFileSize. So file will valid if we handle an image- or zip file and file size is less then or equal 512kb.
5 |
6 |
7 |
8 |
9 | Demo
10 |
11 |
12 |
13 |
14 |
15 |
16 | Typescript
17 |
18 |
19 |
20 |
21 |
22 |
23 | Html
24 |
25 |
26 |
27 |
28 |
29 |
30 | NgxFileUploadValidator: isImage
31 |
32 |
33 |
34 |
35 |
36 |
37 | NgxFileUploadValidator: isZip
38 |
39 |
40 |
41 |
42 |
43 |
44 | Demo
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/upload/src/upload.factory.ts:
--------------------------------------------------------------------------------
1 | import { InjectionToken, inject } from "@angular/core"
2 | import { HttpClient } from "@angular/common/http"
3 | import { INgxFileUploadFile, INgxFileUploadRequest, NgxFileUploadOptions, NgxFileUploadValidation } from "../../api"
4 | import { NgxFileUploadFile } from "./upload.model"
5 | import { NgxFileUploadRequest } from "./upload.request"
6 |
7 | export interface NgxFileUploadFactory {
8 | createUploadRequest(
9 | file: File | File[], options: NgxFileUploadOptions, validator?: NgxFileUploadValidation | null): INgxFileUploadRequest | null;
10 | }
11 |
12 | /**
13 | * Factory to create upload requests
14 | */
15 | class Factory implements NgxFileUploadFactory {
16 |
17 | /**
18 | * construct upload factory
19 | */
20 | public constructor(
21 | private httpClient: HttpClient
22 | ) {}
23 |
24 | public createUploadRequest(file: File | File[], options: NgxFileUploadOptions, validator?: NgxFileUploadValidation): INgxFileUploadRequest | null {
25 | const files = Array.isArray(file) ? file : [file]
26 |
27 | if (files.length) {
28 | const fileModels: INgxFileUploadFile[] = files.map((file) => {
29 | const model = new NgxFileUploadFile(file)
30 | if (validator) {
31 | model.validationErrors = "validate" in validator ? validator.validate(file) : validator(file)
32 | }
33 | return model
34 | })
35 |
36 | // * create one requests which holds all files
37 | return new NgxFileUploadRequest(this.httpClient, fileModels, options)
38 | }
39 |
40 | return null;
41 | }
42 | }
43 |
44 | /**
45 | * InjectionToken for NgxFileuploadFactory
46 | */
47 | export const NgxFileUploadFactory = new InjectionToken("Ngx Fileupload Factory", {
48 | providedIn: "root",
49 | factory: () => new Factory(inject(HttpClient))
50 | });
51 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/ngx-dropzone/src/ngx-dropzone.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Inject } from "@angular/core";
2 | import { NgxFileUploadStorage, NgxFileUploadFactory, NgxFileUploadOptions, INgxFileUploadRequest } from "@ngx-file-upload/core";
3 | import { NgxDropzoneChangeEvent } from "ngx-dropzone";
4 | import * as ExampleCodeData from "projects/example/libs/data/code/ngx-dropzone/drop-zone";
5 |
6 | @Component({
7 | selector: "app-ngx-dropzone-demo",
8 | templateUrl: "./ngx-dropzone.html",
9 | styleUrls: ["./ngx-dropzone-demo.scss"]
10 | })
11 | export class NgxDropZoneDemoComponent implements OnInit {
12 |
13 | public uploads: INgxFileUploadRequest[] = [];
14 |
15 | public code = ExampleCodeData;
16 |
17 | public storage: NgxFileUploadStorage;
18 |
19 | private uploadOptions: NgxFileUploadOptions;
20 |
21 | constructor(
22 | @Inject(NgxFileUploadFactory) private uploadFactory: NgxFileUploadFactory
23 | ) {
24 | this.storage = new NgxFileUploadStorage({
25 | concurrentUploads: 2,
26 | autoStart: true,
27 | removeCompleted: 5000 // remove completed after 5 seconds
28 | });
29 | this.uploadOptions = {
30 | url: "http://localhost:3000/upload",
31 | };
32 | }
33 |
34 | ngOnInit() {
35 | this.storage.change()
36 | .subscribe(uploads => this.uploads = uploads);
37 | }
38 |
39 | public onSelect(event: NgxDropzoneChangeEvent) {
40 | const addedFiles: File[] = event.addedFiles;
41 | const uploads = this.uploadFactory.createUploadRequest(addedFiles, this.uploadOptions);
42 |
43 | if (uploads) {
44 | this.storage.add(uploads);
45 | }
46 | }
47 |
48 | public onRemove(upload: INgxFileUploadRequest) {
49 | this.storage.remove(upload);
50 | }
51 |
52 | public startUploads() {
53 | this.storage.startAll();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/projects/core/src/lib/upload/src/upload.request.model.ts:
--------------------------------------------------------------------------------
1 | import { INgxFileUploadFile, INgxFileUploadRequestData, INgxFileUploadRequestModel, NgxFileUploadResponse, NgxFileUploadState, NgxFileUploadValidationErrors } from "../../api"
2 | import { NgxFileUploadFile } from "./upload.model"
3 |
4 | /**
5 | * Represents an upload request, and store the data inside
6 | */
7 | export class NgxFileUploadRequestModel implements INgxFileUploadRequestModel {
8 |
9 | private filesToUpload: NgxFileUploadFile[] = []
10 |
11 | constructor(file: INgxFileUploadFile | INgxFileUploadFile[]) {
12 | this.filesToUpload = !Array.isArray(file) ? [file] : file
13 | }
14 |
15 | get files(): NgxFileUploadFile[] {
16 | return this.filesToUpload
17 | }
18 |
19 | get name(): string[] {
20 | return this.files.map((file) => file.name)
21 | }
22 |
23 | get size(): number {
24 | return this.files.reduce((size, file) => size + file.size, 0)
25 | }
26 |
27 | get validationErrors(): NgxFileUploadValidationErrors | null {
28 | const validationErrors = this.files.reduce((errors, file) => {
29 | if (file.validationErrors) {
30 | errors[file.name] = {...file.validationErrors}
31 | }
32 | return errors
33 | }, {})
34 | return Object.keys(validationErrors).length ? validationErrors : null
35 | }
36 |
37 | response: NgxFileUploadResponse = {
38 | body: null,
39 | errors: null,
40 | success: false
41 | }
42 |
43 | state: NgxFileUploadState = NgxFileUploadState.IDLE
44 |
45 | uploaded = 0
46 |
47 | progress = 0
48 |
49 | hasError = false
50 |
51 | toJson(): INgxFileUploadRequestData {
52 | return {
53 | files: this.files,
54 | hasError: this.hasError,
55 | name: this.name,
56 | progress: this.progress,
57 | response: this.response,
58 | size: this.size,
59 | state: this.state,
60 | uploaded: this.uploaded,
61 | validationErrors: this.validationErrors
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/src/e2e/src/support/ngx-fileupload-ui/upload-toolbar.ts:
--------------------------------------------------------------------------------
1 | import { by, element, ElementArrayFinder, browser, ElementFinder } from "protractor";
2 |
3 | export class UploadToolbarPO {
4 |
5 | public get toolbar(): ElementFinder {
6 | return element(by.tagName("ngx-file-upload-ui--toolbar"));
7 | }
8 |
9 | public get removeButton(): ElementFinder {
10 | return this.toolbar.element(by.css(".remove-all"));
11 | }
12 |
13 | public get uploadButton(): ElementFinder {
14 | return this.toolbar.element(by.css(".upload-all"));
15 | }
16 |
17 | public get clearButton(): ElementFinder {
18 | return this.toolbar.element(by.css(".clean"));
19 | }
20 |
21 | public get infoBar(): ElementFinder {
22 | return this.toolbar.element(by.css(".info"));
23 | }
24 |
25 | public get uploadStates(): ElementArrayFinder {
26 | return this.infoBar.all(by.css("ul li"));
27 | }
28 |
29 | public get actionButtons(): ElementArrayFinder {
30 | return this.toolbar.all(by.css(".actions button"));
31 | }
32 |
33 | async uploadAll() {
34 | /** scroll to upload button to avoid element could not be clicked */
35 | const location = await this.uploadButton.getLocation();
36 | await browser.executeScript(`scrollTo(${location.y}, ${location.x})`);
37 | return this.uploadButton.click();
38 | }
39 |
40 | async removeAll() {
41 | /** scroll to upload button to avoid element could not be clicked */
42 | const location = await this.removeButton.getLocation();
43 | await browser.executeScript(`scrollTo(${location.y}, ${location.x})`);
44 | return this.removeButton.click();
45 | }
46 |
47 | async clearAll() {
48 | /** scroll to upload button to avoid element could not be clicked */
49 | const location = await this.clearButton.getLocation();
50 | await browser.executeScript(`scrollTo(${location.y}, ${location.x})`);
51 | return this.clearButton.click();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/docs/ui/pipes.md:
--------------------------------------------------------------------------------
1 | # Ngx Fileuplad Build in Pipes
2 |
3 | ## IsCancelAblePipe
4 |
5 | Returns true if an upload is cancelable, this is the case if
6 |
7 | - upload is pending
8 | - upload is starting
9 | - upload is in progress
10 |
11 | ```ts
12 | interface CancelAblePipe extends PipeTransform {
13 | transform(upload: FileUpload): boolean;
14 | }
15 | ```
16 |
17 | @example
18 |
19 | ```html
20 |
21 |
22 |
23 |
24 | ```
25 |
26 | ---
27 |
28 | ## FileSizePipe
29 |
30 | Formats a number into a human readable string with a max precision of 2 and cut trailing zeros. All values will return as binary bytes
31 | KibiByte, MiByte in short value is divided by 1024.
32 |
33 | for example all values in Byte:
34 |
35 | - 123.001 becomes 123 Byte
36 | - 112.10 becomes 112.1 Byte
37 | - 123.12 becomes 123.12 Byte
38 |
39 | Possible size returned:
40 |
41 | - Byte
42 | - KibiByte (Kb)
43 | - MebiByte (Mb)
44 | - GibiByte (Gb)
45 |
46 | ```ts
47 | interface FileSizePipe extends PipeTransform {
48 | /**
49 | *
50 | * @param size size in byte
51 | * @returns string formatted size max precision 2
52 | */
53 | transform(size: number): string;
54 | }
55 | ```
56 |
57 | @example
58 |
59 | ```html
60 | {{upload.uploaded | fileSize}} / {{upload.size | fileSize}}
61 | ```
62 |
63 | ---
64 |
65 | ## State to string pipe
66 |
67 | Returns given state from FileUpload and transform it into a string, by default it will return "idle"
68 |
69 | ```ts
70 | declare type State = "idle" | "pending" | "progress" | "completed" | "start" | "invalid" | "canceled";
71 |
72 | interface StateToStringPipe extends PipeTransform {
73 | transform(state: UploadState): State;
74 | }
75 | ```
76 |
77 | @example
78 |
79 | ```html
80 |
81 | ```
82 |
--------------------------------------------------------------------------------
/src/projects/core/src/tests/validation/grouped.validator.spec.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadGroupedvalidator, NgxFileUploadValidationErrors } from "@ngx-file-upload/dev/core/public-api";
2 | import { ValidatorMockFactory } from "@ngx-file-upload/testing";
3 |
4 | class ValidatorGroupMock extends NgxFileUploadGroupedvalidator {
5 |
6 | public getValidators() {
7 | return this.validators;
8 | }
9 |
10 | public validate(file: File ): NgxFileUploadValidationErrors | null {
11 | return this.execValidator(this.validators[0], file);
12 | }
13 | }
14 |
15 | describe("@ngx-file-upload/core/validation/group", () => {
16 |
17 | const uploadFile = new File(["upload testing"], "upload.txt", { type: "text/plain"});
18 | const validator1 = ValidatorMockFactory.invalid();
19 | const validator2 = ValidatorMockFactory.valid();
20 | const validator3 = ValidatorMockFactory.validValidationFn();
21 |
22 | let group: ValidatorGroupMock;
23 |
24 | beforeEach(() => {
25 | group = new ValidatorGroupMock([validator1]);
26 | });
27 |
28 | it ("it should taken 1 validator with constructor", () => {
29 | expect(group.getValidators()).toContain(validator1);
30 | });
31 |
32 | it ("it should add more validators", () => {
33 | group.add(validator2, validator3);
34 | expect(group.getValidators()).toEqual([validator1, validator2, validator3]);
35 | });
36 |
37 | it ("should clean all validators", () => {
38 | group.clean();
39 | expect(group.getValidators().length).toBe(0);
40 | });
41 |
42 | it("should validate with validation function", () => {
43 | group.clean();
44 | group.add(validator3);
45 | const result = group.validate(uploadFile);
46 | expect(result).toBe(null);
47 | });
48 |
49 | it("should validate with validation class", () => {
50 | group.clean();
51 | group.add(validator2);
52 | const result = group.validate(uploadFile);
53 | expect(result).toBe(null);
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/src/e2e/src/utils/drag-event.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * helper to simulate file drop
3 | *
4 | * @see https://stackoverflow.com/questions/37547182/simulate-drag-and-drop-of-file-to-upload-in-protractor
5 | */
6 | import { accessSync } from "fs";
7 | import { resolve } from "path";
8 | import { F_OK } from "constants";
9 | import { browser, ElementFinder } from "protractor";
10 |
11 | const JS_BIND_INPUT = (target: HTMLElement) => {
12 |
13 | const input = document.createElement("input");
14 | input.type = "file";
15 | input.multiple = true;
16 | input.style.display = "none";
17 | input.addEventListener("change", () => {
18 | target.scrollIntoView( true );
19 |
20 | const rect = target.getBoundingClientRect();
21 | const x = rect.left + rect.width;
22 | const y = rect.top + rect.height;
23 | const data = { files: input.files };
24 |
25 | ["dragenter", "dragover", "drop"].forEach((name) => {
26 | const event: any = document.createEvent("MouseEvent");
27 | event.initMouseEvent( name, !0, !0, window, 0, 0, 0, x, y, !1, !1, !1, !1, 0, null );
28 | event.dataTransfer = data;
29 | target.dispatchEvent(event);
30 | });
31 |
32 | document.body.removeChild(input);
33 | }, false );
34 |
35 | document.body.appendChild(input);
36 | return input;
37 | };
38 |
39 | /**
40 | * Support function to drop a file to a drop area.
41 | *
42 | * @view
43 | *
44 | *
45 | * @example
46 | * dropFile($("#drop-area"), "./image.png");
47 | */
48 | export async function simulateDrop(dropArea: ElementFinder, file: string[] | string) {
49 |
50 | const files = Array.isArray(file) ? file : [file];
51 | const filePath: string[] = files.map((sourceFile) => {
52 | const path = resolve(__dirname, `../data/${sourceFile}`);
53 | accessSync(path, F_OK);
54 | return path;
55 | });
56 |
57 | const element = await dropArea.getWebElement();
58 | const input: any = await browser.executeScript(JS_BIND_INPUT, element);
59 | input.sendKeys(filePath.join("\n"));
60 | }
61 |
--------------------------------------------------------------------------------
/src/projects/core/src/tests/validation/and.validator.spec.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadAndValidator } from "@ngx-file-upload/dev/core/public-api";
2 | import { ValidatorMockFactory } from "@ngx-file-upload/testing";
3 |
4 | describe("@ngx-file-upload/core/validation/and", () => {
5 |
6 | const uploadFile = new File(["upload testing"], "upload.txt", { type: "text/plain"});
7 | let validationGroup: NgxFileUploadAndValidator;
8 |
9 | beforeAll(() => {
10 | validationGroup = new NgxFileUploadAndValidator();
11 | });
12 |
13 | beforeEach(() => {
14 | validationGroup.clean();
15 | });
16 |
17 | it ("it should validate", () => {
18 | validationGroup.add(ValidatorMockFactory.valid());
19 | validationGroup.add(ValidatorMockFactory.valid());
20 | expect(validationGroup.validate(uploadFile)).toBeNull();
21 | });
22 |
23 | it ("it should not validate", () => {
24 | validationGroup.add(ValidatorMockFactory.valid());
25 | validationGroup.add(ValidatorMockFactory.invalid());
26 | expect(validationGroup.validate(uploadFile)).not.toBeNull();
27 | });
28 |
29 | it ("should contain 1 error", () => {
30 |
31 | validationGroup.add(
32 | ValidatorMockFactory.valid(),
33 | ValidatorMockFactory.invalidFileSize()
34 | );
35 |
36 | const validationResult = validationGroup.validate(uploadFile);
37 | const validationKeys = Object.keys(validationResult || {});
38 |
39 | expect(validationKeys.length).toBe(1);
40 | expect(validationKeys).toEqual(["invalidFileSize"]);
41 | });
42 |
43 | it ("should contain multiple errors", () => {
44 |
45 | validationGroup.add(
46 | ValidatorMockFactory.invalid(),
47 | ValidatorMockFactory.invalidFileSize()
48 | );
49 |
50 | const validationResult = validationGroup.validate(uploadFile);
51 | const validationKeys = Object.keys(validationResult || {});
52 |
53 | expect(validationKeys.length).toBe(2);
54 | expect(validationKeys).toEqual(["invalid", "invalidFileSize"]);
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/customize/src/item-template/item-template.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, OnDestroy, Inject } from "@angular/core";
2 | import { NgxFileUploadStorage, NgxFileUploadState, INgxFileUploadRequest } from "@ngx-file-upload/core";
3 | import { Subject } from "rxjs";
4 | import { takeUntil } from "rxjs/operators";
5 |
6 | import * as ExampleCodeData from "projects/example/libs/data/code/customize/item-template";
7 | import * as uiItemTemplateData from "projects/example/libs/data/code/customize/item-template";
8 | import * as codeUploadStorage from "projects/example/libs/data/code/common/upload-storage";
9 | import { ExampleUploadStorage } from "projects/example/libs/data/base/upload-storage";
10 |
11 | @Component({
12 | selector: "app-customize--item-template",
13 | templateUrl: "item-template.component.html",
14 | styleUrls: ["./item-template.component.scss"]
15 | })
16 | export class ItemTemplateComponent implements OnInit, OnDestroy {
17 |
18 | public code = ExampleCodeData;
19 |
20 | public codeUiItemTemplate = uiItemTemplateData;
21 |
22 | public codeUploadStorage = codeUploadStorage;
23 |
24 | public showDocs = false;
25 |
26 | public uploadStates = NgxFileUploadState;
27 |
28 | public uploads: INgxFileUploadRequest[] = [];
29 |
30 | public destroy$: Subject = new Subject();
31 |
32 | public constructor(
33 | @Inject(ExampleUploadStorage) public storage: NgxFileUploadStorage
34 | ) {
35 | }
36 |
37 | public toggleDocs() {
38 | this.showDocs = !this.showDocs;
39 | }
40 |
41 | public ngOnInit() {
42 | this.storage.change()
43 | .pipe(takeUntil(this.destroy$))
44 | .subscribe((requests) => this.uploads = requests);
45 | }
46 |
47 | public ngOnDestroy() {
48 | this.destroy$.next(true);
49 | this.destroy$.complete();
50 | }
51 |
52 | public cancelUpload(upload: INgxFileUploadRequest) {
53 | upload.cancel();
54 | }
55 |
56 | public removeUpload(upload: INgxFileUploadRequest) {
57 | this.storage.remove(upload);
58 | }
59 |
60 | public startUpload(upload: INgxFileUploadRequest) {
61 | upload.start();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/upload-item/src/upload.control.ts:
--------------------------------------------------------------------------------
1 | import { INgxFileUploadRequest, NgxFileUploadControl } from "@ngx-file-upload/core";
2 |
3 | /**
4 | * remote control for a single upload, will passed
5 | * by [NgxFileUploadItem]{@link ../components/NgxFileUploadItem.html} as context.ctrl
6 | * to the item template.
7 | *
8 | * @example
9 | *
10 | *
11 | * start
12 | * retry
13 | * cancel
14 | *
15 | *
16 | *
17 | */
18 | export class Control implements NgxFileUploadControl {
19 |
20 | public constructor(private upload: INgxFileUploadRequest) {}
21 |
22 | /**
23 | * if upload has been failed (http error) it has not completed
24 | * since connection can be broken or something dont has started yet.
25 | *
26 | * Give them a chance for a retry
27 | */
28 | public retry(event?: MouseEvent) {
29 | this.handleEvent(event);
30 | this.upload.retry();
31 | }
32 |
33 | /**
34 | * start single upload
35 | */
36 | public start($event?: MouseEvent) {
37 | this.handleEvent($event);
38 | this.upload.start();
39 | }
40 |
41 | /**
42 | * cancel / stop single upload
43 | */
44 | public stop($event?: MouseEvent) {
45 | this.handleEvent($event);
46 | this.upload.cancel();
47 | }
48 |
49 | public remove($event?: MouseEvent) {
50 | this.handleEvent($event);
51 | this.upload.destroy();
52 | }
53 |
54 | public removeInvalidFiles($event?: MouseEvent) {
55 | this.handleEvent($event);
56 | this.upload.removeInvalidFiles();
57 | }
58 |
59 | private handleEvent(event?: MouseEvent) {
60 | if (event && event instanceof MouseEvent) {
61 | event.stopPropagation();
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/projects/core/src/tests/utils/factory.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, inject } from "@angular/core/testing";
2 | import { HttpClientTestingModule } from "@angular/common/http/testing";
3 | import { ValidatorMockFactory } from "@ngx-file-upload/testing";
4 | import { NgxFileUploadFactory } from "../../lib/upload";
5 |
6 | describe("NgxFileUpload/libs/utils/factory", () => {
7 |
8 | beforeEach(() => {
9 | TestBed.configureTestingModule({
10 | imports: [HttpClientTestingModule],
11 | });
12 | });
13 |
14 | it("should create single NgxFileUploadRequest", inject([NgxFileUploadFactory], (factory: NgxFileUploadFactory) => {
15 | const file = new File(["ngx file upload"], "file1.txt");
16 | const upload = factory.createUploadRequest(file, {url: "/dev/null"});
17 |
18 | expect(upload?.data.files[0].raw).toEqual(file);
19 | }));
20 |
21 | it("should validate file if validation function is passed", inject([NgxFileUploadFactory], (factory: NgxFileUploadFactory) => {
22 | const file1 = new File(["ngx file upload"], "file1.txt");
23 | const upload = factory.createUploadRequest(file1, {url: "/dev/null"}, ValidatorMockFactory.invalidFileSize());
24 | expect(upload?.isInvalid()).toBeTruthy();
25 | }));
26 |
27 | it("should create no requests if no files are passed", inject([NgxFileUploadFactory], (factory: NgxFileUploadFactory) => {
28 | const requests = factory.createUploadRequest([], {url: "/dev/null"}, ValidatorMockFactory.invalidValidationFn);
29 | expect(requests).toBeNull();
30 | }));
31 |
32 | it("should create one requets which holds all files", inject([NgxFileUploadFactory], (factory: NgxFileUploadFactory) => {
33 | const file1 = new File(["ngx file upload"], "file1.txt");
34 | const file2 = new File(["ngx file upload"], "file2.txt");
35 | const file3 = new File(["ngx file upload"], "file3.txt");
36 |
37 | const requests = factory.createUploadRequest([file1, file2, file3], {url: "/dev/null"}, ValidatorMockFactory.invalidValidationFn);
38 | expect(requests?.data.files.length).toBe(3);
39 | expect(requests?.data.name).toEqual(['file1.txt', 'file2.txt', 'file3.txt']);
40 | }));
41 | });
42 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/progressbar/src/ui/progressbar-circle.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
21 |
22 |
23 |
30 |
31 |
32 | 0 ? 'animate' : ''"
33 | shape-rendering="geometricPrecision"
34 | cx="50%"
35 | cy="50%"
36 | [attr.r]="data.radius"
37 | [attr.stroke-dasharray]="data.circumferences"
38 | [attr.stroke-dashoffset]="data.offset"
39 | stroke="white"
40 | fill="black">
41 |
42 |
43 |
44 | 0 ? 'animate' : ''"
45 | shape-rendering="geometricPrecision"
46 | cx="50%"
47 | cy="50%"
48 | [attr.r]="data.radius"
49 | [attr.stroke-dasharray]="data.circumferences"
50 | [attr.stroke-dashoffset]="data.offset - data.circumferences"
51 | fill="black">
52 |
53 |
54 |
55 |
56 |
57 | {{data.progress}} %
58 |
--------------------------------------------------------------------------------
/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "angularCompilerOptions": {
4 | "strictTemplates": false
5 | },
6 | "compilerOptions": {
7 | "baseUrl": "./",
8 | "outDir": "./dist/out-tsc",
9 | "sourceMap": true,
10 | "declaration": false,
11 | "module": "es2020",
12 | "moduleResolution": "node",
13 | "experimentalDecorators": true,
14 | "importHelpers": true,
15 | "target": "ES2022",
16 | "noUnusedParameters": true,
17 | "noUnusedLocals": true,
18 | "strict": true,
19 | "typeRoots": [
20 | "node_modules/@types"
21 | ],
22 | "lib": [
23 | "es2018",
24 | "dom"
25 | ],
26 | "paths": {
27 | "@ngx-file-upload/dev/core/*": [
28 | "projects/core/src/*"
29 | ],
30 | "@ngx-file-upload/core": [
31 | "dist/core"
32 | ],
33 | "@ngx-file-upload/ui": [
34 | "dist/ui"
35 | ],
36 | "@ngx-file-upload/dev/ui/*": [
37 | "projects/ui/src/*"
38 | ],
39 | "@ngx-file-upload/testing": [
40 | "projects/testing/mockup"
41 | ],
42 | "@r-hannuschka/ngx-fileupload": [
43 | "lib/public-api"
44 | ],
45 | "@ngx-fileupload-example/utils/api/upload": [
46 | "projects/example/utils/validators"
47 | ],
48 | "@ngx-fileupload-example/utils/validators": [
49 | "projects/example/libs/utils/validators"
50 | ],
51 | "@ngx-fileupload-example/page/*": [
52 | "projects/example/libs/pages/*"
53 | ],
54 | "@ngx-fileupload-example/ui": [
55 | "projects/example/libs/ui"
56 | ],
57 | "@ngx-fileupload-example/data/*": [
58 | "projects/example/libs/data/*"
59 | ],
60 | "@ngx-fileupload-example/utils/*": [
61 | "projects/example/libs/utils/*"
62 | ],
63 | "@lib/utils/*": [
64 | "lib/ngx-fileupload/libs/utils/*"
65 | ],
66 | "@lib/utils/validation": [
67 | "lib/ngx-fileupload/libs/validation"
68 | ],
69 | "@lib/data/*": [
70 | "./lib/ngx-fileupload/data/*"
71 | ],
72 | "@lib/ui": [
73 | "lib/ngx-fileupload/libs/ui"
74 | ],
75 | "@lib/data/api": [
76 | "lib/ngx-fileupload/libs/api"
77 | ]
78 | },
79 | "useDefineForClassFields": false
80 | }
81 | }
--------------------------------------------------------------------------------
/src/projects/example/assets/scss/_icons.scss:
--------------------------------------------------------------------------------
1 | @import "variables";
2 |
3 | @font-face {
4 | font-family: '#{$icomoon-font-family}';
5 | src: url('#{$icomoon-font-path}/#{$icomoon-font-family}.eot?tks8fx');
6 | src: url('#{$icomoon-font-path}/#{$icomoon-font-family}.eot?tks8fx#iefix') format('embedded-opentype'),
7 | url('#{$icomoon-font-path}/#{$icomoon-font-family}.ttf?tks8fx') format('truetype'),
8 | url('#{$icomoon-font-path}/#{$icomoon-font-family}.woff?tks8fx') format('woff'),
9 | url('#{$icomoon-font-path}/#{$icomoon-font-family}.svg?tks8fx##{$icomoon-font-family}') format('svg');
10 |
11 | font-weight: normal;
12 | font-style: normal;
13 | font-display: block;
14 | }
15 |
16 | @mixin icon {
17 | /* use !important to prevent issues with browser extensions that change fonts */
18 | font-family: '#{$icomoon-font-family}' !important;
19 | speak: none;
20 | font-style: normal;
21 | font-weight: normal;
22 | font-variant: normal;
23 | text-transform: none;
24 | line-height: 1;
25 |
26 | /* Better Font Rendering =========== */
27 | -webkit-font-smoothing: antialiased;
28 | -moz-osx-font-smoothing: grayscale;
29 | }
30 |
31 | [class^="icon-"], [class*=" icon-"] {
32 | @include icon;
33 | }
34 |
35 | .icon-connect {
36 | &:before {
37 | content: $icon-connect;
38 | }
39 | }
40 | .icon-upload {
41 | &:before {
42 | content: $icon-upload;
43 | }
44 | }
45 | .icon-pending {
46 | &:before {
47 | content: $icon-pending;
48 | }
49 | }
50 | .icon-reload {
51 | &:before {
52 | content: $icon-reload;
53 | }
54 | }
55 | .icon-warning {
56 | &:before {
57 | content: $icon-warning;
58 | }
59 | }
60 | .icon-cancel {
61 | &:before {
62 | content: $icon-cancel;
63 | }
64 | }
65 | .icon-canceled {
66 | &:before {
67 | content: $icon-canceled;
68 | }
69 | }
70 | .icon-success {
71 | &:before {
72 | content: $icon-success;
73 | }
74 | }
75 | .icon-progress {
76 | &:before {
77 | content: $icon-progress;
78 | }
79 | }
80 | .icon-toggle-open {
81 | &:before {
82 | content: $icon-toggle-open;
83 | }
84 | }
85 | .icon-toggle-close {
86 | &:before {
87 | content: $icon-toggle-close;
88 | }
89 | }
90 | .icon-github {
91 | &:before {
92 | content: $icon-github;
93 | }
94 | }
95 | .icon-npm {
96 | &:before {
97 | content: $icon-npm;
98 | }
99 | }
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/drop-zone/src/ui/drop-zone.ts:
--------------------------------------------------------------------------------
1 | import { Component, Inject, OnInit, OnDestroy } from "@angular/core";
2 | import { NgxFileUploadStorage, NgxFileUploadFactory, NgxFileUploadOptions, NgxFileUploadState, INgxFileUploadRequest } from "@ngx-file-upload/core";
3 | import { NgxFileDropEntry, FileSystemFileEntry } from "ngx-file-drop";
4 | import { takeUntil } from "rxjs/operators";
5 | import { Subject } from "rxjs";
6 |
7 | import * as ExampleCodeData from "projects/example/libs/data/code/ngx-drop-zone/drop-zone";
8 |
9 | @Component({
10 | selector: "app-drop-zone",
11 | templateUrl: "drop-zone.html",
12 | styleUrls: ["./drop-zone.scss"]
13 | })
14 | export class DropZoneComponent implements OnDestroy, OnInit {
15 |
16 | public uploads: INgxFileUploadRequest[] = [];
17 |
18 | public uploadStorage: NgxFileUploadStorage;
19 |
20 | public code = ExampleCodeData;
21 |
22 | public states = NgxFileUploadState;
23 |
24 | /** upload options */
25 | private uploadOptions: NgxFileUploadOptions = {
26 | url: "http://localhost:3000/upload/gallery",
27 | formData: {
28 | enabled: true,
29 | name: "picture",
30 | additionalData: {
31 | 'token': 'foobar'
32 | }
33 | },
34 | };
35 |
36 | private destroy$: Subject = new Subject();
37 |
38 | constructor(
39 | @Inject(NgxFileUploadFactory) private uploadFactory: NgxFileUploadFactory
40 | ) {
41 | this.uploadStorage = new NgxFileUploadStorage({
42 | concurrentUploads: 1
43 | });
44 | }
45 |
46 | /**
47 | * files get dropped
48 | */
49 | public drop(files: NgxFileDropEntry[]) {
50 | const sources: File[] = []
51 |
52 | files.forEach((file) => {
53 | if (file.fileEntry.isFile) {
54 | const dropped = file.fileEntry as FileSystemFileEntry;
55 | dropped.file((droppedFile: File) => {
56 | if (droppedFile instanceof DataTransferItem) {
57 | return;
58 | }
59 | sources.push(droppedFile);
60 | });
61 | }
62 | });
63 |
64 | const request = this.uploadFactory.createUploadRequest(sources, this.uploadOptions);
65 | if (request) {
66 | this.uploadStorage.add(request);
67 | }
68 | }
69 |
70 | public ngOnInit() {
71 | this.uploadStorage.change()
72 | .pipe(takeUntil(this.destroy$))
73 | .subscribe((uploads) => this.uploads = uploads);
74 | }
75 |
76 | public ngOnDestroy() {
77 | this.destroy$.next(true);
78 | this.destroy$.complete();
79 |
80 | this.uploadStorage.destroy();
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/projects/example/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from "@angular/platform-browser";
2 | import { NgModule, Provider } from "@angular/core";
3 | import { RouterModule } from "@angular/router";
4 | import { environment } from "../environments/environment";
5 |
6 | import { IgxIconModule } from "igniteui-angular";
7 | import { HighlightModule, HIGHLIGHT_OPTIONS } from "ngx-highlightjs";
8 |
9 | import { HTTP_INTERCEPTORS } from "@angular/common/http";
10 | import { FakeUploadInterceptor } from "projects/example/libs/utils/http";
11 |
12 | import { AppComponent } from "./app.component";
13 | import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
14 | import { NgxFileUploadCoreModule } from "@ngx-file-upload/core";
15 |
16 | import { UiModule } from "projects/example/libs/ui";
17 | import { CustomizePage } from "projects/example/libs/pages/customize";
18 | import { Dashboard } from "projects/example/libs/pages/dashboard";
19 | import { ValidationPage } from "projects/example/libs/pages/validation";
20 | import { DropZone } from "projects/example/libs/pages/drop-zone";
21 | import { AutoUploadDemo } from "projects/example/libs/pages/auto-upload";
22 |
23 | const fakeUploadProvider: Provider = {
24 | provide: HTTP_INTERCEPTORS,
25 | useClass: FakeUploadInterceptor,
26 | multi: true
27 | };
28 |
29 | export function getHighlightLanguages() {
30 | return {
31 | typescript: () => import("highlight.js/lib/languages/typescript"),
32 | scss: () => import("highlight.js/lib/languages/scss"),
33 | xml: () => import("highlight.js/lib/languages/xml")
34 | };
35 | }
36 |
37 | @NgModule({
38 | declarations: [
39 | AppComponent
40 | ],
41 | imports: [
42 | BrowserModule,
43 | BrowserAnimationsModule,
44 | RouterModule.forRoot([], { useHash: true }),
45 | IgxIconModule,
46 | HighlightModule,
47 | // app module
48 | NgxFileUploadCoreModule,
49 | UiModule,
50 |
51 | // pages
52 | AutoUploadDemo,
53 | CustomizePage,
54 | Dashboard,
55 | ValidationPage,
56 | DropZone,
57 | ],
58 | bootstrap: [AppComponent],
59 | providers: [
60 | ...environment.demo ? [fakeUploadProvider] : [],
61 | {
62 | provide: HIGHLIGHT_OPTIONS,
63 | useValue: {
64 | coreLibraryLoader: () => import("highlight.js/lib/core"),
65 | languages: getHighlightLanguages()
66 | }
67 | }
68 | ]
69 | })
70 | export class AppModule {
71 | }
72 |
--------------------------------------------------------------------------------
/src/projects/testing/mockup/src/validator.factory.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadValidator, NgxFileUploadValidationErrors, NgxFileUploadValidationFn } from "@ngx-file-upload/core";
2 |
3 | class InvalidValidation implements NgxFileUploadValidator {
4 | validate(): NgxFileUploadValidationErrors | null {
5 | return {
6 | invalid: "this is an invalid file"
7 | };
8 | }
9 | }
10 |
11 | class ValidValidation implements NgxFileUploadValidator {
12 | validate(): NgxFileUploadValidationErrors | null {
13 | return null;
14 | }
15 | }
16 |
17 | class DynamicNameValidation implements NgxFileUploadValidator {
18 |
19 | public constructor(private name: string) {}
20 |
21 | validate(file: File): NgxFileUploadValidationErrors | null {
22 | if (file.name !== this.name) {
23 | return {
24 | dynamicNameValidation: `invalid name: ${file.name}`
25 | };
26 | }
27 | return null;
28 | }
29 | }
30 |
31 | class InvalidFileValidator implements NgxFileUploadValidator {
32 |
33 | validate(): NgxFileUploadValidationErrors | null {
34 | return {
35 | invalidFile: "invalid file"
36 | };
37 | }
38 | }
39 |
40 | class InvalidFileSizeValidator implements NgxFileUploadValidator {
41 |
42 | validate(): NgxFileUploadValidationErrors | null {
43 | return {
44 | invalidFileSize: "file should be at least 1 Petabyte! Bigger is better!"
45 | };
46 | }
47 | }
48 |
49 | export class ValidatorMockFactory {
50 |
51 | public static invalid(): NgxFileUploadValidator {
52 | return new InvalidValidation();
53 | }
54 |
55 | public static valid(): NgxFileUploadValidator {
56 | return new ValidValidation();
57 | }
58 |
59 | public static byName(name: string): NgxFileUploadValidator {
60 | return new DynamicNameValidation(name);
61 | }
62 |
63 | public static invalidFile(): NgxFileUploadValidator {
64 | return new InvalidFileValidator();
65 | }
66 |
67 | public static invalidFileSize(): NgxFileUploadValidator {
68 | return new InvalidFileSizeValidator();
69 | }
70 |
71 | public static validValidationFn(): NgxFileUploadValidationFn {
72 | return () => {
73 | return null;
74 | };
75 | }
76 |
77 | public static invalidValidationFn(): NgxFileUploadValidationFn {
78 | return () => {
79 | return {
80 | invalidValidationFn: "invalid validation function called"
81 | };
82 | };
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/code/utils/validators.ts:
--------------------------------------------------------------------------------
1 | export const IMAGE_VALIDATOR = `
2 | import { NgxFileUploadValidationErrors } from "@ngx-file-upload/core";
3 |
4 | /**
5 | * defines a validation function which should return
6 | * NgxFileUploadValidationErrors if invalid or Null if valid
7 | */
8 | export function isImage(file: File): NgxFileUploadValidationErrors {
9 |
10 | /**
11 | * very easy check, would be better to check for mime type
12 | */
13 | const valid = /\.(jpg|jpeg|gif|png)$/i.test(file.name);
14 |
15 | return !valid
16 | ? { isImage: "not a valid image file" }
17 | : null;
18 | }`;
19 |
20 | export const MAX_SIZE_VALIDATOR = `
21 | import { NgxFileUploadValidator, NgxFileUploadValidationErrors } from "@ngx-file-upload/core";
22 |
23 | export class MaxUploadSizeValidator implements NgxFileUploadValidator {
24 |
25 | private units = ["Byte", "kb", "mb", "gb"];
26 |
27 | /**
28 | * default maxupload size 1Mb as byte
29 | */
30 | private maxSize: number;
31 |
32 | /**
33 | * constructor pass max upload size in byte
34 | */
35 | public constructor(size: number) {
36 | this.maxSize = size || 1024 * 1024;
37 | }
38 |
39 | public validate(file: File): NgxFileUploadValidationErrors | null {
40 | const valid = (file.size / this.maxSize) < 1;
41 |
42 | if (file.size / this.maxSize > 1) {
43 | return {
44 | maxFileSizeValidator: 'max file size ' + this.toUnits(this.maxSize)
45 | };
46 | }
47 | return null;
48 | }
49 |
50 | private toUnits(size: number): string {
51 | let unitIndex = 0;
52 | let totalSize = size;
53 |
54 | while (totalSize > 1024 && unitIndex < this.units.length) {
55 | totalSize = totalSize / 1024;
56 | unitIndex++;
57 | }
58 |
59 | return totalSize.toFixed(2).concat(this.units[unitIndex]);
60 | }
61 | }`;
62 |
63 | export const IS_ZIP_VALIDATOR = `
64 | import { NgxFileUploadValidationErrors } from "@ngx-file-upload/core";
65 |
66 | export function isZipFile(file: File): NgxFileUploadValidationErrors | null {
67 |
68 | const validMime = [
69 | "application/zip",
70 | "application/octet-stream",
71 | "application/x-zip-compressed",
72 | "multipart/x-zip"
73 | ];
74 |
75 | let valid = validMime.some((type) => type === file.type);
76 | valid = valid && /\.zip$/.test(file.name);
77 |
78 | return !valid
79 | ? { zipValidator: "not a valid zip file" }
80 | : null;
81 | }`;
82 |
--------------------------------------------------------------------------------
/src/projects/example/libs/pages/drop-zone/src/ui/drop-zone.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ngx-file-drop deprecated
6 |
7 |
8 |
9 |
10 | {{upload.data.name}}
11 | {{upload.data.uploaded | fileSize}} | {{upload.data.size | fileSize}} | {{upload.data.progress}}%
12 | {{upload.data.state | stateToString}}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | For this example we use ngx-file-drop
24 | library for drag and drop which can also handles drag n drop directories. There are other good librarys out
25 | for drag and drop we decide to use this one for following reasons:
26 |
27 |
28 | Well maintained
29 | no third party libraries involved
30 | Well tested by community
31 |
32 | Since we dont use ngx-fileupload browser, we have to take care when files have been dropped, create a new
33 | NgxFileUploadRequest with NgxFileUploadFactory and put every NgxFileUploadRequest into storage.
34 |
35 |
36 |
37 |
38 |
39 | Demo
40 |
41 |
42 |
43 |
44 |
45 |
46 | Typescript
47 |
48 |
49 |
50 |
51 |
52 |
53 | Html
54 |
55 |
56 |
57 |
58 |
59 |
60 | Scss
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/docs/ui/upload-directive.md:
--------------------------------------------------------------------------------
1 | # Upload Directive
2 |
3 | Simple file drop zone and file browser, listen to add event to get files which was selected for upload.
4 |
5 | @example
6 |
7 | ```ts
8 | import { Component, OnInit, OnDestroy, Inject } from "@angular/core";
9 | import { NgxFileUploadFactory, UploadRequest, UploadStorage, UploadOptions } from "@r-hannuschka/ngx-fileupload";
10 |
11 | @Compononent({
12 | template: `
13 | <-- bind file browser directive to any element -->
14 |
15 | drag drop files here or click
16 |
17 |
18 |
20 |
21 | `,
22 | selector: 'app-upload-component'
23 | })
24 | class UploadComponent implements OnInit {
25 |
26 | public uploads: UploadRequest[];
27 |
28 | public storage: UploadStorage;
29 |
30 | private destroyed: Subject = new Subject();
31 |
32 | public constructor(
33 | @Inject(NgxFileUploadFactory) private uploadFactory: NgxFileUploadFactory
34 | ) {
35 | this.storage = new UploadStorage();
36 | }
37 |
38 | public ngOnInit() {
39 | this.storage.change
40 | .pipe(takeUntil(this.destroyed))
41 | .subscribe((uploads: UploadRequest[]) => this.uploads = uploads);
42 | }
43 |
44 | public ngOnDestroy() {
45 | this.destroyed.next(true);
46 | this.storage.destroy();
47 | }
48 |
49 | /**
50 | * handle add event from file browser directive
51 | *
52 | * create new request with upload factory and attach,
53 | * them to upload storage
54 | */
55 | public onFilesDrop(files: File[]) {
56 |
57 | /** configure upload options */
58 | const uploadOptions: UploadOptions = {
59 | url: 'http://localhost:3000/upload/gallery',
60 | formData: {
61 | enabled: true,
62 | name: 'picture'
63 | }
64 | }
65 |
66 | const uploads = this.uploadFactory.createUploadRequest(files, uploadOptions /*, validators */);
67 | this.uploadStorage.add(uploads);
68 | }
69 | }
70 | ```
71 |
72 | ## @Input
73 |
74 | | name | type | description | mandatory |
75 | |---|---|---|---|
76 | | ngxFileUpload | void | adds file browser to any element | true |
77 |
78 | ## @Output
79 |
80 | | name | type | description |
81 | |---|---|---|
82 | | add | File[] | files which was added for upload |
83 |
84 | ## Further reading
85 |
86 | - [Upload Factory](./factory.md)
87 | - [Upload Storage](./upload.storgage.md)
88 |
--------------------------------------------------------------------------------
/docs/ui/i18n.md:
--------------------------------------------------------------------------------
1 | # Ngx Fileupload I18N
2 |
3 |
4 | To add a specific language to @ngx-file-upload/ui components create a new language file where you define custom translations which will only
5 | work for predefined components we provide with @ngx-file-upload/ui.
6 |
7 | If you need full angular i18n support like [@ngx-translate](https://www.npmjs.com/org/ngx-translate) or i18n provided by @angular/cli you have to
8 | create your own components.
9 |
10 | ## Included Translations by module
11 |
12 | ### Common Upload View (NgxFileUploadUiCommonModule)
13 |
14 | ```ts
15 | export interface NgxFileUploadUiI18nCommon extends Labels {
16 | SELECT_FILES: string;
17 | }
18 | ```
19 |
20 | ### Upload Toolbar (NgxFileUploadUiToolbarModule)
21 |
22 | NgxFileUploadUiToolbarModule
23 |
24 | ```ts
25 | export interface NgxFileUploadUiI18nToolbar extends Labels {
26 | /** remove invalid or completed files */
27 | CLEAN_UP: string;
28 | /** remove all (even pending, queued and currently running) */
29 | REMOVE_ALL: string;
30 | /** start all uploads */
31 | UPLOAD_ALL: string;
32 | /** label for quick view upload state (completed, running, pendning and so on) */
33 | UPLOADS: string;
34 | }
35 | ```
36 |
37 | ### Upload Item (NgxFileUploadUiItemModule)
38 |
39 | ```ts
40 | export interface NgxFileUploadUiI18nItem extends Labels {
41 | UPLOADED: string;
42 | }
43 | ```
44 |
45 | ### Injection Token (NgxFileUploadUiI18n)
46 |
47 | ```ts
48 | export interface NgxFileUploadUiI18n {
49 | common?: NgxFileUploadUiI18nCommon;
50 | item?: NgxFileUploadUiI18nItem;
51 | toolbar?: NgxFileUploadUiI18nToolbar;
52 | }
53 | ```
54 |
55 | ### Usage
56 |
57 | Simply provide **NGX_FILE_UPLOAD_UI_I18N** as provider and pass as value your translations / labels
58 |
59 | @example
60 |
61 | ```ts
62 | import { NGX_FILE_UPLOAD_UI_I18N, NgxFileUploadUiI18n } from "@ngx-file-upload/ui";
63 |
64 | /**
65 | * define translation json data all sections are optional
66 | * if not set it will take default value
67 | */
68 | const ngxFileUploadI18n: NgxFileUploadUiI18n = {
69 | common: {
70 | SELECT_FILES: "Select File"
71 | },
72 | item: {
73 | UPLOADED: "uploaded"
74 | },
75 | toolbar: {
76 | CLEAN_UP: "Remove invalid and completed",
77 | REMOVE_ALL: "Remove all",
78 | UPLOADS: "Progessing File Uploads",
79 | UPLOAD_ALL: "Upload All"
80 | }
81 | };
82 |
83 | @NgModule({
84 | ...
85 | providers: [
86 | ...
87 | /**
88 | * @optional bind language data to injection token
89 | * if not provided it will use default text labels
90 | */
91 | { provide: NGX_FILE_UPLOAD_UI_I18N, useValue: ngxFileUploadI18n },
92 | ...
93 | })
94 | export class AppModule {
95 | }
96 | ```
97 |
--------------------------------------------------------------------------------
/src/server/upload-server.js:
--------------------------------------------------------------------------------
1 | // call all the required packages
2 | const express = require("express");
3 | const app = express();
4 | const resolve = require("path").resolve;
5 | const dirname = require("path").dirname;
6 | const cors = require('cors');
7 | const letsLog = require("letslog");
8 | const fileUpload = require("express-fileupload");
9 |
10 | const logger = new letsLog.Logger({
11 | baseComment: "",
12 | loglvl: letsLog.ELoglevel.DEBUG,
13 | transports: [
14 | {
15 | baseComment: "",
16 | loglvl: letsLog.ELoglevel.DEBUG,
17 | logpath: resolve(dirname(__filename)),
18 | logFileName: "upload",
19 | type: letsLog.ETransportType.filesystem,
20 | showBaseComment: false,
21 | showDate: false,
22 | showLoglevel: false
23 | }
24 | ]
25 | });
26 |
27 | let response = null;
28 | let timeout = 0;
29 |
30 | function sendResponse(res, file, msg = null) {
31 | const defaultResponse = {
32 | file: {
33 | id: 0,
34 | type: "any"
35 | },
36 | message: msg || `Hoooray File: ${file.name} uploaded to /dev/null`
37 | };
38 |
39 | res.status(response ? response.state : 200);
40 | res.send(response ? response.body : defaultResponse);
41 | }
42 |
43 | app.use(function(req, res, next) {
44 | res.header("Access-Control-Allow-Origin", "*");
45 | res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
46 | next();
47 | });
48 | app.use(cors());
49 | app.use(fileUpload());
50 |
51 | app.post("/upload", function(req, res) {
52 | const uploadedFile = req.files.file;
53 | logger.info(`File uploaded: ${uploadedFile.name}`);
54 |
55 | if(timeout) {
56 | setTimeout(() => sendResponse(res, uploadedFile), timeout);
57 | } else {
58 | sendResponse(res, uploadedFile);
59 | }
60 | });
61 |
62 | app.post("/upload/gallery", function(req, res) {
63 |
64 | const uploadedFile = req.files.picture;
65 | const metadata = JSON.stringify(req.body);
66 |
67 | console.dir(req.files);
68 | console.dir(req.body);
69 |
70 | logger.debug(`Picture uploaded: ${uploadedFile.name}`);
71 | logger.debug(`Metadata send: ${metadata}`)
72 |
73 | const message = `New picture added to our gallery ${uploadedFile.name}`;
74 | if(timeout) {
75 | setTimeout(() => sendResponse(res, uploadedFile, message), timeout);
76 | } else {
77 | sendResponse(res, uploadedFile, message);
78 | }
79 | });
80 |
81 | app.listen(3000, () => process.stdout.write("Server started on port 3000\n"));
82 |
83 | /**
84 | * register process messages through ipc
85 | */
86 | process.on("message", (data) => {
87 | response = data.response;
88 | timeout = data.timeout || 0;
89 | });
90 |
--------------------------------------------------------------------------------
/src/projects/testing/mockup/src/upload-request.mock.ts:
--------------------------------------------------------------------------------
1 | import { Observable, Subject } from "rxjs";
2 | import { INgxFileUploadRequest, INgxFileUploadRequestModel, NgxFileUploadState } from "@ngx-file-upload/core";
3 | import { take } from "rxjs/operators";
4 | import { INgxFileUploadRequestData } from "@ngx-file-upload/dev/core/public-api";
5 |
6 | /**
7 | * represents a single fileupload
8 | */
9 | export class UploadRequestMock implements INgxFileUploadRequest {
10 |
11 | destroy$: Subject;
12 |
13 | destroyed: Observable;
14 |
15 | public hooks: Observable[] = [];
16 |
17 | requestId: string = "";
18 |
19 | data: INgxFileUploadRequestData;
20 |
21 | change$: Subject;
22 |
23 | public constructor(model: INgxFileUploadRequestModel) {
24 | this.data = model;
25 | this.change$ = new Subject();
26 | this.destroy$ = new Subject();
27 | this.destroyed = this.destroy$.asObservable();
28 | }
29 |
30 | removeInvalidFiles(): void {
31 | throw new Error("Method not implemented.");
32 | }
33 |
34 | set state(state: NgxFileUploadState) {
35 | this.data.state = state;
36 | }
37 |
38 | get state(): NgxFileUploadState {
39 | return this.data.state;
40 | }
41 |
42 | isCanceled(): boolean {
43 | return this.data.state === NgxFileUploadState.CANCELED;
44 | }
45 |
46 | retry(): void {
47 | }
48 |
49 | beforeStart(hook: Observable): void {
50 | this.hooks.push(hook);
51 | }
52 |
53 | destroy(): void {
54 | this.destroy$.next(true);
55 | this.destroy$.complete();
56 | this.change$.complete();
57 | }
58 |
59 | isCompleted(): boolean {
60 | return this.data.state === NgxFileUploadState.COMPLETED;
61 | }
62 |
63 | isIdle(): boolean {
64 | return this.data.state === NgxFileUploadState.IDLE;
65 | }
66 |
67 | start(): void {
68 | this.hooks.forEach((hook) => hook.pipe(take(1)).subscribe((start) => {
69 | if (start) {
70 | this.data.state = NgxFileUploadState.START;
71 | this.applyChange();
72 | }
73 | }));
74 | }
75 |
76 | cancel(): void {
77 | }
78 |
79 | hasError(): boolean {
80 | return false;
81 | }
82 |
83 | isInvalid(): boolean {
84 | return this.data.state === NgxFileUploadState.INVALID;
85 | }
86 |
87 | isPending(): boolean {
88 | return this.data.state === NgxFileUploadState.PENDING;
89 | }
90 |
91 | isProgress(): boolean {
92 | return this.data.state === NgxFileUploadState.PROGRESS || this.data.state === NgxFileUploadState.START;
93 | }
94 |
95 | public get change(): Observable {
96 | return this.change$.asObservable();
97 | }
98 |
99 | public applyChange() {
100 | this.change$.next(this.data)
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/projects/example/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
22 | // import "classlist.js"; // Run `npm install --save classlist.js`.
23 |
24 | /**
25 | * Web Animations `@angular/platform-browser/animations`
26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28 | */
29 | // import "web-animations-js"; // Run `npm install --save web-animations-js`.
30 |
31 | /**
32 | * By default, zone.js will patch all possible macroTask and DomEvents
33 | * user can disable parts of macroTask/DomEvents patch by setting following flags
34 | * because those flags need to be set before `zone.js` being loaded, and webpack
35 | * will put import in the top of bundle, so user need to create a separate file
36 | * in this directory (for example: zone-flags.ts), and put the following flags
37 | * into that file, and then add the following code before importing zone.js.
38 | * import "./zone-flags.ts";
39 | *
40 | * The flags allowed in zone-flags.ts are listed here.
41 | *
42 | * The following flags will work for all browsers.
43 | *
44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ["scroll", "mousemove"]; // disable patch specified eventNames
47 | *
48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
50 | *
51 | * (window as any).__Zone_enable_cross_context_check = true;
52 | *
53 | */
54 |
55 | /***************************************************************************************************
56 | * Zone JS is required by default for Angular itself.
57 | */
58 | import "zone.js"; // Included with Angular CLI.
59 |
60 |
61 | /***************************************************************************************************
62 | * APPLICATION IMPORTS
63 | */
64 |
--------------------------------------------------------------------------------
/src/projects/example/libs/data/base/icons.ts:
--------------------------------------------------------------------------------
1 | export const html5Icon = `
2 | HTML5 Logo
3 |
4 |
5 |
6 |
7 |
8 | `;
9 |
10 | export const tsLogo = `
11 |
34 |
36 |
48 |
49 | `;
50 |
--------------------------------------------------------------------------------
/src/projects/core/src/tests/upload/upload.headers.spec.ts:
--------------------------------------------------------------------------------
1 |
2 | import { TestBed, getTestBed } from "@angular/core/testing";
3 | import { HttpClientTestingModule, HttpTestingController, TestRequest } from "@angular/common/http/testing";
4 | import { HttpClient } from "@angular/common/http";
5 | import { Type } from "@angular/core";
6 | import { NgxFileUploadFile, NgxFileUploadRequest } from "../../lib/upload";
7 |
8 | describe("NgxFileUpload/libs/upload", () => {
9 |
10 | const url = "https://localhost/file/upload";
11 | let httpClient: HttpClient;
12 | let injector: TestBed;
13 | let httpMock: HttpTestingController;
14 |
15 | beforeEach(() => {
16 | TestBed.configureTestingModule({
17 | imports: [HttpClientTestingModule]
18 | });
19 |
20 | injector = getTestBed();
21 | httpMock = injector.inject(HttpTestingController as Type);
22 | httpClient = injector.inject(HttpClient as Type);
23 | });
24 |
25 | function createNgxFileUploadFile(): NgxFileUploadFile {
26 | const raw = new File(['mocked file'], 'mockedfile.txt')
27 | return new NgxFileUploadFile(raw)
28 | }
29 |
30 | it("should append authorization header if value is passed as string", () => {
31 |
32 | const upload = new NgxFileUploadRequest(httpClient, createNgxFileUploadFile(), {
33 | url,
34 | headers: {
35 | authorization: "01234567890abcdef"
36 | }
37 | });
38 | upload.start();
39 |
40 | const testRequest: TestRequest = httpMock.expectOne(url);
41 | expect(testRequest.request.headers.has("Authorization")).toBeTruthy();
42 | expect(testRequest.request.headers.get("Authorization")).toEqual(`Bearer 01234567890abcdef`);
43 | });
44 |
45 | it("should send custom authorization header", () => {
46 | const upload = new NgxFileUploadRequest(httpClient, createNgxFileUploadFile(), {
47 | url,
48 | headers: {
49 | authorization: {
50 | key: "CustomAuthorizationKey",
51 | token: "my-token"
52 | }
53 | }
54 | });
55 | upload.start();
56 |
57 | const testRequest: TestRequest = httpMock.expectOne(url);
58 | expect(testRequest.request.headers.has("Authorization")).toBeTruthy();
59 | expect(testRequest.request.headers.get("Authorization")).toEqual(`CustomAuthorizationKey my-token`);
60 | });
61 |
62 | it("should append header", () => {
63 | const upload = new NgxFileUploadRequest(httpClient, createNgxFileUploadFile(), {
64 | url,
65 | headers: {
66 | "X-RefKey": "01234567890abcdef"
67 | }
68 | });
69 | upload.start();
70 |
71 | const testRequest: TestRequest = httpMock.expectOne(url);
72 | expect(testRequest.request.headers.has("X-RefKey")).toBeTruthy();
73 | expect(testRequest.request.headers.get("X-RefKey")).toEqual(`01234567890abcdef`);
74 | });
75 |
76 | afterEach(() => {
77 | httpMock.verify();
78 | });
79 | });
80 |
--------------------------------------------------------------------------------
/src/projects/ui/src/tests/ui/upload-view.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed, inject, waitForAsync } from "@angular/core/testing";
2 | import { HttpClientTestingModule } from "@angular/common/http/testing";
3 | import { CommonModule } from "@angular/common";
4 | import { NoopAnimationsModule } from "@angular/platform-browser/animations";
5 |
6 | import { NgxFileUploadStorage, NgxFileUploadFactory } from "@ngx-file-upload/core";
7 | import { UploadViewComponent, NgxFileUploadUiModule } from "@ngx-file-upload/dev/ui/public-api";
8 | import { NgxFileuploadFactoryMock, UploadStorageMock } from "@ngx-file-upload/testing";
9 |
10 | describe( "Upload Component:", () => {
11 |
12 | let fixture: ComponentFixture;
13 | let testComponent: UploadViewComponent;
14 |
15 | beforeEach(waitForAsync(() => {
16 | TestBed.configureTestingModule( {
17 | imports: [
18 | CommonModule,
19 | NoopAnimationsModule,
20 | HttpClientTestingModule,
21 | NgxFileUploadUiModule
22 | ],
23 | declarations: [
24 | ],
25 | providers: [{
26 | provide: NgxFileUploadFactory,
27 | useClass: NgxFileuploadFactoryMock
28 | }]
29 | }).compileComponents();
30 | }));
31 |
32 | beforeEach(() => {
33 | fixture = TestBed.createComponent(UploadViewComponent);
34 | testComponent = fixture.componentInstance;
35 | });
36 |
37 | it("should create an upload storage if no one is passed", () => {
38 | fixture.detectChanges();
39 |
40 | expect(testComponent.uploadStorage).not.toBeUndefined();
41 | expect(testComponent.uploadStorage instanceof NgxFileUploadStorage).toBeTruthy();
42 | });
43 |
44 | it( "should call UploadFactory empty files array is dropped", inject(
45 | [NgxFileUploadFactory], (factory: NgxFileuploadFactoryMock
46 | ) => {
47 | const spy = spyOn(factory, "createUploadRequest").and.callThrough();
48 | const file = new File(["hello unit test"], "upload.txt");
49 |
50 | fixture.detectChanges();
51 | testComponent.dropFiles([file]);
52 |
53 | expect(spy).toHaveBeenCalled();
54 | }));
55 |
56 | it( "should not call UploadFactory empty files array is dropped", inject(
57 | [NgxFileUploadFactory], (factory: NgxFileuploadFactoryMock
58 | ) => {
59 | const spy = spyOn(factory, "createUploadRequest").and.callThrough();
60 | fixture.detectChanges();
61 | testComponent.dropFiles([]);
62 | expect(spy).not.toHaveBeenCalled();
63 | }));
64 |
65 | it( "should not create own storage if one is passed", () => {
66 | const fakeStorage = new UploadStorageMock();
67 | testComponent.storage = fakeStorage;
68 | fixture.detectChanges();
69 |
70 | expect(testComponent.uploadStorage).toBe(fakeStorage);
71 | });
72 |
73 | it( "should add headers", () => {
74 | const fakeStorage = new UploadStorageMock();
75 | testComponent.storage = fakeStorage;
76 | testComponent.headers = {
77 | authorization: {
78 | token: "my-token"
79 | }
80 | };
81 | fixture.detectChanges();
82 |
83 | expect(testComponent.headers).toEqual({
84 | authorization: {
85 | token: "my-token"
86 | }
87 | });
88 | });
89 | });
90 |
--------------------------------------------------------------------------------
/src/projects/core/src/tests/upload/upload.queue.spec.ts:
--------------------------------------------------------------------------------
1 | import { NgxFileUploadQueue, NgxFileUploadState } from "@ngx-file-upload/dev/core/public-api";
2 | import { UploadRequestMock, NgxFileUploadRequestModel } from "@ngx-file-upload/testing";
3 |
4 | describe("ngx-fileupload/libs/upload/upload.queue", () => {
5 |
6 | let queue: NgxFileUploadQueue;
7 |
8 | beforeEach(() => {
9 | queue = new NgxFileUploadQueue();
10 | });
11 |
12 | it ("should add upload and register beforeStartHook", () => {
13 |
14 | const uploadFile = new NgxFileUploadRequestModel();
15 | const request = new UploadRequestMock(uploadFile);
16 |
17 | const hookSpy = spyOn(request, "beforeStart");
18 | queue.register(request);
19 |
20 | expect(hookSpy).toHaveBeenCalled();
21 | });
22 |
23 | it ("should set state of second request to pending", () => {
24 | const request1 = new UploadRequestMock(new NgxFileUploadRequestModel());
25 | const request2 = new UploadRequestMock(new NgxFileUploadRequestModel());
26 |
27 | spyOn(request1, "start").and.callFake(() => request1.hooks[0].subscribe(() => (
28 | request1.data.state = NgxFileUploadState.START,
29 | request1.applyChange()
30 | )));
31 |
32 | spyOn(request2, "start").and.callFake(() => request2.hooks[0].subscribe(() =>
33 | expect(request2.data.state).toBe(NgxFileUploadState.PENDING)
34 | ));
35 |
36 | queue.concurrent = 1;
37 |
38 | queue.register(request1);
39 | queue.register(request2);
40 |
41 | request1.start();
42 | request2.start();
43 | });
44 |
45 | it ("should start second request after first completed", () => {
46 | const request1 = new UploadRequestMock(new NgxFileUploadRequestModel());
47 | const request2 = new UploadRequestMock(new NgxFileUploadRequestModel());
48 |
49 | const r2StartSpy = spyOn(request2, "start").and.callThrough();
50 |
51 | queue.concurrent = 1; // concurrent uploads are 0, we could literally upload nothing
52 |
53 | queue.register(request1);
54 | queue.register(request2);
55 |
56 | // start both
57 | request1.start();
58 | request2.start();
59 |
60 | // finish request 1
61 | request1.data.state = NgxFileUploadState.COMPLETED;
62 | request1.applyChange();
63 |
64 | /** should started 2 times */
65 | expect(r2StartSpy).toHaveBeenCalledTimes(2);
66 | expect(request2.isProgress()).toBeTruthy();
67 | });
68 |
69 | it ("should remove request from queue, if request is canceled", () => {
70 | const request1 = new UploadRequestMock(new NgxFileUploadRequestModel());
71 | const request2 = new UploadRequestMock(new NgxFileUploadRequestModel());
72 |
73 | const r2StartSpy = spyOn(request2, "start").and.callThrough();
74 |
75 | queue.concurrent = 1; // concurrent uploads are 0, we could literally upload nothing
76 | queue.register(request1);
77 | queue.register(request2);
78 |
79 | // start both
80 | request1.start();
81 | request2.start();
82 |
83 | // kill request
84 | request2.destroy();
85 |
86 | // finish request 1
87 | request1.data.state = NgxFileUploadState.COMPLETED;
88 | request1.applyChange();
89 |
90 | /** should called only 1 time */
91 | expect(r2StartSpy).toHaveBeenCalledTimes(1);
92 | });
93 | });
94 |
--------------------------------------------------------------------------------
/src/projects/ui/src/lib/toolbar/src/toolbar.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input, OnDestroy } from "@angular/core";
2 | import { Subject } from "rxjs";
3 | import { takeUntil, debounceTime } from "rxjs/operators";
4 | import { INgxFileUploadRequest, NgxFileUploadStorage } from "@ngx-file-upload/core";
5 | import { NgxFileUploadUiI18nProvider, NgxFileUploadUiI18nKey, NgxFileUploadUiI18nToolbar } from "../../i18n";
6 |
7 | interface InfoData {
8 | error: number;
9 | idle: number;
10 | pending: number;
11 | progress: number;
12 | }
13 |
14 | @Component({
15 | selector: "ngx-file-upload-ui--toolbar",
16 | templateUrl: "toolbar.html",
17 | styleUrls: ["./toolbar.scss"]
18 | })
19 | export class UploadToolbarComponent implements OnInit, OnDestroy {
20 |
21 | @Input()
22 | public storage: NgxFileUploadStorage | undefined;
23 |
24 | public uploadInfo: InfoData = { error: 0, pending: 0, idle: 0, progress: 0 };
25 |
26 | public hasUploadsInList = false;
27 |
28 | public i18n: NgxFileUploadUiI18nToolbar | undefined;
29 |
30 | /**
31 | * true if we have completed or invalid uploads
32 | * in list
33 | */
34 | public isCleanable = false;
35 |
36 | /**
37 | */
38 | private destroyed$: Subject = new Subject();
39 |
40 | public constructor(
41 | private i18nProvider: NgxFileUploadUiI18nProvider
42 | ) {}
43 |
44 | ngOnInit() {
45 | this.i18n = this.i18nProvider.getI18n(NgxFileUploadUiI18nKey.ToolBar);
46 | this.registerStoreChange();
47 | }
48 |
49 | ngOnDestroy() {
50 | this.destroyed$.next(true);
51 | }
52 |
53 | /** start upload for all files */
54 | public uploadAll() {
55 | if (this.storage) {
56 | this.storage.startAll();
57 | }
58 | }
59 |
60 | /** stop all uploads */
61 | public stopAll() {
62 | if (this.storage) {
63 | this.storage.stopAll();
64 | }
65 | }
66 |
67 | /** purge uploads, invalid, completed, canceled will be removed */
68 | public cleanAll() {
69 | if (this.storage) {
70 | this.storage.purge();
71 | }
72 | }
73 |
74 | private registerStoreChange() {
75 | if (this.storage) {
76 | this.storage.change()
77 | .pipe(
78 | debounceTime(10),
79 | takeUntil(this.destroyed$)
80 | )
81 | .subscribe((uploads: INgxFileUploadRequest[]) => {
82 | this.updateInfoBar(uploads);
83 | this.isCleanable = uploads.some(upload => upload.isCompleted(true) || upload.isInvalid());
84 | this.hasUploadsInList = uploads.length > 0;
85 | });
86 | }
87 | }
88 |
89 | private updateInfoBar(uploads: INgxFileUploadRequest[]) {
90 | this.uploadInfo = uploads.reduce((data, upload) => {
91 | return {
92 | error : data.error + (upload.hasError() || upload.isInvalid() ? 1 : 0),
93 | idle : data.idle + (upload.isIdle() ? 1 : 0),
94 | pending : data.pending + (upload.isPending() ? 1 : 0),
95 | progress: data.progress + (upload.isProgress() ? 1 : 0)
96 | };
97 | }, {idle: 0, pending: 0, error: 0, progress: 0});
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngx-fileupload",
3 | "version": "11.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "test": "ng test",
9 | "lint": "ng lint",
10 | "e2e": "ng e2e --configuration e2e --port=4201",
11 | "e2e:watch": "watch 'ng e2e --port=4201' lib example e2e --wait=1",
12 | "build:demo": "ng build --configuration=demo --base-href=/ngx-fileupload/",
13 | "deploy:demo": "npx ngh --dir=dist\\ngx-fileupload-example",
14 | "build:core": "ng build core",
15 | "package:core": "tar -cvf ./dist/core.tar.gz -C dist/core .",
16 | "package:ui": "tar -cvf ./dist/ui.tar.gz -C dist/ui .",
17 | "install:core": "npm i --save ./dist/core.tar.gz",
18 | "github-actions:unit-tests-core": "ng test core --watch=false --code-coverage",
19 | "github-actions:unit-tests-ui": "ng test ui --watch=false --code-coverage",
20 | "github-actions:e2e-chrome": "ng e2e --configuration=github-actions-chrome --port=4201",
21 | "github-actions:e2e-firefox": "ng e2e --configuration=github-actions-firefox --port=4201",
22 | "test:code-coverage": "ng test --code-coverage",
23 | "webdriver:update": "webdriver-manager update --version.gecko=v0.26.0 --versions.chrome 78.0.3904.70 --standalone false"
24 | },
25 | "private": true,
26 | "dependencies": {
27 | "@angular-devkit/core": "17.3.4",
28 | "@angular/animations": "17.3.4",
29 | "@angular/cdk": "17.3.4",
30 | "@angular/common": "17.3.4",
31 | "@angular/compiler": "17.3.4",
32 | "@angular/core": "17.3.4",
33 | "@angular/forms": "17.3.4",
34 | "@angular/platform-browser": "17.3.4",
35 | "@angular/platform-browser-dynamic": "17.3.4",
36 | "@angular/router": "17.3.4",
37 | "highlight.js": "11.4.0",
38 | "igniteui-theming": "6.0.2",
39 | "ngx-dropzone": "3.0.0",
40 | "ngx-file-drop": "13.0.0",
41 | "ngx-highlightjs": "6.1.3",
42 | "rxjs": "7.4.0",
43 | "tslib": "2.3.1"
44 | },
45 | "devDependencies": {
46 | "@angular-devkit/build-angular": "17.3.4",
47 | "@angular-eslint/builder": "17.3.0",
48 | "@angular-eslint/eslint-plugin": "17.3.0",
49 | "@angular-eslint/eslint-plugin-template": "17.3.0",
50 | "@angular-eslint/schematics": "17.3.0",
51 | "@angular-eslint/template-parser": "17.3.0",
52 | "@angular/cli": "17.3.4",
53 | "@angular/compiler-cli": "17.3.4",
54 | "@angular/language-service": "17.3.4",
55 | "@types/jasmine": "3.10.5",
56 | "@types/jasminewd2": "2.0.10",
57 | "@types/node": "20.5.6",
58 | "@typescript-eslint/eslint-plugin": "7.6.0",
59 | "@typescript-eslint/parser": "7.6.0",
60 | "bootstrap-scss": "5.1.3",
61 | "codelyzer": "6.0.2",
62 | "cors": "2.8.5",
63 | "eslint": "8.57.0",
64 | "express": "4.17.3",
65 | "express-fileupload": "1.2.1",
66 | "https-proxy-agent": "5.0.0",
67 | "igniteui-angular": "17.1.8",
68 | "jasmine-core": "4.0.0",
69 | "jasmine-spec-reporter": "7.0.0",
70 | "karma": "6.4.3",
71 | "karma-chrome-launcher": "3.2.0",
72 | "karma-coverage": "2.2.1",
73 | "karma-coverage-istanbul-reporter": "3.0.3",
74 | "karma-jasmine": "5.1.0",
75 | "karma-jasmine-html-reporter": "2.1.0",
76 | "karma-mocha-reporter": "2.2.5",
77 | "letslog": "1.0.12",
78 | "ng-packagr": "17.3.0",
79 | "protractor": "7.0.0",
80 | "ts-node": "10.4.0",
81 | "tslint": "6.1.3",
82 | "typescript": "5.4.5",
83 | "watch": "1.0.2",
84 | "zone.js": "0.14.4"
85 | },
86 | "resolutions": {
87 | "https-proxy-agent": "5.0.0"
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/projects/example/libs/utils/http/fake-upload.ts:
--------------------------------------------------------------------------------
1 | import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpEventType, HttpResponse, HttpErrorResponse } from "@angular/common/http";
2 | import { Observable, interval, Subscriber } from "rxjs";
3 | import { Injectable } from "@angular/core";
4 | import { takeWhile } from "rxjs/operators";
5 |
6 | interface FakeUpload {
7 | state: "start" | "progress" | "completed";
8 | uploaded: number;
9 | size: number;
10 | }
11 |
12 | @Injectable()
13 | export class FakeUploadInterceptor implements HttpInterceptor {
14 |
15 | /**
16 | * chunk size: upload speed for 16MBit DSL per second (with sunshine and gas station in front)
17 | */
18 | private chunkSize = 1024 * 1024
19 |
20 | intercept(req: HttpRequest, next: HttpHandler): Observable> {
21 | if (req.url.indexOf("upload") === -1) {
22 | return next.handle(req)
23 | }
24 | debugger
25 | const file: File[] = req.body.has("file") ? req.body.getAll("file") : req.body.getAll("picture")
26 | return this.createFakeUpload(file, req.url.indexOf("error") !== -1)
27 | }
28 |
29 | /**
30 | * return fake upload observable for http client
31 | */
32 | private createFakeUpload(files: File[], hasError = false): Observable> {
33 | return new Observable>((observer) => {
34 | observer.next({type: HttpEventType.Sent})
35 | const upload: FakeUpload = {
36 | state: "progress",
37 | uploaded: 0,
38 | size: files.reduce((size, file) => size + file.size, 0)
39 | };
40 |
41 | // fake upload
42 | interval(1000).pipe(
43 | takeWhile(() => upload.state !== "completed")
44 | ).subscribe({
45 | next: () => this.nextTick(upload, observer),
46 | complete: () => this.uploadCompleted(observer, files.map((file) => file.name).join(', '), hasError)
47 | });
48 | });
49 | }
50 |
51 | /**
52 | * tick next chunk was "uploaded"
53 | */
54 | private nextTick(upload: FakeUpload, observer: Subscriber>): void {
55 | const tmpUploaded = upload.uploaded + this.chunkSize;
56 | const uploadedTotal = tmpUploaded < upload.size ? tmpUploaded : upload.size;
57 |
58 | upload.uploaded = uploadedTotal;
59 |
60 | observer.next({
61 | type: HttpEventType.UploadProgress,
62 | loaded: upload.uploaded,
63 | total: upload.size
64 | });
65 |
66 | if (uploadedTotal === upload.size) {
67 | upload.state = "completed";
68 | }
69 | }
70 |
71 | /**
72 | * upload has been completed
73 | */
74 | private uploadCompleted(observer: Subscriber>, fileName: string, hasError = false ): void {
75 |
76 | if (hasError) {
77 | const error: HttpErrorResponse = new HttpErrorResponse({
78 | status: 401,
79 | error: ["Fakeuploader Random Error", "An error occured"]
80 | });
81 | observer.error(error);
82 | } else {
83 | const response = new HttpResponse({
84 | status: 201,
85 | body: {
86 | file: { id: 0, type: "any" },
87 | message: `Hoooray File: ${fileName} uploaded to /dev/null`
88 | }
89 | });
90 | observer.next(response);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/projects/ui/src/assets/scss/_icons.scss:
--------------------------------------------------------------------------------
1 | @import "./variables";
2 | @import "./animation";
3 |
4 | $font-path : $ngx-fileupload-icons--font-path;
5 | $font-family: $ngx-fileupload-icons--font-family;
6 | $font-size : $ngx-fileupload-icons--font-size;
7 | $line-height: $ngx-fileupload-icons--line-height;
8 |
9 | @font-face {
10 | font-family: '#{$font-family}';
11 | src: url('#{$font-path}/#{$font-family}.eot?p1ifjq');
12 | src: url('#{$font-path}/#{$font-family}.eot?p1ifjq#iefix') format('embedded-opentype'),
13 | url('#{$font-path}/#{$font-family}.ttf?p1ifjq') format('truetype'),
14 | url('#{$font-path}/#{$font-family}.woff?p1ifjq') format('woff'),
15 | url('#{$font-path}/#{$font-family}.svg?p1ifjq##{$font-family}') format('svg');
16 | font-weight: normal;
17 | font-style: normal;
18 | font-display: block;
19 | }
20 |
21 | [class^="ngx-fileupload-icon--"], [class*=" ngx-fileupload-icon--"] {
22 | /* use !important to prevent issues with browser extensions that change fonts */
23 | font-family: '#{$font-family}' !important;
24 | font-style: normal;
25 | font-weight: normal;
26 | font-variant: normal;
27 | text-transform: none;
28 | line-height: $line-height;
29 | font-size: inherit;
30 |
31 | /* Better Font Rendering =========== */
32 | -webkit-font-smoothing: antialiased;
33 | -moz-osx-font-smoothing: grayscale;
34 | }
35 |
36 | .ngx-fileupload-icon--start:before {
37 | color: map-get($map: $colors, $key: "progress");
38 | content: $ngx-fileupload-icon--connect;
39 | }
40 |
41 | .ngx-fileupload-icon--progress {
42 | color: map-get($map: $colors, $key: "progress");
43 | display: inline-block;
44 | -webkit-animation: rotating 2s linear infinite;
45 | -moz-animation: rotating 2s linear infinite;
46 | -ms-animation: rotating 2s linear infinite;
47 | -o-animation: rotating 2s linear infinite;
48 | animation: rotating 2s linear infinite;
49 |
50 | &:before {
51 | content: $ngx-fileupload-icon--progress;
52 | }
53 | }
54 |
55 | .ngx-fileupload-icon--invalid,
56 | .ngx-fileupload-icon--error {
57 | color: map-get($map: $colors, $key: "red");
58 | &:before {
59 | content: $ngx-fileupload-icon--error;
60 | }
61 | }
62 |
63 | .ngx-fileupload-icon--upload {
64 | &:before {
65 | content: $ngx-fileupload-icon--upload;
66 | }
67 | }
68 |
69 | .ngx-fileupload-icon--pending {
70 | &:before {
71 | content: $ngx-fileupload-icon--pending;
72 | }
73 | }
74 |
75 | .ngx-fileupload-icon--idle {
76 | &:before {
77 | content: $ngx-fileupload-icon--idle;
78 | }
79 | }
80 |
81 | .ngx-fileupload-icon--reload {
82 | &:before {
83 | content: $ngx-fileupload-icon--reload;
84 | }
85 | }
86 |
87 | .ngx-fileupload-icon--remove {
88 | &:before {
89 | content: $ngx-fileupload-icon--remove;
90 | }
91 | }
92 |
93 | .ngx-fileupload-icon--add {
94 | &:before {
95 | content: $ngx-fileupload-icon--plus;
96 | }
97 | }
98 |
99 | .ngx-fileupload-icon--cancel,
100 | .ngx-fileupload-icon--canceled {
101 | &:before {
102 | content: $ngx-fileupload-icon--canceled;
103 | }
104 | }
105 |
106 | .ngx-fileupload-icon--completed {
107 |
108 | &.success {
109 | color: map-get($colors, success);
110 |
111 | &:before {
112 | content: $ngx-fileupload-icon--success;
113 | }
114 | }
115 |
116 | &.error {
117 | color: map-get($colors, red);
118 |
119 | &:before {
120 | content: $ngx-fileupload-icon--error;
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------