├── .editorconfig
├── .eslintrc.json
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── angular.json
├── browserslist
├── package-lock.json
├── package.json
├── projects
├── ngx-file-drop-example
│ ├── karma.conf.js
│ ├── src
│ │ ├── app
│ │ │ ├── app.component.html
│ │ │ ├── app.component.scss
│ │ │ ├── app.component.spec.ts
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ └── variables.scss
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.ts
│ │ ├── polyfills.ts
│ │ ├── styles.scss
│ │ └── test.ts
│ ├── tsconfig.app.json
│ └── tsconfig.spec.json
└── ngx-file-drop
│ ├── ng-package.json
│ ├── package.json
│ ├── src
│ ├── lib
│ │ ├── dom.types.ts
│ │ ├── ngx-file-drop-entry.ts
│ │ ├── ngx-file-drop.component.html
│ │ ├── ngx-file-drop.component.scss
│ │ ├── ngx-file-drop.component.ts
│ │ ├── ngx-file-drop.module.ts
│ │ └── ngx-templates.directive.ts
│ └── public-api.ts
│ ├── tsconfig.lib.json
│ └── tsconfig.lib.prod.json
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.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 | ],
15 | "createDefaultProgram": true
16 | },
17 | "extends": [
18 | "plugin:@angular-eslint/recommended",
19 | "plugin:@angular-eslint/template/process-inline-templates"
20 | ],
21 | "rules": {
22 | "@angular-eslint/no-output-on-prefix": "off"
23 | }
24 | },
25 | {
26 | "files": [
27 | "*.html"
28 | ],
29 | "extends": [
30 | "plugin:@angular-eslint/template/recommended"
31 | ],
32 | "rules": {}
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.angular/cache
2 | # Visual Studio
3 | .vs/
4 | .vscode
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.sln.docstates
10 |
11 | # Node Files
12 | /node_modules
13 | /bower_components
14 | npm-debug.log
15 | yarn-error.log
16 |
17 | # IDE configuration
18 | **/.idea/
19 | pre-commit-hook.sh
20 |
21 | # OS generated files
22 | .DS_Store
23 | .DS_Store?
24 | Icon[\r]
25 | ._*
26 | .Spotlight-V100
27 | .Trashes
28 | ehthumbs.db
29 | Thumbs.db
30 |
31 | # Build files
32 | /dist/
33 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Language
2 | language: node_js
3 | node_js:
4 | - "node"
5 |
6 | #Disable google analytics promp
7 | before_install:
8 | - export NG_CLI_ANALYTICS=ci
9 |
10 | # Branches to build
11 | branches:
12 | only:
13 | - master
14 |
15 | install: npm ci
16 |
17 | before_script: npm run lint
18 |
19 | script: npm run build
20 |
21 | # Notifications
22 | notifications:
23 | email:
24 | recipients:
25 | - georgi.peltekov@accedia.com
26 | on_success: change
27 | on_failure: change
28 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## Change Log
2 | ### [16.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v15.0.0...v16.0.0) (2023-06-19)
3 | * Update to Angular 16
4 |
5 | ### [15.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v14.0.2...v15.0.0) (2023-03-07)
6 | * Update to Angular 15
7 |
8 | ### [14.0.2](https://github.com/georgipeltekov/ngx-file-drop/compare/v14.0.1...v14.0.2) (2022-11-23)
9 | * Regression fix due to getAsFile
10 |
11 | ### [14.0.1](https://github.com/georgipeltekov/ngx-file-drop/compare/v14.0.0...v14.0.1) (2022-06-27)
12 | * Use getAsFile when possible
13 |
14 | ### [14.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v13.0.0...v14.0.0) (2022-06-08)
15 | * Update to Angular 14
16 |
17 | ### [13.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v12.0.0...v13.0.0) (2021-12-01)
18 | * Update to Angular 13
19 |
20 | ### [12.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v11.3.0...v12.0.0) (2021-12-01)
21 | * Update to Angular 12
22 |
23 | ### [11.3.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v11.2.0...v11.3.0) (2021-11-04)
24 | * Revert 11.2.0
25 | * Remove unused interfaces from dom.types
26 |
27 | ### [11.2.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v11.1.0...v11.2.0) (2021-09-09)
28 | * On folder/files drop validate accepted file extensions
29 |
30 | ### [11.1.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v11.0.1...v11.1.0) (2021-04-21)
31 | * Make FileSystemFileEntry.file() chainable
32 |
33 | ### [11.0.1](https://github.com/georgipeltekov/ngx-file-drop/compare/v11.0.0...v11.0.1) (2021-02-16)
34 | * Fix bug with dropEffect not taking into consideration and Outlook problems
35 |
36 | ### [11.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v10.1.1...v11.0.0) (2021-01-29)
37 | * Update to Angular 11
38 |
39 | ### [10.1.1](https://github.com/georgipeltekov/ngx-file-drop/compare/v10.0.0...v10.1.1) (2020-11-11)
40 | * Compile with View Engine
41 |
42 | ### [10.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v9.0.1...v10.0.0) (2020-10-02)
43 | * Update to Angular 10
44 |
45 | ### [9.0.1](https://github.com/georgipeltekov/ngx-file-drop/compare/v9.0.0...v9.0.1) (2020-04-15)
46 | * Add dragenter option
47 |
48 | ### [9.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v8.0.8...v9.0.0) (2020-03-31)
49 | * Update to Angular 9
50 |
51 | ### [8.0.8](https://github.com/georgipeltekov/ngx-file-drop/compare/v8.0.7...v8.0.8) (2019-09-26)
52 | * Add directory parameter
53 |
54 | ### [8.0.7](https://github.com/georgipeltekov/ngx-file-drop/compare/v8.0.6...v8.0.7) (2019-08-08)
55 | * Revert previous version due to regression
56 |
57 | ### [8.0.6](https://github.com/georgipeltekov/ngx-file-drop/compare/v8.0.5...v8.0.6) (2019-08-06)
58 | * Add readme to the npm package
59 |
60 | ### [8.0.5](https://github.com/georgipeltekov/ngx-file-drop/compare/v8.0.4...v8.0.5) (2019-08-06)
61 | * Add directory parameter
62 |
63 | ### [8.0.4](https://github.com/georgipeltekov/ngx-file-drop/compare/v8.0.3...v8.0.4) (2019-07-17)
64 | * Lowering node version requirement to LTS version 10 ( again)
65 |
66 | ### [8.0.3](https://github.com/georgipeltekov/ngx-file-drop/compare/v8.0.2...v8.0.3) (2019-06-28)
67 | * Lowering node version requirement to LTS version 10
68 |
69 | ### [8.0.2](https://github.com/georgipeltekov/ngx-file-drop/compare/v8.0.0...v8.0.2) (2019-06-05)
70 | * Update README
71 |
72 | ### [8.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v6.0.1...v8.0.0) (2019-06-04)
73 | * Update to Angular 8
74 |
75 | ### [6.0.1](https://github.com/georgipeltekov/ngx-file-drop/compare/v6.0.0...v6.0.1) (2019-05-08)
76 | * Add support for multiple attribute changing
77 |
78 | ### [6.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v5.1.0...v6.0.0) (2019-03-11)
79 | * Code cleanup and consistent naming scheme, removing deprecated code
80 |
81 | ### [5.1.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v5.0.6...v5.1.0) (2019-03-08)
82 | * Code cleanup and consistent naming scheme
83 |
84 | ### [5.0.6](https://github.com/georgipeltekov/ngx-file-drop/compare/v5.0.5...v5.0.6) (2019-02-27)
85 | * Add accept field
86 |
87 | ### [5.0.5](https://github.com/georgipeltekov/ngx-file-drop/compare/v5.0.4...v5.0.5) (2019-02-13)
88 | * Add custom styling properties
89 |
90 | ### [5.0.4](https://github.com/georgipeltekov/ngx-file-drop/compare/v5.0.3...v5.0.4) (2019-02-04)
91 | * Add property for browse button label
92 | * Code optimization and refactoring
93 |
94 | ### [5.0.3](https://github.com/georgipeltekov/ngx-file-drop/compare/v5.0.2...v5.0.3) (2019-02-01)
95 | * Fix bug introduced with previous version
96 |
97 | ### [5.0.2](https://github.com/georgipeltekov/ngx-file-drop/compare/v5.0.1...v5.0.2) (2019-01-23)
98 | * Add browse file button functionality
99 |
100 | ### [5.0.1](https://github.com/georgipeltekov/ngx-file-drop/compare/v5.0.0...v5.0.1) (2019-01-18)
101 | * Support patch-level differences for zone.js
102 | * Update Readme
103 |
104 | ### [5.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v4.0.6...v5.0.0) (2018-10-22)
105 | * Update to Angular 7.0.0
106 |
107 | ### [4.0.6](https://github.com/georgipeltekov/ngx-file-drop/compare/v4.0.5...v4.0.6) (2018-06-19)
108 | * Bug fixing
109 |
110 | ### [4.0.5](https://github.com/georgipeltekov/ngx-file-drop/compare/v4.0.4...v4.0.5) (2018-06-19)
111 | * Fix for big, nested folder structure
112 |
113 | ### [4.0.4](https://github.com/georgipeltekov/ngx-file-drop/compare/v4.0.3...v4.0.4) (2018-05-16)
114 | * Clear unused dependencies
115 |
116 | ### [4.0.3](https://github.com/georgipeltekov/ngx-file-drop/compare/v4.0.2...v4.0.3) (2018-05-15)
117 | * Loosen Angular-Dependencies
118 |
119 | ### [4.0.2](https://github.com/georgipeltekov/ngx-file-drop/compare/v4.0.0...v4.0.2) (2018-05-15)
120 | * Small changes in gitignore
121 |
122 | ### [4.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v3.0.2...v4.0.0) (2018-05-07)
123 | * Update to Angular 6.0.0
124 |
125 | ### [3.0.2](https://github.com/georgipeltekov/ngx-file-drop/compare/v3.0.1...v3.0.2) (2018-04-29)
126 | * Allow drag events to be ignored that originate from document (introduced in 3.0.1) even if using custom styles
127 |
128 | ### [3.0.1](https://github.com/georgipeltekov/ngx-file-drop/compare/v3.0.0...v3.0.1) (2018-04-25)
129 | * Conditionally Disable Dropzone and Ignore DragEvents that initiate from within the browser document
130 |
131 | ### [3.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v2.0.5...v3.0.0) (2018-03-15)
132 | * Added better typescript types
133 |
134 | ### [2.0.5](https://github.com/georgipeltekov/ngx-file-drop/compare/v2.0.4...v2.0.5) (2018-02-18)
135 | * Some cleanups
136 |
137 | ### [2.0.4](https://github.com/georgipeltekov/ngx-file-drop/compare/v2.0.3...v2.0.4) (2018-01-19)
138 | * Update angular-cli version due to vulnerable dependencies
139 |
140 | ### [2.0.3](https://github.com/georgipeltekov/ngx-file-drop/compare/v2.0.2...v2.0.3) (2018-01-18)
141 | * Multiple File-Drops
142 |
143 | ### [2.0.2](https://github.com/georgipeltekov/ngx-file-drop/compare/v2.0.1...v2.0.2) (2017-12-20)
144 | * Using a workaround to enable getting files when no webkitGetAsEntry is supported
145 |
146 | ### [2.0.1](https://github.com/georgipeltekov/ngx-file-drop/compare/v2.0.0...v2.0.1) (2017-11-20)
147 | * Fix packaging
148 |
149 | ### [2.0.0](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.18...v2.0.0) (2017-11-20)
150 | * Allow angular 4 & 5 and change the build and packaging process
151 |
152 | ### [1.0.18](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.17...v1.0.18) (2017-10-30)
153 | * Allow angular 4 & 5
154 |
155 | ### [1.0.17](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.16...v1.0.17) (2017-10-27)
156 | * Revert Angular 5 changes
157 |
158 | ### [1.0.16](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.15...v1.0.16) (2017-10-27)
159 | * Prepare upgrade to Angular 5
160 | * Changes to confirm to the tslint rules
161 |
162 | ### [1.0.15](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.14...v1.0.15) (2017-10-19)
163 | * Read entries should be called until all dirs are read
164 |
165 | ### [1.0.14](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.13...v1.0.14) (2017-10-19)
166 | * Add dist folder with .js and .js.map files
167 |
168 | ### [1.0.13](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.12...v1.0.13) (2017-10-13)
169 | * Fix typo in Readme
170 | * Add ng-content tag to support nested components within drag/drop region
171 |
172 | ### [1.0.12](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.11...v1.0.12) (2017-09-13)
173 | * Fix bugs in Safari
174 |
175 | ### [1.0.11](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.10...v1.0.11) (2017-09-13)
176 | * Fix bug in Safari
177 |
178 | ### [1.0.10](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.9...v1.0.10) (2017-06-21)
179 | * Check subscription exists before unsubscribing
180 |
181 | ### [1.0.9](https://github.com/georgipeltekov/ngx-file-drop/compare/v1.0.4...v1.0.9) (2017-06-06)
182 | * Add onFileOver and onFileLeave functions
183 |
184 | ### 1.0.8 (2017-06-03)
185 | * Remove some not needed dependencies
186 |
187 | ### 1.0.7 (2017-06-01)
188 | * Fix typos in Readme
189 |
190 | ### 1.0.5 (2017-05-01)
191 | * Add Travis CI
192 | * Update Readme.md
193 |
194 | ### [1.0.4](https://github.com/georgipeltekov/ngx-file-drop/tree/v1.0.4) (2017-05-28)
195 | * Add LICENSE
196 | * Add DEMO
197 |
198 | ### 1.0.3 (2017-05-28)
199 | * Update npm support
200 |
201 | ### 1.0.1 (2017-05-27)
202 | * Doc update
203 | * Style changes
204 |
205 | ### 1.0.0 (2017-05-25)
206 | * Initial release
207 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 georgipeltekov
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
13 | all 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
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.npmjs.com/package/ngx-file-drop) [](https://www.npmjs.com/package/ngx-file-drop) [](https://travis-ci.org/georgipeltekov/ngx-file-drop) [](https://github.com/georgipeltekov/ngx-file-drop/blob/master/LICENSE)
2 |
3 | ## Overview
4 |
5 | An Angular module for simple desktop file and folder drag and drop. This library does not need rxjs-compat.
6 |
7 | For previous Angular support please use older versions.
8 |
9 | This library relies on HTML 5 File API thus IE is not supported
10 |
11 | ## DEMO
12 | You can check the [DEMO](https://georgipeltekov.github.io/) of the library
13 |
14 | ## Installation
15 |
16 | ```bash
17 | npm install ngx-file-drop --save
18 | ```
19 |
20 | ## Usage
21 |
22 |
23 | ### Importing The 'ngx-file-drop' Module
24 |
25 | ```TypeScript
26 | import { BrowserModule } from '@angular/platform-browser';
27 | import { NgModule } from '@angular/core';
28 | import { FormsModule } from '@angular/forms';
29 | import { HttpClientModule } from '@angular/common/http';
30 |
31 | import { AppComponent } from './app.component';
32 | import { NgxFileDropModule } from 'ngx-file-drop';
33 |
34 |
35 | @NgModule({
36 | declarations: [
37 | AppComponent
38 | ],
39 | imports: [
40 | BrowserModule,
41 | FormsModule,
42 | HttpClientModule,
43 | NgxFileDropModule
44 | ],
45 | providers: [],
46 | bootstrap: [AppComponent]
47 | })
48 | export class AppModule { }
49 |
50 | ```
51 |
52 | ### Enabling File Drag
53 |
54 |
55 | ```TypeScript
56 | import { Component } from '@angular/core';
57 | import { NgxFileDropEntry, FileSystemFileEntry, FileSystemDirectoryEntry } from 'ngx-file-drop';
58 |
59 | @Component({
60 | selector: 'demo-root',
61 | templateUrl: './app.component.html',
62 | styleUrls: ['./app.component.scss']
63 | })
64 | export class AppComponent {
65 |
66 | public files: NgxFileDropEntry[] = [];
67 |
68 | public dropped(files: NgxFileDropEntry[]) {
69 | this.files = files;
70 | for (const droppedFile of files) {
71 |
72 | // Is it a file?
73 | if (droppedFile.fileEntry.isFile) {
74 | const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;
75 | fileEntry.file((file: File) => {
76 |
77 | // Here you can access the real file
78 | console.log(droppedFile.relativePath, file);
79 |
80 | /**
81 | // You could upload it like this:
82 | const formData = new FormData()
83 | formData.append('logo', file, relativePath)
84 |
85 | // Headers
86 | const headers = new HttpHeaders({
87 | 'security-token': 'mytoken'
88 | })
89 |
90 | this.http.post('https://mybackend.com/api/upload/sanitize-and-save-logo', formData, { headers: headers, responseType: 'blob' })
91 | .subscribe(data => {
92 | // Sanitized logo returned from backend
93 | })
94 | **/
95 |
96 | });
97 | } else {
98 | // It was a directory (empty directories are added, otherwise only files)
99 | const fileEntry = droppedFile.fileEntry as FileSystemDirectoryEntry;
100 | console.log(droppedFile.relativePath, fileEntry);
101 | }
102 | }
103 | }
104 |
105 | public fileOver(event){
106 | console.log(event);
107 | }
108 |
109 | public fileLeave(event){
110 | console.log(event);
111 | }
112 | }
113 |
114 |
115 | ```
116 | ```HTML
117 |
118 |
120 |
121 | Optional custom content that replaces the the entire default content.
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | Name |
130 |
131 |
132 |
133 |
134 | {{ item.relativePath }} |
135 |
136 |
137 |
138 |
139 |
140 | ```
141 |
142 | ## Parameters
143 |
144 | Name | Description | Example |
145 | ------------- | ------------- | -------------
146 | (onFileDrop) | On drop function called after the files are read | (onFileDrop)="dropped($event)"
147 | (onFileOver) | On drop over function| (onFileOver)="fileOver($event)"
148 | (onFileLeave) | On drop leave function| (onFileLeave)="fileLeave($event)"
149 | accept | String of accepted formats | accept=".png"
150 | directory | Whether directories are accepted | directory="true"
151 | dropZoneLabel | Text to be displayed inside the drop box | dropZoneLabel="Drop files here"
152 | dropZoneClassName | Custom style class name(s) to be used on the "drop-zone" area | dropZoneClassName="my-style"
153 | contentClassName | Custom style class name(s) to be used for the content area | contentClassName="my-style"
154 | \[disabled\] | Conditionally disable the dropzone | \[disabled\]="condition"
155 | \[showBrowseBtn\] | Whether browse file button should be shown | \[showBrowseBtn\]="true"
156 | browseBtnClassName | Custom style class name(s) to be used for the button | browseBtnClassName="my-style"
157 | browseBtnLabel | The label of the browse file button | browseBtnLabel="Browse files"
158 | multiple | Whether multiple or single files are accepted | multiple="true"
159 | useDragEnter | Use dragenter event instead of dragover | useDragEnter="true"
160 |
161 | ## License
162 |
163 | [MIT](/LICENSE)
164 |
165 | ## Change Log
166 |
167 | [CHANGELOG](/CHANGELOG.md)
168 |
169 | ## Donate Crypto
170 | * Bitcoin: 18yJcRSyY7J9K7kHrkNQ2JspLfSgLKWUnh
171 | * Ethereum: 0xdF1E80c91599CA6d4a8745888e658f45B86b0FEd
172 |
173 |
174 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "ngx-file-drop": {
7 | "projectType": "library",
8 | "root": "projects/ngx-file-drop",
9 | "sourceRoot": "projects/ngx-file-drop/src",
10 | "prefix": "lib",
11 | "architect": {
12 | "build": {
13 | "builder": "@angular-devkit/build-angular:ng-packagr",
14 | "options": {
15 | "project": "projects/ngx-file-drop/ng-package.json"
16 | },
17 | "configurations": {
18 | "production": {
19 | "tsConfig": "projects/ngx-file-drop/tsconfig.lib.prod.json"
20 | },
21 | "development": {
22 | "tsConfig": "projects/ngx-file-drop/tsconfig.lib.json"
23 | }
24 | },
25 | "defaultConfiguration": "production"
26 | },
27 | "lint": {
28 | "builder": "@angular-devkit/build-angular:tslint",
29 | "options": {
30 | "eslintConfig": ".eslintrc.json",
31 | "lintFilePatterns": ["**/*.spec.ts", "**/*.ts"]
32 | }
33 | }
34 | }
35 | },
36 | "ngx-file-drop-example": {
37 | "projectType": "application",
38 | "schematics": {
39 | "@schematics/angular:component": {
40 | "style": "scss"
41 | },
42 | "@schematics/angular:application": {
43 | "strict": true
44 | }
45 | },
46 | "root": "projects/ngx-file-drop-example",
47 | "sourceRoot": "projects/ngx-file-drop-example/src",
48 | "prefix": "app",
49 | "architect": {
50 | "build": {
51 | "builder": "@angular-devkit/build-angular:browser",
52 | "options": {
53 | "outputPath": "dist/ngx-file-drop-example",
54 | "index": "projects/ngx-file-drop-example/src/index.html",
55 | "main": "projects/ngx-file-drop-example/src/main.ts",
56 | "polyfills": "projects/ngx-file-drop-example/src/polyfills.ts",
57 | "tsConfig": "projects/ngx-file-drop-example/tsconfig.app.json",
58 | "inlineStyleLanguage": "scss",
59 | "assets": [
60 | "projects/ngx-file-drop-example/src/favicon.ico",
61 | "projects/ngx-file-drop-example/src/assets"
62 | ],
63 | "styles": [
64 | "projects/ngx-file-drop-example/src/styles.scss"
65 | ],
66 | "scripts": []
67 | },
68 | "configurations": {
69 | "production": {
70 | "budgets": [
71 | {
72 | "type": "initial",
73 | "maximumWarning": "500kb",
74 | "maximumError": "1mb"
75 | },
76 | {
77 | "type": "anyComponentStyle",
78 | "maximumWarning": "2kb",
79 | "maximumError": "4kb"
80 | }
81 | ],
82 | "fileReplacements": [
83 | {
84 | "replace": "projects/ngx-file-drop-example/src/environments/environment.ts",
85 | "with": "projects/ngx-file-drop-example/src/environments/environment.prod.ts"
86 | }
87 | ],
88 | "outputHashing": "all"
89 | },
90 | "development": {
91 | "buildOptimizer": false,
92 | "optimization": false,
93 | "vendorChunk": true,
94 | "extractLicenses": false,
95 | "sourceMap": true,
96 | "namedChunks": true
97 | }
98 | },
99 | "defaultConfiguration": "production"
100 | },
101 | "serve": {
102 | "builder": "@angular-devkit/build-angular:dev-server",
103 | "configurations": {
104 | "production": {
105 | "browserTarget": "ngx-file-drop-example:build:production"
106 | },
107 | "development": {
108 | "browserTarget": "ngx-file-drop-example:build:development"
109 | }
110 | },
111 | "defaultConfiguration": "development"
112 | },
113 | "extract-i18n": {
114 | "builder": "@angular-devkit/build-angular:extract-i18n",
115 | "options": {
116 | "browserTarget": "ngx-file-drop-example:build"
117 | }
118 | },
119 | "test": {
120 | "builder": "@angular-devkit/build-angular:karma",
121 | "options": {
122 | "main": "projects/ngx-file-drop-example/src/test.ts",
123 | "polyfills": "projects/ngx-file-drop-example/src/polyfills.ts",
124 | "tsConfig": "projects/ngx-file-drop-example/tsconfig.spec.json",
125 | "karmaConfig": "projects/ngx-file-drop-example/karma.conf.js",
126 | "inlineStyleLanguage": "scss",
127 | "assets": [
128 | "projects/ngx-file-drop-example/src/favicon.ico",
129 | "projects/ngx-file-drop-example/src/assets"
130 | ],
131 | "styles": [
132 | "projects/ngx-file-drop-example/src/styles.scss"
133 | ],
134 | "scripts": []
135 | }
136 | }
137 | }
138 | }},
139 | "cli": {
140 | "analytics": false
141 | },
142 | "schematics": {
143 | "@schematics/angular:component": {
144 | "prefix": "ngx",
145 | "style": "scss"
146 | },
147 | "@schematics/angular:directive": {
148 | "prefix": "ngx"
149 | }
150 | }
151 | }
--------------------------------------------------------------------------------
/browserslist:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # You can see what browsers were selected by your queries by running:
6 | # npx browserslist
7 |
8 | > 0.5%
9 | last 2 versions
10 | Firefox ESR
11 | not dead
12 | not IE 9-11 # For IE 9-11 support, remove 'not'.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "repository": "georgipeltekov/ngx-file-drop",
3 | "engines": {
4 | "node": ">= 16.13.0",
5 | "npm": ">= 8.1.0"
6 | },
7 | "scripts": {
8 | "prestart": "npm run build",
9 | "start": "ng serve",
10 | "clean": "rimraf out-tsc dist/*",
11 | "prebuild": "npm run clean",
12 | "build": "ng build ngx-file-drop --configuration=production",
13 | "lint": "ng lint"
14 | },
15 | "devDependencies": {
16 | "@angular-devkit/build-angular": "^19.1.3",
17 | "@angular-devkit/core": "^16.1.0",
18 | "@angular-eslint/builder": "16.0.3",
19 | "@angular-eslint/eslint-plugin": "16.0.3",
20 | "@angular-eslint/eslint-plugin-template": "16.0.3",
21 | "@angular-eslint/schematics": "16.0.3",
22 | "@angular-eslint/template-parser": "16.0.3",
23 | "@angular/cli": "^16.1.0",
24 | "@angular/common": "^16.1.1",
25 | "@angular/compiler": "^16.1.1",
26 | "@angular/compiler-cli": "^16.1.1",
27 | "@angular/core": "^16.1.1",
28 | "@angular/platform-browser": "^16.1.1",
29 | "@angular/platform-browser-dynamic": "^16.1.1",
30 | "@typescript-eslint/eslint-plugin": "^5.59.2",
31 | "@typescript-eslint/parser": "^5.59.2",
32 | "eslint": "^8.39.0",
33 | "ng-packagr": "^16.1.0",
34 | "rxjs": "^6.5.4",
35 | "typescript": "^4.9.5",
36 | "zone.js": "~0.13.1"
37 | },
38 | "dependencies": {
39 | "tslib": "^2.3.1"
40 | }
41 | }
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/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'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | jasmine: {
17 | // you can add configuration options for Jasmine here
18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19 | // for example, you can disable the random execution with `random: false`
20 | // or set a specific seed with `seed: 4321`
21 | },
22 | clearContext: false // leave Jasmine Spec Runner output visible in browser
23 | },
24 | jasmineHtmlReporter: {
25 | suppressAll: true // removes the duplicated traces
26 | },
27 | coverageReporter: {
28 | dir: require('path').join(__dirname, '../../coverage/ngx-file-drop-example'),
29 | subdir: '.',
30 | reporters: [
31 | { type: 'html' },
32 | { type: 'text-summary' }
33 | ]
34 | },
35 | reporters: ['progress', 'kjhtml'],
36 | port: 9876,
37 | colors: true,
38 | logLevel: config.LOG_INFO,
39 | autoWatch: true,
40 | browsers: ['Chrome'],
41 | singleRun: false,
42 | restartOnFileChange: true
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 | ngx-file-drop-example
3 |
4 |
5 |
6 | Enabled?
7 |
8 |
9 |
11 |
12 |
13 | {{entries | json}}
14 |
15 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/app/app.component.scss:
--------------------------------------------------------------------------------
1 | @import './variables.scss';
2 |
3 | .w-50 {
4 | width: 50%;
5 | }
6 |
7 | .pb-2 {
8 | padding-bottom: 15px;
9 | }
10 |
11 | :host ::ng-deep {
12 |
13 | ngx-file-drop {
14 | div.ngx-file-drop__content,
15 | div.ngx-file-drop__drop-zone--enabled,
16 | div.ngx-file-drop__drop-zone--disabled {
17 | height: 200px;
18 | border-radius: 30px;
19 | color: $colors-text-primary;
20 | font-size: 18px;
21 | font-weight: 400;
22 | font-family: $font-family-standard;
23 | flex-direction: column;
24 | transition: all .2s ease-in-out;
25 |
26 | a {
27 | color: $colors-blue-primary;
28 | }
29 | }
30 |
31 | div.ngx-file-drop__drop-zone--enabled,
32 | div.ngx-file-drop__drop-zone--disabled {
33 | border: 3px dashed $colors-border
34 | }
35 |
36 | div.ngx-file-drop__drop-zone--enabled:hover {
37 | border-color: $colors-text-primary;
38 | }
39 |
40 | div.ngx-file-drop__drop-zone--disabled:hover {
41 | border: 3px dashed $colors-border;
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import { AppComponent } from './app.component';
3 |
4 | describe('AppComponent', () => {
5 | beforeEach(async () => {
6 | await TestBed.configureTestingModule({
7 | declarations: [
8 | AppComponent
9 | ],
10 | }).compileComponents();
11 | });
12 |
13 | it('should create the app', () => {
14 | const fixture = TestBed.createComponent(AppComponent);
15 | const app = fixture.componentInstance;
16 | expect(app).toBeTruthy();
17 | });
18 |
19 | it(`should have as title 'ngx-file-drop-example'`, () => {
20 | const fixture = TestBed.createComponent(AppComponent);
21 | const app = fixture.componentInstance;
22 | expect(app.title).toEqual('ngx-file-drop-example');
23 | });
24 |
25 | it('should render title', () => {
26 | const fixture = TestBed.createComponent(AppComponent);
27 | fixture.detectChanges();
28 | const compiled = fixture.nativeElement as HTMLElement;
29 | expect(compiled.querySelector('.content span')?.textContent).toContain('ngx-file-drop-example app is running!');
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { NgxFileDropEntry } from 'ngx-file-drop';
3 |
4 | @Component({
5 | selector: 'app-root',
6 | templateUrl: './app.component.html',
7 | styleUrls: ['./app.component.scss']
8 | })
9 | export class AppComponent {
10 | title = 'ngx-file-drop-example';
11 |
12 | checked = true;
13 | entries: string[] = [];
14 |
15 | get className(): string {
16 | return !this.checked ? 'ngx-file-drop__drop-zone--disabled' : 'ngx-file-drop__drop-zone--enabled';
17 | }
18 |
19 | dropped(files: NgxFileDropEntry[]): void {
20 | this.entries = files.map(file => file.relativePath);
21 | }
22 |
23 | onChange(event: any): void {
24 | this.checked = event.target.checked;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { NgModule } from '@angular/core';
3 | import { BrowserModule } from '@angular/platform-browser';
4 | import { NgxFileDropModule } from 'ngx-file-drop';
5 | import { AppComponent } from './app.component';
6 |
7 | @NgModule({
8 | declarations: [
9 | AppComponent
10 | ],
11 | imports: [
12 | BrowserModule,
13 | CommonModule,
14 | NgxFileDropModule,
15 | ],
16 | providers: [],
17 | bootstrap: [AppComponent]
18 | })
19 | export class AppModule { }
20 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/app/variables.scss:
--------------------------------------------------------------------------------
1 |
2 | // Grid Breakpoints
3 | $media-breakpoint-up-xl: 1200px;
4 | $media-breakpoint-up-lg: 992px;
5 | $media-breakpoint-up-md: 768px;
6 | $media-breakpoint-up-sm: 575px;
7 |
8 | // Shoe-Stomp Update Began October 2020
9 |
10 | // Font Family
11 | $font-family-standard: 'Inter', sans-serif;
12 | $font-family-display: 'Inter', sans-serif;
13 | $font-family-code: 'Source Code Pro', monospace;
14 | $font-size-standard: 15px;
15 |
16 | // Color System
17 | $colors-brand-blue: #007bff;
18 | $colors-brand-green: #06d6a0;
19 | $colors-white-primary: #ffffff;
20 | $colors-background-primary: #f8f9fa;
21 | $colors-background-secondary: #02284c;
22 | $colors-text-primary: #001428;
23 | $colors-text-secondary: #b6c2cc;
24 | $colors-text-muted: #6c757d;
25 | $colors-border: #dfe2e5;
26 | $colors-blue-iceberg: #80a9d0;
27 | $colors-blue-primary: #007bfd;
28 | $colors-blue-100: #ecf4ff;
29 | $colors-blue-200: #b0d6ff;
30 | $colors-blue-300: #77b7fe;
31 | $colors-blue-400: #3a9afe;
32 | $colors-blue-500: #027afd;
33 | $colors-blue-600: #0269d8;
34 | $colors-blue-700: #0256b2;
35 | $colors-blue-800: #00448c;
36 | $colors-blue-900: #013166;
37 | $colors-green-primary: #0cd7a0;
38 | $colors-green-100: #d8fdf3;
39 | $colors-green-200: #a5f4df;
40 | $colors-green-300: #72eac9;
41 | $colors-green-400: #3ee1b5;
42 | $colors-green-500: #0dd7a0;
43 | $colors-green-600: #0abe8e;
44 | $colors-green-700: #06a67c;
45 | $colors-green-800: #0a8e6a;
46 | $colors-green-900: #0a7457;
47 | $colors-grey-charcoal: #434655;
48 | $colors-grey-ash: #a8aabc;
49 | $colors-grey-200: #f4f5f6;
50 | $colors-grey-300: #e0e2e5;
51 | $colors-grey-400: #d2d6da;
52 | $colors-grey-500: #afb8bf;
53 | $colors-grey-600: #9ba3ac;
54 | $colors-grey-700: #6e7a87;
55 | $colors-grey-800: #40474f;
56 | $colors-grey-900: #121417;
57 | $colors-pink-primary: #f0476f;
58 | $colors-pink-100: #fdecf0;
59 | $colors-pink-200: #f9c3d0;
60 | $colors-pink-300: #f799b0;
61 | $colors-pink-400: #f47190;
62 | $colors-pink-500: #f1476f;
63 | $colors-pink-600: #df3960;
64 | $colors-pink-700: #cd2b51;
65 | $colors-pink-800: #bc1c42;
66 | $colors-pink-900: #aa0e31;
67 | $colors-purple-200: #e0dbfa;
68 | $colors-purple-300: #d1c9f9;
69 | $colors-purple-400: #c1b6f7;
70 | $colors-purple-600: #9282e9;
71 | $colors-purple-700: #7460de;
72 | $colors-purple-800: #543cd3;
73 | $colors-purple-900: #3619c8;
74 | $colors-yellow-300: #fce8af;
75 | $colors-yellow-200: #f7ebc9;
76 | $colors-yellow-400: #fbe093;
77 | $colors-yellow-gold: #fad775;
78 | $colors-yellow-600: #f7cf59;
79 | $colors-yellow-700: #f4c43e;
80 | $colors-yellow-800: #f1ba24;
81 | $colors-yellow-900: #edb009;
82 |
83 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/georgipeltekov/ngx-file-drop/98b39452eeb67805ad0a38f2e7dd3cd3c2c4ae59/projects/ngx-file-drop-example/src/assets/.gitkeep
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build` 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 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/georgipeltekov/ngx-file-drop/98b39452eeb67805ad0a38f2e7dd3cd3c2c4ae59/projects/ngx-file-drop-example/src/favicon.ico
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NgxFileDropExample
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/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 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/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 | /**
22 | * IE11 requires the following for NgClass support on SVG elements
23 | */
24 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
25 |
26 | /**
27 | * Web Animations `@angular/platform-browser/animations`
28 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
29 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
30 | */
31 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
32 |
33 | /**
34 | * By default, zone.js will patch all possible macroTask and DomEvents
35 | * user can disable parts of macroTask/DomEvents patch by setting following flags
36 | * because those flags need to be set before `zone.js` being loaded, and webpack
37 | * will put import in the top of bundle, so user need to create a separate file
38 | * in this directory (for example: zone-flags.ts), and put the following flags
39 | * into that file, and then add the following code before importing zone.js.
40 | * import './zone-flags';
41 | *
42 | * The flags allowed in zone-flags.ts are listed here.
43 | *
44 | * The following flags will work for all browsers.
45 | *
46 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
47 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
48 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
49 | *
50 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
51 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
52 | *
53 | * (window as any).__Zone_enable_cross_context_check = true;
54 | *
55 | */
56 |
57 | /***************************************************************************************************
58 | * Zone JS is required by default for Angular itself.
59 | */
60 | import 'zone.js'; // Included with Angular CLI.
61 |
62 |
63 | /***************************************************************************************************
64 | * APPLICATION IMPORTS
65 | */
66 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/src/styles.scss:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/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/testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | // First, initialize the Angular testing environment.
11 | getTestBed().initTestEnvironment(
12 | BrowserDynamicTestingModule,
13 | platformBrowserDynamicTesting(),
14 | { teardown: { destroyAfterEach: true }},
15 | );
16 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../../out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts",
10 | "src/polyfills.ts"
11 | ],
12 | "include": [
13 | "src/**/*.d.ts"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop-example/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../../out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts",
12 | "src/polyfills.ts"
13 | ],
14 | "include": [
15 | "src/**/*.spec.ts",
16 | "src/**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist/ngx-file-drop",
4 | "lib": {
5 | "entryFile": "src/public-api.ts"
6 | }
7 | }
--------------------------------------------------------------------------------
/projects/ngx-file-drop/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngx-file-drop",
3 | "version": "16.0.0",
4 | "description": "Angular ngx-file-drop - Simple desktop file and folder drag and drop",
5 | "author": "Georgi Peltekov",
6 | "license": "MIT",
7 | "repository": "georgipeltekov/ngx-file-drop",
8 | "engines": {
9 | "node": ">= 14.5.0",
10 | "npm": ">= 6.9.0"
11 | },
12 | "keywords": [
13 | "angular2",
14 | "angular 2",
15 | "angular4",
16 | "angular 4",
17 | "angular5",
18 | "angular 5",
19 | "angular6",
20 | "angular 6",
21 | "angular7",
22 | "angular 7",
23 | "angular8",
24 | "angular 8",
25 | "angular9",
26 | "angular 9",
27 | "angular10",
28 | "angular 10",
29 | "angular11",
30 | "angular 11",
31 | "angular12",
32 | "angular 12",
33 | "angular13",
34 | "angular 13",
35 | "angular14",
36 | "angular 14",
37 | "file drop",
38 | "folder drop",
39 | "file upload",
40 | "folder upload",
41 | "typescript",
42 | "drag and drop"
43 | ],
44 | "peerDependencies": {
45 | "@angular/common": ">=14.0.0",
46 | "@angular/core": ">=14.0.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/src/lib/dom.types.ts:
--------------------------------------------------------------------------------
1 |
2 | export interface FileSystemEntry {
3 | name: string,
4 | isDirectory: boolean
5 | isFile: boolean
6 | }
7 |
8 | export interface FileSystemEntryMetadata {
9 | modificationTime?: Date,
10 | size?: number
11 | }
12 |
13 | export interface FileSystemDirectoryReader {
14 | readEntries(
15 | successCallback: (result: FileSystemEntry[]) => void,
16 | ): void
17 | }
18 |
19 | export interface FileSystemFlags {
20 | create?: boolean
21 | exclusive?: boolean
22 | }
23 |
24 | export interface FileSystemDirectoryEntry extends FileSystemEntry {
25 | isDirectory: true
26 | isFile: false
27 | createReader(): FileSystemDirectoryReader
28 | }
29 |
30 | export interface FileSystemFileEntry extends FileSystemEntry {
31 | isDirectory: false
32 | isFile: true
33 | file(callback: (file: File) => T): T
34 | }
35 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/src/lib/ngx-file-drop-entry.ts:
--------------------------------------------------------------------------------
1 | import { FileSystemEntry, FileSystemFileEntry, FileSystemDirectoryEntry } from './dom.types';
2 |
3 | /**
4 | * fileEntry is an instance of {@link FileSystemFileEntry} or {@link FileSystemDirectoryEntry}.
5 | * Which one is it can be checked using {@link FileSystemEntry.isFile} or {@link FileSystemEntry.isDirectory}
6 | * properties of the given {@link FileSystemEntry}.
7 | */
8 | export class NgxFileDropEntry {
9 | constructor(
10 | public relativePath: string,
11 | public fileEntry: FileSystemEntry
12 | ) {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/src/lib/ngx-file-drop.component.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
21 |
22 |
23 | {{dropZoneLabel}}
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/src/lib/ngx-file-drop.component.scss:
--------------------------------------------------------------------------------
1 | .ngx-file-drop__drop-zone {
2 | height: 100px;
3 | margin: auto;
4 | border: 2px dotted #0782d0;
5 | border-radius: 30px;
6 | }
7 |
8 | .ngx-file-drop__drop-zone--over {
9 | background-color: rgba(147, 147, 147, 0.5);
10 | }
11 |
12 | .ngx-file-drop__content {
13 | display: flex;
14 | align-items: center;
15 | justify-content: center;
16 | height: 100px;
17 | color: #0782d0;
18 | }
19 |
20 | .ngx-file-drop__drop-zone-label {
21 | text-align: center;
22 | }
23 |
24 | .ngx-file-drop__file-input {
25 | display: none;
26 | }
27 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/src/lib/ngx-file-drop.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Component,
3 | ContentChild,
4 | ElementRef,
5 | EventEmitter,
6 | Input,
7 | NgZone,
8 | OnDestroy,
9 | Output,
10 | Renderer2,
11 | TemplateRef,
12 | ViewChild
13 | } from '@angular/core';
14 | import { Subscription, timer } from 'rxjs';
15 |
16 | import { NgxFileDropEntry } from './ngx-file-drop-entry';
17 | import { FileSystemDirectoryEntry, FileSystemEntry, FileSystemFileEntry } from './dom.types';
18 | import { NgxFileDropContentTemplateDirective } from './ngx-templates.directive';
19 |
20 | @Component({
21 | selector: 'ngx-file-drop',
22 | templateUrl: './ngx-file-drop.component.html',
23 | styleUrls: ['./ngx-file-drop.component.scss'],
24 | })
25 | export class NgxFileDropComponent implements OnDestroy {
26 |
27 | @Input()
28 | public accept: string = '*';
29 |
30 | @Input()
31 | public directory: boolean = false;
32 |
33 | @Input()
34 | public multiple: boolean = true;
35 |
36 | @Input()
37 | public dropZoneLabel: string = '';
38 |
39 | @Input()
40 | public dropZoneClassName: string = 'ngx-file-drop__drop-zone';
41 |
42 | @Input()
43 | public useDragEnter: boolean = false;
44 |
45 | @Input()
46 | public contentClassName: string = 'ngx-file-drop__content';
47 |
48 | @Input()
49 | public showBrowseBtn: boolean = false;
50 |
51 | @Input()
52 | public browseBtnClassName: string = 'btn btn-primary btn-xs ngx-file-drop__browse-btn';
53 |
54 | @Input()
55 | public browseBtnLabel: string = 'Browse files';
56 |
57 | @Output()
58 | public onFileDrop: EventEmitter = new EventEmitter();
59 |
60 | @Output()
61 | public onFileOver: EventEmitter = new EventEmitter();
62 |
63 | @Output()
64 | public onFileLeave: EventEmitter = new EventEmitter();
65 |
66 | // custom templates
67 | @ContentChild(NgxFileDropContentTemplateDirective, { read: TemplateRef }) contentTemplate?: TemplateRef;
68 |
69 | @ViewChild('fileSelector', { static: true })
70 | public fileSelector?: ElementRef;
71 |
72 | public isDraggingOverDropZone: boolean = false;
73 |
74 | private globalDraggingInProgress: boolean = false;
75 | private readonly globalDragStartListener: () => void;
76 | private readonly globalDragEndListener: () => void;
77 |
78 | private files: NgxFileDropEntry[] = [];
79 | private numOfActiveReadEntries: number = 0;
80 |
81 | private helperFormEl: HTMLFormElement | null = null;
82 | private fileInputPlaceholderEl: HTMLDivElement | null = null;
83 |
84 | private dropEventTimerSubscription: Subscription | null = null;
85 |
86 | private _disabled: boolean = false;
87 |
88 | public get disabled(): boolean { return this._disabled; }
89 |
90 | @Input()
91 | public set disabled(value: boolean) {
92 | this._disabled = (value != null && `${value}` !== 'false');
93 | }
94 |
95 | constructor(
96 | private zone: NgZone,
97 | private renderer: Renderer2
98 | ) {
99 | this.globalDragStartListener = this.renderer.listen('document', 'dragstart', (evt: Event) => {
100 | this.globalDraggingInProgress = true;
101 | });
102 | this.globalDragEndListener = this.renderer.listen('document', 'dragend', (evt: Event) => {
103 | this.globalDraggingInProgress = false;
104 | });
105 | }
106 |
107 | public ngOnDestroy(): void {
108 | if (this.dropEventTimerSubscription) {
109 | this.dropEventTimerSubscription.unsubscribe();
110 | this.dropEventTimerSubscription = null;
111 | }
112 | this.globalDragStartListener();
113 | this.globalDragEndListener();
114 | this.files = [];
115 | this.helperFormEl = null;
116 | this.fileInputPlaceholderEl = null;
117 | }
118 |
119 | public onDragOver(event: DragEvent): void {
120 | if (this.useDragEnter) {
121 | this.preventAndStop(event);
122 | if (event.dataTransfer) {
123 | event.dataTransfer.dropEffect = 'copy';
124 | }
125 | } else if (!this.isDropzoneDisabled() && !this.useDragEnter && event.dataTransfer) {
126 | if (!this.isDraggingOverDropZone) {
127 | this.isDraggingOverDropZone = true;
128 | this.onFileOver.emit(event);
129 | }
130 | this.preventAndStop(event);
131 | event.dataTransfer.dropEffect = 'copy';
132 | }
133 | }
134 |
135 | public onDragEnter(event: Event): void {
136 | if (!this.isDropzoneDisabled() && this.useDragEnter) {
137 | if (!this.isDraggingOverDropZone) {
138 | this.isDraggingOverDropZone = true;
139 | this.onFileOver.emit(event);
140 | }
141 | this.preventAndStop(event);
142 | }
143 | }
144 |
145 | public onDragLeave(event: Event): void {
146 | if (!this.isDropzoneDisabled()) {
147 | if (this.isDraggingOverDropZone) {
148 | this.isDraggingOverDropZone = false;
149 | this.onFileLeave.emit(event);
150 | }
151 | this.preventAndStop(event);
152 | }
153 | }
154 |
155 | public dropFiles(event: DragEvent): void {
156 | if (this.isDropzoneDisabled()) {
157 | return;
158 | }
159 | this.isDraggingOverDropZone = false;
160 | if (event.dataTransfer) {
161 | let items: FileList | DataTransferItemList;
162 | if (event.dataTransfer.items) {
163 | items = event.dataTransfer.items;
164 | } else {
165 | items = event.dataTransfer.files;
166 | }
167 | this.preventAndStop(event);
168 | this.checkFiles(items);
169 | }
170 | }
171 |
172 | public openFileSelector = (event?: MouseEvent): void => {
173 | if (this.fileSelector && this.fileSelector.nativeElement) {
174 | (this.fileSelector.nativeElement as HTMLInputElement).click();
175 | }
176 | };
177 |
178 | /**
179 | * Processes the change event of the file input and adds the given files.
180 | * @param Event event
181 | */
182 | public uploadFiles(event: Event): void {
183 | if (this.isDropzoneDisabled()) {
184 | return;
185 | }
186 | if (event.target) {
187 | const items = (event.target as HTMLInputElement).files || ([] as any);
188 | this.checkFiles(items);
189 | this.resetFileInput();
190 | }
191 | }
192 |
193 | private getFakeDropEntry(file: File): NgxFileDropEntry {
194 | const fakeFileEntry: FileSystemFileEntry = {
195 | name: file.name,
196 | isDirectory: false,
197 | isFile: true,
198 | file: (callback: (filea: File) => T) => callback(file),
199 | };
200 | return new NgxFileDropEntry(fakeFileEntry.name, fakeFileEntry);
201 | }
202 |
203 | private checkFile(item: DataTransferItem | File): void {
204 | if (!item) {
205 | return;
206 | }
207 | // if ("getAsFile" in item) {
208 | // const file = item.getAsFile();
209 | // if (file) {
210 | // this.addToQueue(
211 | // this.getFakeDropEntry(file)
212 | // );
213 | // return;
214 | // }
215 | // }
216 | if ("webkitGetAsEntry" in item) {
217 | let entry = item.webkitGetAsEntry();
218 | if (entry) {
219 | if (entry.isFile) {
220 | const toUpload: NgxFileDropEntry = new NgxFileDropEntry(entry.name, entry);
221 | this.addToQueue(toUpload);
222 |
223 | } else if (entry.isDirectory) {
224 | this.traverseFileTree(entry, entry.name);
225 | }
226 | return;
227 | }
228 | }
229 | this.addToQueue(this.getFakeDropEntry((item as File)));
230 | }
231 |
232 | private checkFiles(items: FileList | DataTransferItemList): void {
233 | for (let i = 0; i < items.length; i++) {
234 | this.checkFile(items[i]);
235 | }
236 |
237 | if (this.dropEventTimerSubscription) {
238 | this.dropEventTimerSubscription.unsubscribe();
239 | }
240 | this.dropEventTimerSubscription = timer(200, 200)
241 | .subscribe(() => {
242 | if (this.files.length > 0 && this.numOfActiveReadEntries === 0) {
243 | const files = this.files;
244 | this.files = [];
245 | this.onFileDrop.emit(files);
246 | }
247 | });
248 | }
249 |
250 | private traverseFileTree(item: FileSystemEntry, path: string): void {
251 | if (item.isFile) {
252 | const toUpload: NgxFileDropEntry = new NgxFileDropEntry(path, item);
253 | this.files.push(toUpload);
254 |
255 | } else {
256 | path = path + '/';
257 | const dirReader = (item as FileSystemDirectoryEntry).createReader();
258 | let entries: FileSystemEntry[] = [];
259 |
260 | const readEntries = () => {
261 | this.numOfActiveReadEntries++;
262 | dirReader.readEntries((result) => {
263 | if (!result.length) {
264 | // add empty folders
265 | if (entries.length === 0) {
266 | const toUpload: NgxFileDropEntry = new NgxFileDropEntry(path, item);
267 | this.zone.run(() => {
268 | this.addToQueue(toUpload);
269 | });
270 |
271 | } else {
272 | for (let i = 0; i < entries.length; i++) {
273 | this.zone.run(() => {
274 | this.traverseFileTree(entries[i], path + entries[i].name);
275 | });
276 | }
277 | }
278 |
279 | } else {
280 | // continue with the reading
281 | entries = entries.concat(result);
282 | readEntries();
283 | }
284 |
285 | this.numOfActiveReadEntries--;
286 | });
287 | };
288 |
289 | readEntries();
290 | }
291 | }
292 |
293 | /**
294 | * Clears any added files from the file input element so the same file can subsequently be added multiple times.
295 | */
296 | private resetFileInput(): void {
297 | if (this.fileSelector && this.fileSelector.nativeElement) {
298 | const fileInputEl = this.fileSelector.nativeElement as HTMLInputElement;
299 | const fileInputContainerEl = fileInputEl.parentElement;
300 | const helperFormEl = this.getHelperFormElement();
301 | const fileInputPlaceholderEl = this.getFileInputPlaceholderElement();
302 |
303 | // Just a quick check so we do not mess up the DOM (will never happen though).
304 | if (fileInputContainerEl !== helperFormEl) {
305 | // Insert the form input placeholder in the DOM before the form input element.
306 | this.renderer.insertBefore(fileInputContainerEl, fileInputPlaceholderEl, fileInputEl);
307 | // Add the form input as child of the temporary form element, removing the form input from the DOM.
308 | this.renderer.appendChild(helperFormEl, fileInputEl);
309 | // Reset the form, thus clearing the input element of any files.
310 | helperFormEl.reset();
311 | // Add the file input back to the DOM in place of the file input placeholder element.
312 | this.renderer.insertBefore(fileInputContainerEl, fileInputEl, fileInputPlaceholderEl);
313 | // Remove the input placeholder from the DOM
314 | this.renderer.removeChild(fileInputContainerEl, fileInputPlaceholderEl);
315 | }
316 | }
317 | }
318 |
319 | /**
320 | * Get a cached HTML form element as a helper element to clear the file input element.
321 | */
322 | private getHelperFormElement(): HTMLFormElement {
323 | if (!this.helperFormEl) {
324 | this.helperFormEl = this.renderer.createElement('form') as HTMLFormElement;
325 | }
326 |
327 | return this.helperFormEl;
328 | }
329 |
330 | /**
331 | * Get a cached HTML div element to be used as placeholder for the file input element when clearing said element.
332 | */
333 | private getFileInputPlaceholderElement(): HTMLDivElement {
334 | if (!this.fileInputPlaceholderEl) {
335 | this.fileInputPlaceholderEl = this.renderer.createElement('div') as HTMLDivElement;
336 | }
337 |
338 | return this.fileInputPlaceholderEl;
339 | }
340 |
341 | private isDropzoneDisabled(): boolean {
342 | return (this.globalDraggingInProgress || this.disabled);
343 | }
344 |
345 | private addToQueue(item: NgxFileDropEntry): void {
346 | this.files.push(item);
347 | }
348 |
349 | private preventAndStop(event: Event): void {
350 | event.stopPropagation();
351 | event.preventDefault();
352 | }
353 | }
354 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/src/lib/ngx-file-drop.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NgxFileDropComponent } from './ngx-file-drop.component';
4 | import { NgxFileDropContentTemplateDirective } from './ngx-templates.directive';
5 |
6 | @NgModule({
7 | declarations: [
8 | NgxFileDropComponent,
9 | NgxFileDropContentTemplateDirective,
10 | ],
11 | imports: [
12 | CommonModule
13 | ],
14 | exports: [
15 | NgxFileDropComponent,
16 | NgxFileDropContentTemplateDirective,
17 | ],
18 | providers: [],
19 | bootstrap: [
20 | NgxFileDropComponent
21 | ],
22 | })
23 | export class NgxFileDropModule {}
24 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/src/lib/ngx-templates.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, TemplateRef } from '@angular/core';
2 |
3 | @Directive({ selector: '[ngx-file-drop-content-tmp]' })
4 | export class NgxFileDropContentTemplateDirective {
5 | constructor(public template: TemplateRef) { }
6 | }
7 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/src/public-api.ts:
--------------------------------------------------------------------------------
1 | export { NgxFileDropComponent } from './lib/ngx-file-drop.component';
2 | export { NgxFileDropModule } from './lib/ngx-file-drop.module';
3 | export { NgxFileDropEntry } from './lib/ngx-file-drop-entry';
4 | export { FileSystemEntry, FileSystemDirectoryEntry, FileSystemFileEntry } from './lib/dom.types';
5 | export { NgxFileDropContentTemplateDirective } from './lib/ngx-templates.directive';
6 |
--------------------------------------------------------------------------------
/projects/ngx-file-drop/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../../out-tsc/lib",
6 | "declaration": true,
7 | "declarationMap": true,
8 | "inlineSources": true,
9 | "types": []
10 | },
11 | "exclude": [
12 | "src/test.ts",
13 | "**/*.spec.ts"
14 | ]
15 | }
--------------------------------------------------------------------------------
/projects/ngx-file-drop/tsconfig.lib.prod.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.lib.json",
4 | "compilerOptions": {
5 | "declarationMap": false
6 | },
7 | "angularCompilerOptions": {
8 | "compilationMode": "partial"
9 | }
10 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "forceConsistentCasingInFileNames": true,
8 | "strict": true,
9 | "noImplicitOverride": true,
10 | "noPropertyAccessFromIndexSignature": true,
11 | "noImplicitReturns": true,
12 | "noFallthroughCasesInSwitch": true,
13 | "sourceMap": true,
14 | "paths": {
15 | "ngx-file-drop": [
16 | "dist/ngx-file-drop"
17 | ]
18 | },
19 | "declaration": false,
20 | "downlevelIteration": true,
21 | "experimentalDecorators": true,
22 | "moduleResolution": "node",
23 | "importHelpers": true,
24 | "target": "ES2022",
25 | "module": "es2020",
26 | "lib": [
27 | "es2020",
28 | "dom"
29 | ],
30 | "useDefineForClassFields": false
31 | },
32 | "angularCompilerOptions": {
33 | "enableI18nLegacyMessageIdFormat": false,
34 | "strictInjectionParameters": true,
35 | "strictInputAccessModifiers": true,
36 | "strictTemplates": true
37 | }
38 | }
39 |
--------------------------------------------------------------------------------