├── .editorconfig
├── .github
└── FUNDING.yml
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── LICENSE
├── README.md
├── angular.json
├── package-lock.json
├── package.json
├── projects
└── ngx-file-helpers
│ ├── LICENSE
│ ├── README.md
│ ├── ng-package.json
│ ├── package.json
│ ├── src
│ ├── lib
│ │ ├── file-dropzone.directive.ts
│ │ ├── file-handler.ts
│ │ ├── file-picker.directive.ts
│ │ ├── helpers.ts
│ │ ├── ngx-file-helpers.module.ts
│ │ ├── read-file-impl.ts
│ │ ├── read-file.ts
│ │ └── read-mode.enum.ts
│ └── public-api.ts
│ ├── tsconfig.lib.json
│ └── tsconfig.lib.prod.json
├── src
├── app
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.ts
│ ├── file-dropzone-demo
│ │ ├── file-dropzone-demo.component.css
│ │ ├── file-dropzone-demo.component.html
│ │ └── file-dropzone-demo.component.ts
│ ├── file-picker-demo
│ │ ├── file-picker-demo.component.css
│ │ ├── file-picker-demo.component.html
│ │ └── file-picker-demo.component.ts
│ ├── file-picker-large-files-demo
│ │ ├── file-picker-large-files-demo.component.css
│ │ ├── file-picker-large-files-demo.component.html
│ │ └── file-picker-large-files-demo.component.ts
│ └── read-mode.pipe.ts
├── assets
│ └── .gitkeep
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
└── styles.css
├── tsconfig.app.json
├── tsconfig.json
├── version.bat
└── version.sh
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://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 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: fvilers
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # Compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 | /bazel-out
8 |
9 | # Node
10 | /node_modules
11 | npm-debug.log
12 | yarn-error.log
13 |
14 | # IDEs and editors
15 | .idea/
16 | .project
17 | .classpath
18 | .c9/
19 | *.launch
20 | .settings/
21 | *.sublime-workspace
22 |
23 | # Visual Studio Code
24 | .vscode/*
25 | !.vscode/settings.json
26 | !.vscode/tasks.json
27 | !.vscode/launch.json
28 | !.vscode/extensions.json
29 | .history/*
30 |
31 | # Miscellaneous
32 | /.angular/cache
33 | .sass-cache/
34 | /connect.lock
35 | /coverage
36 | /libpeerconnection.log
37 | testem.log
38 | /typings
39 |
40 | # System files
41 | .DS_Store
42 | Thumbs.db
43 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
3 | "version": "0.2.0",
4 | "configurations": [
5 | {
6 | "name": "ng serve",
7 | "type": "pwa-chrome",
8 | "request": "launch",
9 | "preLaunchTask": "npm: start",
10 | "url": "http://localhost:4200/"
11 | },
12 | {
13 | "name": "ng test",
14 | "type": "chrome",
15 | "request": "launch",
16 | "preLaunchTask": "npm: test",
17 | "url": "http://localhost:9876/debug.html"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.exclude": {
3 | ".angular": true,
4 | "dist": true,
5 | "node_modules": true,
6 | "package-lock.json": true
7 | },
8 | "cSpell.words": ["devkit", "dropzone", "packagr"]
9 | }
10 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
3 | "version": "2.0.0",
4 | "tasks": [
5 | {
6 | "type": "npm",
7 | "script": "start",
8 | "isBackground": true,
9 | "problemMatcher": {
10 | "owner": "typescript",
11 | "pattern": "$tsc",
12 | "background": {
13 | "activeOnStart": true,
14 | "beginsPattern": {
15 | "regexp": "(.*?)"
16 | },
17 | "endsPattern": {
18 | "regexp": "bundle generation complete"
19 | }
20 | }
21 | }
22 | },
23 | {
24 | "type": "npm",
25 | "script": "test",
26 | "isBackground": true,
27 | "problemMatcher": {
28 | "owner": "typescript",
29 | "pattern": "$tsc",
30 | "background": {
31 | "activeOnStart": true,
32 | "beginsPattern": {
33 | "regexp": "(.*?)"
34 | },
35 | "endsPattern": {
36 | "regexp": "bundle generation complete"
37 | }
38 | }
39 | }
40 | }
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | https://github.com/fvilers/ngx-file-helpers.git
2 | MIT License
3 |
4 | Copyright (c) 2020 Fabian Vilers
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NgxFileHelpersDemo
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 13.1.3.
4 |
5 | ## Development server
6 |
7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
16 |
17 | ## Running unit tests
18 |
19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20 |
21 | ## Running end-to-end tests
22 |
23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
24 |
25 | ## Further help
26 |
27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
28 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "ngx-file-helpers-demo": {
7 | "projectType": "application",
8 | "schematics": {
9 | "@schematics/angular:component": {
10 | "style": "css",
11 | "skipTests": true
12 | },
13 | "@schematics/angular:class": {
14 | "skipTests": true
15 | },
16 | "@schematics/angular:directive": {
17 | "skipTests": true
18 | },
19 | "@schematics/angular:guard": {
20 | "skipTests": true
21 | },
22 | "@schematics/angular:interceptor": {
23 | "skipTests": true
24 | },
25 | "@schematics/angular:pipe": {
26 | "skipTests": true
27 | },
28 | "@schematics/angular:resolver": {
29 | "skipTests": true
30 | },
31 | "@schematics/angular:service": {
32 | "skipTests": true
33 | },
34 | "@schematics/angular:application": {
35 | "strict": true
36 | }
37 | },
38 | "root": "",
39 | "sourceRoot": "src",
40 | "prefix": "app",
41 | "architect": {
42 | "build": {
43 | "builder": "@angular/build:application",
44 | "options": {
45 | "outputPath": {
46 | "base": "dist/ngx-file-helpers-demo"
47 | },
48 | "index": "src/index.html",
49 | "polyfills": [
50 | "zone.js"
51 | ],
52 | "tsConfig": "tsconfig.app.json",
53 | "inlineStyleLanguage": "css",
54 | "assets": [
55 | "src/favicon.ico",
56 | "src/assets"
57 | ],
58 | "styles": [
59 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
60 | "src/styles.css"
61 | ],
62 | "scripts": [],
63 | "browser": "src/main.ts"
64 | },
65 | "configurations": {
66 | "production": {
67 | "budgets": [
68 | {
69 | "type": "initial",
70 | "maximumWarning": "500kb",
71 | "maximumError": "1mb"
72 | },
73 | {
74 | "type": "anyComponentStyle",
75 | "maximumWarning": "2kb",
76 | "maximumError": "4kb"
77 | }
78 | ],
79 | "fileReplacements": [
80 | {
81 | "replace": "src/environments/environment.ts",
82 | "with": "src/environments/environment.prod.ts"
83 | }
84 | ],
85 | "outputHashing": "all"
86 | },
87 | "development": {
88 | "optimization": false,
89 | "extractLicenses": false,
90 | "sourceMap": true,
91 | "namedChunks": true
92 | }
93 | },
94 | "defaultConfiguration": "production"
95 | },
96 | "serve": {
97 | "builder": "@angular/build:dev-server",
98 | "configurations": {
99 | "production": {
100 | "buildTarget": "ngx-file-helpers-demo:build:production"
101 | },
102 | "development": {
103 | "buildTarget": "ngx-file-helpers-demo:build:development"
104 | }
105 | },
106 | "defaultConfiguration": "development"
107 | },
108 | "extract-i18n": {
109 | "builder": "@angular/build:extract-i18n",
110 | "options": {
111 | "buildTarget": "ngx-file-helpers-demo:build"
112 | }
113 | }
114 | }
115 | },
116 | "ngx-file-helpers": {
117 | "projectType": "library",
118 | "root": "projects/ngx-file-helpers",
119 | "sourceRoot": "projects/ngx-file-helpers/src",
120 | "prefix": "lib",
121 | "architect": {
122 | "build": {
123 | "builder": "@angular/build:ng-packagr",
124 | "options": {
125 | "project": "projects/ngx-file-helpers/ng-package.json"
126 | },
127 | "configurations": {
128 | "production": {
129 | "tsConfig": "projects/ngx-file-helpers/tsconfig.lib.prod.json"
130 | },
131 | "development": {
132 | "tsConfig": "projects/ngx-file-helpers/tsconfig.lib.json"
133 | }
134 | },
135 | "defaultConfiguration": "production"
136 | }
137 | }
138 | }
139 | },
140 | "cli": {
141 | "analytics": false
142 | },
143 | "schematics": {
144 | "@schematics/angular:component": {
145 | "type": "component"
146 | },
147 | "@schematics/angular:directive": {
148 | "type": "directive"
149 | },
150 | "@schematics/angular:service": {
151 | "type": "service"
152 | },
153 | "@schematics/angular:guard": {
154 | "typeSeparator": "."
155 | },
156 | "@schematics/angular:interceptor": {
157 | "typeSeparator": "."
158 | },
159 | "@schematics/angular:module": {
160 | "typeSeparator": "."
161 | },
162 | "@schematics/angular:pipe": {
163 | "typeSeparator": "."
164 | },
165 | "@schematics/angular:resolver": {
166 | "typeSeparator": "."
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngx-file-helpers-demo",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "prestart": "npm run build:lib",
7 | "start": "ng serve",
8 | "start:lib": "ng build ngx-file-helpers --watch",
9 | "build": "ng build",
10 | "build:lib": "ng build ngx-file-helpers --configuration production",
11 | "prepublish:lib": "npm run build:lib",
12 | "publish:lib": "npm publish dist/ngx-file-helpers",
13 | "watch": "ng build --watch --configuration development"
14 | },
15 | "private": true,
16 | "dependencies": {
17 | "@angular/animations": "^20.0.0",
18 | "@angular/cdk": "^20.0.1",
19 | "@angular/common": "^20.0.0",
20 | "@angular/compiler": "^20.0.0",
21 | "@angular/core": "^20.0.0",
22 | "@angular/forms": "^20.0.0",
23 | "@angular/material": "^20.0.1",
24 | "@angular/platform-browser": "^20.0.0",
25 | "@angular/platform-browser-dynamic": "^20.0.0",
26 | "@angular/router": "^20.0.0",
27 | "rxjs": "~7.8.2",
28 | "tslib": "^2.8.1",
29 | "zone.js": "^0.15.1"
30 | },
31 | "devDependencies": {
32 | "@angular/build": "^20.0.0",
33 | "@angular/cli": "^20.0.0",
34 | "@angular/compiler-cli": "^20.0.0",
35 | "@types/jasmine": "~5.1.8",
36 | "@types/node": "^22.15.27",
37 | "jasmine-core": "~5.7.1",
38 | "karma": "~6.4.4",
39 | "karma-chrome-launcher": "~3.2.0",
40 | "karma-coverage": "~2.2.1",
41 | "karma-jasmine": "~5.1.0",
42 | "karma-jasmine-html-reporter": "~2.1.0",
43 | "ng-packagr": "^20.0.0",
44 | "typescript": "~5.8.3"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/LICENSE:
--------------------------------------------------------------------------------
1 | https://github.com/fvilers/ngx-file-helpers.git
2 | MIT License
3 |
4 | Copyright (c) 2020 Fabian Vilers
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/README.md:
--------------------------------------------------------------------------------
1 | # ngx-file-helpers
2 |
3 | Angular File Helpers
4 |
5 | ## Installation
6 |
7 | Add the package to your application.
8 |
9 | ```
10 | npm install --save ngx-file-helpers
11 | ```
12 |
13 | ## Demo
14 |
15 | https://stackblitz.com/edit/ngx-file-helpers-demo
16 |
17 | ## Breaking changes
18 |
19 | Here's a list of the breaking changes upon the 14.0 release:
20 |
21 | - Angular (core/common) version 20.0.0 or greater is a peer dependency;
22 |
23 | Here's a list of the breaking changes upon the 13.0 release:
24 |
25 | - Angular (core/common) version 19.0.0 or greater is a peer dependency;
26 |
27 | Here's a list of the breaking changes upon the 12.0 release:
28 |
29 | - Angular (core/common) version 18.0.0 or greater is a peer dependency;
30 |
31 | Here's a list of the breaking changes upon the 11.0 release:
32 |
33 | - Angular (core/common) version 17.0.0 or greater is a peer dependency;
34 |
35 | Here's a list of the breaking changes upon the 10.0 release:
36 |
37 | - Angular (core/common) version 16.0.0 or greater is a peer dependency;
38 |
39 | Here's a list of the breaking changes upon the 9.0 release:
40 |
41 | - Angular (core/common) version 15.0.0 or greater is a peer dependency;
42 |
43 | Here's a list of the breaking changes upon the 8.0 release:
44 |
45 | - Angular (core/common) version 14.0.0 or greater is a peer dependency;
46 |
47 | Here's a list of the breaking changes upon the 7.0 release:
48 |
49 | - Angular (core/common) version 13.0.0 or greater is a peer dependency;
50 |
51 | Here's a list of the breaking changes upon the 6.0 release:
52 |
53 | - Angular (core/common) version 12.0.0 or greater is a peer dependency;
54 |
55 | Here's a list of the breaking changes upon the 5.0 release:
56 |
57 | - Angular (core/common) version 11.0.0 or greater is a peer dependency;
58 |
59 | Here's a list of the breaking changes upon the 4.0 release:
60 |
61 | - Angular (core/common) version 9.1.0 or greater is a peer dependency;
62 |
63 | Here's a list of the breaking changes upon the 3.0 release:
64 |
65 | - Angular (core/common) version 8.2.0 or greater is a peer dependency;
66 |
67 | Here's a list of the breaking changes upon the 2.0 release:
68 |
69 | - Angular (core/common) version 7.2.0 or greater is a peer dependency;
70 | - The module name has changed to `NgxFileHelpersModule`;
71 | - Read mode is not anymore bound using the directive name but the `[readMode]` property;
72 | - The `lastModifiedDate` property doesn't exist anymore on the `ReadFile` interface.
73 |
74 | ## Getting started
75 |
76 | Import the file helpers module to your application module.
77 |
78 | ```
79 | import { BrowserModule } from '@angular/platform-browser';
80 | import { NgModule } from '@angular/core';
81 | import { NgxFileHelpersModule } from 'ngx-file-helpers';
82 |
83 | import { AppComponent } from './app.component';
84 |
85 | @NgModule({
86 | declarations: [AppComponent],
87 | imports: [
88 | BrowserModule,
89 | NgxFileHelpersModule
90 | ],
91 | bootstrap: [AppComponent]
92 | })
93 | export class AppModule { }
94 | ```
95 |
96 | ## File Picker
97 |
98 | Add the file picker directive to an element, like a button.
99 |
100 | ```
101 |
102 | ```
103 |
104 | Select how the file should be read; by default the mode is dataUrl.
105 |
106 | ```
107 |
108 | ```
109 |
110 | Bind to the `filePick` event to get the picked file from the `$event` variable.
111 |
112 | ```
113 |
119 | ```
120 |
121 | Use the optional `accept` attribute to indicate the types of files that the control can select.
122 |
123 | ```
124 |
131 | ```
132 |
133 | Use the optional `multiple` attribute to indicate whether the user can pick more than one file.
134 |
135 | ```
136 |
144 | ```
145 |
146 | Use the option `filter` attribute to specify a callback that you would implemented to filter if the file should be read or ignored.
147 |
148 | ```
149 |
158 | ```
159 |
160 | ```
161 | export class MyComponent {
162 | ...
163 | ignoreTooBigFile(file: File): boolean {
164 | return file.size < 100000;
165 | }
166 | }
167 | ```
168 |
169 | The directive also has a `reset()` method that unset the selected file. This is useful if you want to force the `filePick` event to trigger again even if the user has picked the same file. The directive is exported as `ngxFilePicker` so you can select is using a `ViewChild` decorator.
170 |
171 | ```
172 |
177 | ```
178 |
179 | ```
180 | export class MyComponent {
181 | ...
182 | @ViewChild('myFilePicker')
183 | private filePicker: FilePickerDirective;
184 | ...
185 |
186 | onReadEnd(fileCount: number) {
187 | this.status = `Read ${fileCount} file(s) on ${new Date().toLocaleTimeString()}.`;
188 | this.filePicker.reset();
189 | }
190 | }
191 | ```
192 |
193 | There are three more events that can be listened to:
194 |
195 | - `readStart`: triggered when the directive start to read files.
196 | - `readError`: triggered when the directive has encountered an error reading a file; this typically occurs when dropping a folder
197 | - `readEnd`: triggered when the directive has read all the files.
198 |
199 | `readStart` emits the number of files (`$event` variable) to be read.
200 | `readError` emits an object containing the file and the error that occurred.
201 | `readEnd` emits the number of files that have been successfully read.
202 |
203 | In some cases you may want to filter files before reading them. You could use a special input argument `filter` which takes a function which should return `true` file to be read or `false` to stop reading.
204 |
205 | ```
206 | export class MyComponent {
207 | ...
208 |
209 | filterFileBeforeReading(file) {
210 | // file is a native browser File
211 | // skip files which are >25mb
212 | return file.size < 25 * 1000 * 1000;
213 | }
214 | }
215 | ```
216 |
217 | ```
218 |
227 | ```
228 |
229 | ## File Dropzone
230 |
231 | Add the file dropzone directive to an element, like a div.
232 |
233 | ```
234 |
Drop a file in this zone.
235 | ```
236 |
237 | Select how the file should be read; by default the mode is dataUrl.
238 |
239 | ```
240 | Drop a file in this zone.
241 | ```
242 |
243 | Bind to the `fileDrop` event to get the dropped file from the `$event` variable.
244 |
245 | ```
246 |
249 | Drop a file in this zone.
250 |
251 | ```
252 |
253 | The directive is exported as `ngxFileDropzone` so you can select is using a `ViewChild` decorator. You can use the same `filter` attribute and `readStart`, `readEnd` events (see the `FilePicker` directive).
254 |
255 | ## ReadFile
256 |
257 | The read file implements the following interface:
258 |
259 | ```
260 | interface ReadFile {
261 | name: string;
262 | size: number;
263 | type: string;
264 | readMode: ReadMode;
265 | content?: any;
266 | underlyingFile: File; // https://developer.mozilla.org/en-US/docs/Web/API/File
267 | }
268 | ```
269 |
270 | ## ReadMode
271 |
272 | Available read modes are exposed through the ReadMode enum:
273 |
274 | ```
275 | enum ReadMode {
276 | ArrayBuffer,
277 | BinaryString,
278 | DataURL,
279 | Text
280 | Skip,
281 | }
282 | ```
283 |
284 | A new read mode has been introduced to ensure the directive skips reading the file. This is particularly important when uploading large files as the FileReader used behind the scenes cannot handle that case by default. Reading the underlying file is left to the directive consumer as the `content` property will be `undefined` for `ReadMode.Skip`.
285 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist/ngx-file-helpers",
4 | "lib": {
5 | "entryFile": "src/public-api.ts"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngx-file-helpers",
3 | "version": "14.0.0",
4 | "description": "Angular File Helpers",
5 | "repository": {
6 | "type": "git",
7 | "url": "git+https://github.com/fvilers/ngx-file-helpers.git"
8 | },
9 | "keywords": [
10 | "angular",
11 | "file",
12 | "helpers"
13 | ],
14 | "author": "Fabian Vilers (https://www.dev-one.com/)",
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/fvilers/ngx-file-helpers/issues"
18 | },
19 | "homepage": "https://github.com/fvilers/ngx-file-helpers/projects/ngx-file-helpers#readme",
20 | "peerDependencies": {
21 | "@angular/common": "^20.0.0",
22 | "@angular/core": "^20.0.0"
23 | },
24 | "dependencies": {
25 | "tslib": "^2.8.1"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/src/lib/file-dropzone.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, HostListener, output } from '@angular/core';
2 | import { FileHandler } from './file-handler';
3 | import { ReadFile } from './read-file';
4 |
5 | @Directive({
6 | selector: '[ngxFileDropzone]',
7 | exportAs: 'ngxFileDropzone',
8 | })
9 | export class FileDropzoneDirective extends FileHandler {
10 | public readonly fileDrop = output();
11 |
12 | @HostListener('dragenter', ['$event'])
13 | public onDragEnter(event: DragEvent) {
14 | event.stopPropagation();
15 | event.preventDefault();
16 | }
17 |
18 | @HostListener('dragover', ['$event'])
19 | public onDragOver(event: DragEvent) {
20 | event.stopPropagation();
21 | event.preventDefault();
22 | }
23 |
24 | @HostListener('drop', ['$event'])
25 | public onDrop(event: DragEvent) {
26 | event.stopPropagation();
27 | event.preventDefault();
28 |
29 | if (event.dataTransfer !== null) {
30 | this.readFiles(event.dataTransfer.files, (readFile) =>
31 | this.fileDrop.emit(readFile)
32 | );
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/src/lib/file-handler.ts:
--------------------------------------------------------------------------------
1 | import { Directive, input, output } from '@angular/core';
2 | import { readFileAsync } from './helpers';
3 | import { ReadFile } from './read-file';
4 | import { ReadMode } from './read-mode.enum';
5 |
6 | @Directive()
7 | export abstract class FileHandler {
8 | public readonly readMode = input(ReadMode.DataURL);
9 |
10 | public readonly filter = input<(file: File, index: number, files: Array) => boolean>(() => true);
11 |
12 | public readonly readStart = output();
13 |
14 | public readonly readEnd = output();
15 |
16 | public readonly readError = output<{
17 | file: File;
18 | error: any;
19 | }>();
20 |
21 | protected async readFiles(
22 | files: FileList,
23 | onFileRead: (fileRead: ReadFile) => void
24 | ): Promise {
25 | const filteredFiles = Array.from(files).filter((file, index, array) =>
26 | this.filter()(file, index, array)
27 | );
28 | const fileCount = filteredFiles.length;
29 | let readCount = 0;
30 |
31 | this.readStart.emit(fileCount);
32 |
33 | await Promise.all(
34 | filteredFiles.map(async (file) => {
35 | try {
36 | const readFile = await readFileAsync(file, this.readMode());
37 | onFileRead(readFile);
38 | readCount++;
39 | } catch (err) {
40 | this.readError.emit({ file, error: err });
41 | // do not re-throw, the promise returned by readFiles is not awaited anywhere
42 | // and re-throwing would result in "unhandled rejections" that the consumer cannot handle
43 | }
44 | })
45 | ).finally(() => {
46 | this.readEnd.emit(readCount);
47 | });
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/src/lib/file-picker.directive.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Directive,
3 | ElementRef,
4 | HostListener,
5 | OnInit,
6 | Renderer2,
7 | booleanAttribute,
8 | inject,
9 | input,
10 | output
11 | } from '@angular/core';
12 | import { FileHandler } from './file-handler';
13 | import { ReadFile } from './read-file';
14 |
15 | @Directive({
16 | selector: '[ngxFilePicker]',
17 | exportAs: 'ngxFilePicker',
18 | })
19 | export class FilePickerDirective extends FileHandler implements OnInit {
20 | readonly #el = inject(ElementRef);
21 | readonly #renderer = inject(Renderer2);
22 |
23 | public readonly accept = input('');
24 |
25 | public readonly multiple = input(false, {
26 | transform: booleanAttribute,
27 | });
28 |
29 | public readonly filePick = output();
30 |
31 | private _input?: HTMLInputElement;
32 |
33 | public ngOnInit() {
34 | this._input = this.#renderer.createElement('input');
35 | this.#renderer.appendChild(this.#el.nativeElement, this._input);
36 |
37 | this.#renderer.setAttribute(this._input, 'type', 'file');
38 | this.#renderer.setAttribute(this._input, 'accept', this.accept());
39 | this.#renderer.setStyle(this._input, 'display', 'none');
40 |
41 | if (this.multiple()) {
42 | this.#renderer.setAttribute(this._input, 'multiple', 'multiple');
43 | }
44 |
45 | this.#renderer.listen(this._input, 'change', (event: Event) =>
46 | this._onListen(event)
47 | );
48 | }
49 |
50 | public reset() {
51 | if (!this._input) {
52 | console.error(
53 | 'It seems that ngOnInit() has not been executed or that the hidden _input element is null. Did you mess with the DOM?'
54 | );
55 | return;
56 | }
57 |
58 | this._input.value = '';
59 | }
60 |
61 | @HostListener('click')
62 | public browse() {
63 | if (!this._input) {
64 | console.error(
65 | 'It seems that ngOnInit() has not been executed or that the hidden _input element is null. Did you mess with the DOM?'
66 | );
67 | return;
68 | }
69 |
70 | this._input.click();
71 | }
72 |
73 | // The callback signature prevent the async/await usage
74 | private _onListen(event: Event) {
75 | const target = event.target as HTMLInputElement;
76 |
77 | if (target.files !== null) {
78 | this.readFiles(target.files, (readFile) => this.filePick.emit(readFile))
79 | // reset value to trick change event making it changeable every time
80 | .finally(() => (target.value = ''));
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/src/lib/helpers.ts:
--------------------------------------------------------------------------------
1 | import { ReadFile } from './read-file';
2 | import { ReadFileImpl } from './read-file-impl';
3 | import { ReadMode } from './read-mode.enum';
4 |
5 | export function coerceBooleanProperty(value: any): boolean {
6 | return value != null && `${value}` !== 'false';
7 | }
8 |
9 | export async function readFileAsync(
10 | file: File,
11 | readMode: ReadMode
12 | ): Promise {
13 | return new Promise((resolve, reject) => {
14 | const reader = new FileReader();
15 |
16 | reader.onload = (event: ProgressEvent) => {
17 | const fileReader = event.target as FileReader;
18 | const readFile = new ReadFileImpl(file, readMode, fileReader.result);
19 |
20 | resolve(readFile);
21 | };
22 |
23 | reader.onerror = (event: ProgressEvent) => {
24 | reject(event);
25 | };
26 |
27 | switch (readMode) {
28 | case ReadMode.ArrayBuffer:
29 | reader.readAsArrayBuffer(file);
30 | break;
31 | case ReadMode.BinaryString:
32 | reader.readAsBinaryString(file);
33 | break;
34 | case ReadMode.Text:
35 | reader.readAsText(file);
36 | break;
37 | case ReadMode.Skip:
38 | // Immediately return without reading the file
39 | // See: https://github.com/fvilers/ngx-file-helpers/issues/57
40 | resolve(new ReadFileImpl(file, readMode));
41 | break;
42 | case ReadMode.DataURL:
43 | default:
44 | reader.readAsDataURL(file);
45 | break;
46 | }
47 | });
48 | }
49 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/src/lib/ngx-file-helpers.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { FileDropzoneDirective } from './file-dropzone.directive';
3 | import { FilePickerDirective } from './file-picker.directive';
4 |
5 | @NgModule({
6 | imports: [FileDropzoneDirective, FilePickerDirective],
7 | exports: [FileDropzoneDirective, FilePickerDirective],
8 | })
9 | export class NgxFileHelpersModule { }
10 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/src/lib/read-file-impl.ts:
--------------------------------------------------------------------------------
1 | import { ReadFile } from './read-file';
2 | import { ReadMode } from './read-mode.enum';
3 |
4 | export class ReadFileImpl implements ReadFile {
5 | get name(): string {
6 | return this.underlyingFile.name;
7 | }
8 |
9 | get size(): number {
10 | return this.underlyingFile.size;
11 | }
12 |
13 | get type(): string {
14 | return this.underlyingFile.type;
15 | }
16 |
17 | constructor(
18 | public readonly underlyingFile: File,
19 | public readonly readMode: ReadMode,
20 | public readonly content?: any
21 | ) {}
22 | }
23 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/src/lib/read-file.ts:
--------------------------------------------------------------------------------
1 | import { ReadMode } from './read-mode.enum';
2 |
3 | export interface ReadFile {
4 | name: string;
5 | size: number;
6 | type: string;
7 | readMode: ReadMode;
8 | content?: any;
9 | underlyingFile: File;
10 | }
11 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/src/lib/read-mode.enum.ts:
--------------------------------------------------------------------------------
1 | export enum ReadMode {
2 | ArrayBuffer,
3 | BinaryString,
4 | DataURL,
5 | Text,
6 | Skip,
7 | }
8 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/src/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of ngx-file-helpers
3 | */
4 |
5 | export * from './lib/file-dropzone.directive';
6 | export * from './lib/file-picker.directive';
7 | export * from './lib/ngx-file-helpers.module';
8 | export * from './lib/read-file';
9 | export * from './lib/read-mode.enum';
10 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/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": ["src/test.ts", "**/*.spec.ts"]
12 | }
13 |
--------------------------------------------------------------------------------
/projects/ngx-file-helpers/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 | }
11 |
--------------------------------------------------------------------------------
/src/app/app.component.css:
--------------------------------------------------------------------------------
1 | .filler {
2 | flex: 1 1 auto;
3 | }
4 |
5 | main {
6 | padding: 20px;
7 | }
8 |
9 | .tab-container {
10 | padding: 5px;
11 | }
12 |
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 | Angular File Helpers Demo
3 |
4 | GitHub
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { MatButtonModule } from '@angular/material/button';
3 | import { MatTabsModule } from '@angular/material/tabs';
4 | import { MatToolbarModule } from '@angular/material/toolbar';
5 | import { NgxFileHelpersModule } from 'ngx-file-helpers';
6 | import { FileDropzoneDemoComponent } from './file-dropzone-demo/file-dropzone-demo.component';
7 | import { FilePickerDemoComponent } from './file-picker-demo/file-picker-demo.component';
8 | import { FilePickerLargeFilesDemoComponent } from './file-picker-large-files-demo/file-picker-large-files-demo.component';
9 |
10 | @Component({
11 | selector: 'app-root',
12 | templateUrl: './app.component.html',
13 | styleUrl: './app.component.css',
14 | imports: [
15 | MatButtonModule,
16 | MatTabsModule,
17 | MatToolbarModule,
18 | NgxFileHelpersModule,
19 | FileDropzoneDemoComponent,
20 | FilePickerDemoComponent,
21 | FilePickerLargeFilesDemoComponent
22 | ]
23 | })
24 | export class AppComponent { }
25 |
--------------------------------------------------------------------------------
/src/app/file-dropzone-demo/file-dropzone-demo.component.css:
--------------------------------------------------------------------------------
1 | .dropzone {
2 | align-items: center;
3 | background: lightgrey;
4 | border: dashed 1px grey;
5 | display: flex;
6 | justify-content: center;
7 | height: 350px;
8 | width: 500px;
9 | }
10 |
11 | .hover {
12 | background: grey;
13 | border: dashed 1px darkgrey;
14 | }
15 |
--------------------------------------------------------------------------------
/src/app/file-dropzone-demo/file-dropzone-demo.component.html:
--------------------------------------------------------------------------------
1 | Drop a file
2 |
8 |
9 | @if (files.length) {
10 | Dropped files
11 | }
12 |
13 |
14 | @for(file of files; track $index) {
15 | -
16 | {{ file.name }} ({{ file.size }} bytes) read using {{ readMode | readMode }}
17 |
{{ file.content }}
18 |
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/src/app/file-dropzone-demo/file-dropzone-demo.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { NgxFileHelpersModule, ReadFile, ReadMode } from 'ngx-file-helpers';
3 | import { ReadModePipe } from '../read-mode.pipe';
4 |
5 | @Component({
6 | selector: 'app-file-dropzone-demo',
7 | templateUrl: './file-dropzone-demo.component.html',
8 | styleUrl: './file-dropzone-demo.component.css',
9 | imports: [NgxFileHelpersModule, ReadModePipe]
10 | })
11 | export class FileDropzoneDemoComponent {
12 | public readMode = ReadMode.DataURL;
13 | public isHover: boolean = false;
14 | public files: Array = [];
15 |
16 | addFile(file: ReadFile) {
17 | this.files.push(file);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/app/file-picker-demo/file-picker-demo.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fvilers/ngx-file-helpers/998c179947bb57e4ba799722bf59573648d9836b/src/app/file-picker-demo/file-picker-demo.component.css
--------------------------------------------------------------------------------
/src/app/file-picker-demo/file-picker-demo.component.html:
--------------------------------------------------------------------------------
1 | Pick an image
2 |
3 | {{ status }}
4 |
5 | @if (picked) {
6 |
7 |
8 |
9 |
10 | File:
11 | {{ picked.name }}
12 |
13 | {{ picked.size }} bytes
14 | Read as {{ picked.readMode | readMode }}
15 |
16 |
17 | }
18 |
19 |
34 |
--------------------------------------------------------------------------------
/src/app/file-picker-demo/file-picker-demo.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, viewChild } from '@angular/core';
2 | import { MatButtonModule } from '@angular/material/button';
3 | import {
4 | FilePickerDirective,
5 | NgxFileHelpersModule,
6 | ReadFile,
7 | ReadMode,
8 | } from 'ngx-file-helpers';
9 | import { ReadModePipe } from '../read-mode.pipe';
10 |
11 | @Component({
12 | selector: 'app-file-picker-demo',
13 | templateUrl: './file-picker-demo.component.html',
14 | styleUrl: './file-picker-demo.component.css',
15 | imports: [MatButtonModule, NgxFileHelpersModule, ReadModePipe]
16 | })
17 | export class FilePickerDemoComponent {
18 | public readMode = ReadMode.DataURL;
19 | public picked: ReadFile | null = null;
20 | public status: string | null = null;
21 |
22 | protected readonly filePicker = viewChild(FilePickerDirective);
23 |
24 | protected ignoreTooBigFile(file: File): boolean {
25 | return file.size < 100000;
26 | }
27 |
28 | protected onReadStart(fileCount: number): void {
29 | this.status = `Reading ${fileCount} file(s)...`;
30 | this.picked = null;
31 | }
32 |
33 | protected onFilePicked(file: ReadFile): void {
34 | this.picked = file;
35 | }
36 |
37 | protected onReadEnd(fileCount: number): void {
38 | this.status = `Read ${fileCount} file(s) on ${new Date().toLocaleTimeString()}.`;
39 | this.filePicker()?.reset();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/app/file-picker-large-files-demo/file-picker-large-files-demo.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fvilers/ngx-file-helpers/998c179947bb57e4ba799722bf59573648d9836b/src/app/file-picker-large-files-demo/file-picker-large-files-demo.component.css
--------------------------------------------------------------------------------
/src/app/file-picker-large-files-demo/file-picker-large-files-demo.component.html:
--------------------------------------------------------------------------------
1 | Pick a large file
2 |
3 | {{ status }}
4 |
5 | @if (picked) {
6 |
7 | {{ picked.name }} ({{ picked.size }} bytes) read using {{
8 | readMode | readMode
9 | }}
10 |
11 | }
12 |
13 |
25 |
--------------------------------------------------------------------------------
/src/app/file-picker-large-files-demo/file-picker-large-files-demo.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, viewChild } from '@angular/core';
2 | import { MatButtonModule } from '@angular/material/button';
3 | import {
4 | FilePickerDirective,
5 | NgxFileHelpersModule,
6 | ReadFile,
7 | ReadMode,
8 | } from 'ngx-file-helpers';
9 | import { ReadModePipe } from '../read-mode.pipe';
10 |
11 | @Component({
12 | selector: 'app-file-picker-large-files-demo',
13 | templateUrl: './file-picker-large-files-demo.component.html',
14 | styleUrl: './file-picker-large-files-demo.component.css',
15 | imports: [MatButtonModule, NgxFileHelpersModule, ReadModePipe]
16 | })
17 | export class FilePickerLargeFilesDemoComponent {
18 | public readMode = ReadMode.Skip;
19 | public picked: ReadFile | null = null;
20 | public status: string | null = null;
21 |
22 | protected readonly filePicker = viewChild(FilePickerDirective);
23 |
24 | protected onReadStart(fileCount: number): void {
25 | this.status = `Reading ${fileCount} file(s)...`;
26 | this.picked = null;
27 | }
28 |
29 | protected onFilePicked(file: ReadFile): void {
30 | this.picked = file;
31 | }
32 |
33 | protected onReadEnd(fileCount: number): void {
34 | this.status = `Read ${fileCount} file(s) on ${new Date().toLocaleTimeString()}.`;
35 | this.filePicker()?.reset();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/app/read-mode.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { ReadMode } from 'ngx-file-helpers';
3 |
4 | @Pipe({ name: 'readMode' })
5 | export class ReadModePipe implements PipeTransform {
6 | public transform(value: ReadMode): string {
7 | switch (value) {
8 | case ReadMode.ArrayBuffer:
9 | return 'Array Buffer';
10 | case ReadMode.BinaryString:
11 | return 'Binary String';
12 | case ReadMode.DataURL:
13 | return 'Data URL';
14 | case ReadMode.Text:
15 | return 'Text';
16 | case ReadMode.Skip:
17 | return 'Skip';
18 | default:
19 | console.warn('Missing case for read mode', value);
20 | return '';
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fvilers/ngx-file-helpers/998c179947bb57e4ba799722bf59573648d9836b/src/assets/.gitkeep
--------------------------------------------------------------------------------
/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | };
4 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fvilers/ngx-file-helpers/998c179947bb57e4ba799722bf59573648d9836b/src/favicon.ico
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ngx-file-helpers Demo
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { ApplicationConfig, enableProdMode } from '@angular/core';
2 | import { bootstrapApplication } from '@angular/platform-browser';
3 | import { provideAnimations } from '@angular/platform-browser/animations';
4 | import { AppComponent } from './app/app.component';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | const appConfig: ApplicationConfig = {
12 | providers: [provideAnimations()]
13 | }
14 |
15 | bootstrapApplication(AppComponent, appConfig).catch((err) => {
16 | console.error(err)
17 | });
18 |
--------------------------------------------------------------------------------
/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 recent versions of Safari, Chrome (including
12 | * Opera), Edge on the desktop, and iOS 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 | * By default, zone.js will patch all possible macroTask and DomEvents
23 | * user can disable parts of macroTask/DomEvents patch by setting following flags
24 | * because those flags need to be set before `zone.js` being loaded, and webpack
25 | * will put import in the top of bundle, so user need to create a separate file
26 | * in this directory (for example: zone-flags.ts), and put the following flags
27 | * into that file, and then add the following code before importing zone.js.
28 | * import './zone-flags';
29 | *
30 | * The flags allowed in zone-flags.ts are listed here.
31 | *
32 | * The following flags will work for all browsers.
33 | *
34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
37 | *
38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
40 | *
41 | * (window as any).__Zone_enable_cross_context_check = true;
42 | *
43 | */
44 |
45 | /***************************************************************************************************
46 | * Zone JS is required by default for Angular itself.
47 | */
48 | import 'zone.js'; // Included with Angular CLI.
49 |
50 | /***************************************************************************************************
51 | * APPLICATION IMPORTS
52 | */
53 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
3 | html,
4 | body {
5 | height: 100%;
6 | }
7 | body {
8 | margin: 0;
9 | font-family: Roboto, "Helvetica Neue", sans-serif;
10 | }
11 |
--------------------------------------------------------------------------------
/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": ["src/main.ts"],
9 | "include": ["src/**/*.d.ts"]
10 | }
11 |
--------------------------------------------------------------------------------
/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 | "esModuleInterop": true,
9 | "strict": true,
10 | "noImplicitOverride": true,
11 | "noPropertyAccessFromIndexSignature": true,
12 | "noImplicitReturns": true,
13 | "noFallthroughCasesInSwitch": true,
14 | "sourceMap": true,
15 | "paths": {
16 | "ngx-file-helpers": [
17 | "dist/ngx-file-helpers/ngx-file-helpers",
18 | "dist/ngx-file-helpers"
19 | ]
20 | },
21 | "declaration": false,
22 | "experimentalDecorators": true,
23 | "moduleResolution": "bundler",
24 | "importHelpers": true,
25 | "target": "ES2022",
26 | "module": "es2020",
27 | "lib": [
28 | "es2020",
29 | "dom"
30 | ],
31 | "useDefineForClassFields": false
32 | },
33 | "angularCompilerOptions": {
34 | "enableI18nLegacyMessageIdFormat": false,
35 | "strictInjectionParameters": true,
36 | "strictInputAccessModifiers": true,
37 | "strictTemplates": true
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/version.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | IF "%1"=="" GOTO :usage
4 |
5 | rem Important: no space between %1 and pipe
6 | echo %1|findstr /r "^[0-9]*[0-9]\.[0-9]*[0-9]\.[0-9]*[0-9]$" >nul 2>&1
7 | IF errorlevel 1 (
8 | GOTO :usage
9 | )
10 |
11 | pushd projects\ngx-file-helpers
12 | CALL npm version %1
13 | popd
14 |
15 | CALL git commit -a -m "%1" && git tag v%1
16 | CALL git push && git push --tags
17 |
18 | GOTO:eof
19 |
20 | :usage
21 | echo Usage: %0 ^ ^(x.y.z^)
22 |
--------------------------------------------------------------------------------
/version.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | usage () {
4 | echo "Usage: $0 (x.y.z)"
5 | exit 1
6 | }
7 |
8 | if [ "$#" -ne 1 ]; then
9 | usage
10 | fi
11 |
12 | version=$1
13 |
14 | if [[ "$version" =~ ^[0-9]*[0-9]\.[0-9]*[0-9]\.[0-9]*[0-9]$ ]]; then
15 | echo $version
16 | else
17 | usage
18 | fi
19 |
20 | pushd projects/ngx-file-helpers
21 | npm version $version
22 | popd
23 |
24 | git commit -a -m "$version" && git tag $version
25 | git push && git push --tags
26 |
--------------------------------------------------------------------------------