├── .editorconfig ├── .eslintrc.json ├── .github └── workflows │ └── nodejs.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── projects └── angular-busy2 │ ├── .eslintrc.json │ ├── LICENSE │ ├── README.md │ ├── ng-package.json │ ├── package.json │ ├── src │ ├── lib │ │ ├── cgBusy.component.css │ │ ├── cgBusy.component.html │ │ ├── cgBusy.component.ts │ │ ├── cgBusy.directive.ts │ │ ├── cgBusy.interface.ts │ │ ├── cgBusy.module.ts │ │ ├── cgBusy.service.ts │ │ └── cgBusyDefaults.service.ts │ └── public_api.ts │ ├── tsconfig.lib.json │ ├── tsconfig.lib.lint.json │ ├── tsconfig.lib.prod.json │ └── tsconfig.spec.json ├── src ├── app │ ├── app.component.css │ ├── app.component.html │ ├── app.component.ts │ └── app.config.ts ├── assets │ ├── favicon.ico │ └── finalfantasy.gif ├── index.html ├── main.ts ├── styles.css └── theme.scss ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.lint.json └── tsconfig.spec.json /.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 | ij_typescript_use_double_quotes = false 14 | 15 | [*.md] 16 | max_line_length = off 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /.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.lint.json", 14 | "tsconfig.spec.json" 15 | ] 16 | }, 17 | "plugins": [ 18 | "@typescript-eslint" 19 | ], 20 | "extends": [ 21 | "plugin:@angular-eslint/recommended", 22 | "plugin:@angular-eslint/template/process-inline-templates" 23 | ], 24 | "rules": { 25 | "@angular-eslint/component-selector": [ 26 | "error", 27 | { 28 | "prefix": "app", 29 | "style": "kebab-case", 30 | "type": "element" 31 | } 32 | ], 33 | "@angular-eslint/directive-selector": [ 34 | "error", 35 | { 36 | "prefix": "app", 37 | "style": "camelCase", 38 | "type": "attribute" 39 | } 40 | ] 41 | } 42 | }, 43 | { 44 | "files": [ 45 | "*.html" 46 | ], 47 | "extends": [ 48 | "plugin:@angular-eslint/template/recommended" 49 | ], 50 | "rules": {} 51 | } 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [22.x] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | - name: npm install, build, and deploy 21 | run: | 22 | npm ci --legacy-peer-deps 23 | npm run deploy 24 | env: 25 | CI: true 26 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://docs.github.com/get-started/getting-started-with-git/ignoring-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 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at tiberiuzuld@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Tiberiu Zuld 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-busy2 [Live Demo](https://tiberiuzuld.github.io/angular-busy) 2 | 3 | [![npm version](https://badge.fury.io/js/angular-busy2.svg)](https://badge.fury.io/js/angular-busy2) 4 | ![Node CI](https://github.com/tiberiuzuld/angular-busy/workflows/Node%20CI/badge.svg) 5 | [![downloads](https://img.shields.io/npm/dm/angular-busy2.svg)](https://www.npmjs.com/package/angular-busy2) 6 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/tiberiuzuld) 7 | 8 | > Show busy/loading indicators on Observable, Subscription, Promise, Boolean, Number 9 | 10 | ### For [AngularJS 1 branch 1.x](https://github.com/tiberiuzuld/angular-busy/tree/1.x) 11 | 12 | ## Getting Started 13 | 14 | Install with npm. 15 | 16 | ```bash 17 | npm install angular-busy2 --save 18 | ``` 19 | 20 | Add `CgBusyModule` as a module dependency for your module. 21 | 22 | You have to import it with `forRoot` in any module where you want to provide `CgBusyDefaults`. 23 | 24 | Usually you do that in your root module (`app.module`). 25 | 26 | If you never import it with `forRoot` `CgBusyDefaults` will always be `undefined`. 27 | 28 | `forRoot` takes optional `CgBusyOptions` as parameter. 29 | 30 | For every omitted option in the supplied `CgBusyOptions` the libraries default value will be used. 31 | 32 | ```typescript 33 | import { CgBusyModule } from 'angular-busy2'; 34 | 35 | @NgModule({ 36 | imports: [ 37 | CgBusyModule.forRoot({ 38 | backdrop: true 39 | }) //import it with .forRoot in your root module. provide some optional Options. 40 | ] 41 | }) 42 | ``` 43 | 44 | In every shared module/sub module you should import `CgBusyModule` without `forRoot` unless you want to provide a 45 | different instance of `CgBusyDefaults` 46 | 47 | ### Standalone import directive 48 | 49 | ```typescript 50 | import { CgBusyDirective } from 'angular-busy2'; 51 | 52 | @Component({ 53 | standalone: true, 54 | imports: [CgBusyDirective], 55 | // ... 56 | }) 57 | 58 | // main.ts if you bootstrap application 59 | bootstrapApplication(AppComponent, { 60 | providers: [ 61 | importProvidersFrom(CgBusyModule.forRoot()) 62 | // ... 63 | ] 64 | }).catch(err => console.log(err)); 65 | ``` 66 | 67 | ## Options 68 | 69 | The `[cgBusy]` directive expects any Observable, Subscription, Promise, Boolean, Number and optional `[cgBusyConfig]` 70 | configuration object. 71 | 72 | In other words. You may do this: 73 | 74 | ```html 75 | 76 |
77 | ``` 78 | 79 | or this: 80 | 81 | ```html 82 | 83 |
85 | ``` 86 | 87 | * `promise` - Required. The promise/Observables (or array of promises/Observables) that will cause the busy indicator to 88 | show. Also supports boolean and numbers (truthy values will show loading...) 89 | * `message` - Optional. Defaults to 'Please Wait...'. The message to show in the indicator. This value may be updated 90 | while the promise is active. The indicator will reflect the updated values as they're changed. 91 | * `backdrop` - Optional. Boolean, default is true. If true a faded backdrop will be shown behind the progress indicator. 92 | * `templateRef` - Optional. If provided, the given template will be shown in place of the default progress indicator 93 | template. 94 | * `delay` - Optional. The amount of time to wait until showing the indicator. Defaults to 0. Specified in milliseconds. 95 | * `minDuration` - Optional. The amount of time to keep the indicator showing even if the promise was resolved quicker. 96 | Defaults to 0. Specified in milliseconds. 97 | * `wrapperClass` - Optional. The name(s) of the CSS classes to be applied to the wrapper element of the busy 98 | sign/animation. Defaults to `undefined`. Typically only useful if you wish to apply different positioning to the 99 | animation. 100 | 101 | ## Overriding Defaults 102 | 103 | The default values for `message`, `backdrop`, `templateRef`, `delay`, and `minDuration` may all be overridden by 104 | overriding the `CgBusyDefaults`, like so: 105 | 106 | ```typescript 107 | import { CgBusyDefaults } from 'angular-busy2'; 108 | 109 | class AppComponent { 110 | @ViewChild('customTemplate') 111 | private customTemplateTpl: TemplateRef; 112 | 113 | constructor(private busyDefaults: CgBusyDefaults) { 114 | this.busyDefaults.delay = 5000; 115 | } 116 | 117 | ngOnInit() { 118 | this.busyDefaults.templateRef = this.customTemplateTpl; 119 | } 120 | } 121 | ``` 122 | 123 | ```html 124 | 125 | 126 |
127 |
128 |
129 |
130 | ``` 131 | 132 | Only the values you'd like overridden need to be specified. 133 | 134 | > Fork from original angular-busy (cgBusy) https://github.com/cgross/angular-busy 135 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-busy2-app": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:application": { 10 | "strict": true 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "cg", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:application", 19 | "options": { 20 | "outputPath": "dist/demo", 21 | "index": "src/index.html", 22 | "polyfills": [ 23 | "zone.js" 24 | ], 25 | "tsConfig": "tsconfig.app.json", 26 | "assets": [ 27 | "src/assets" 28 | ], 29 | "styles": [ 30 | "src/styles.css", 31 | "src/theme.scss" 32 | ], 33 | "scripts": [], 34 | "browser": "src/main.ts" 35 | }, 36 | "configurations": { 37 | "production": { 38 | "baseHref": "/angular-busy/", 39 | "budgets": [ 40 | { 41 | "type": "anyComponentStyle", 42 | "maximumWarning": "4kb", 43 | "maximumError": "8kb" 44 | } 45 | ], 46 | "outputHashing": "all" 47 | }, 48 | "development": { 49 | "optimization": false, 50 | "extractLicenses": false, 51 | "sourceMap": true 52 | } 53 | }, 54 | "defaultConfiguration": "production" 55 | }, 56 | "serve": { 57 | "builder": "@angular-devkit/build-angular:dev-server", 58 | "configurations": { 59 | "production": { 60 | "buildTarget": "angular-busy2-app:build:production" 61 | }, 62 | "development": { 63 | "buildTarget": "angular-busy2-app:build:development" 64 | } 65 | }, 66 | "defaultConfiguration": "development" 67 | }, 68 | "extract-i18n": { 69 | "builder": "@angular-devkit/build-angular:extract-i18n" 70 | }, 71 | "test": { 72 | "builder": "@angular-devkit/build-angular:karma", 73 | "options": { 74 | "polyfills": [ 75 | "zone.js", 76 | "zone.js/testing" 77 | ], 78 | "tsConfig": "tsconfig.spec.json", 79 | "assets": [ 80 | "src/assets" 81 | ], 82 | "styles": [ 83 | "src/styles.css" 84 | ], 85 | "scripts": [] 86 | } 87 | }, 88 | "lint": { 89 | "builder": "@angular-eslint/builder:lint", 90 | "options": { 91 | "lintFilePatterns": [ 92 | "src/**/*.ts", 93 | "src/**/*.html" 94 | ] 95 | } 96 | }, 97 | "deploy": { 98 | "builder": "angular-cli-ghpages:deploy", 99 | "options": { 100 | "buildTarget": "angular-busy2-app:build:production", 101 | "repo": "https://GH_TOKEN@github.com/tiberiuzuld/angular-busy.git", 102 | "name": "Tiberiu Zuld", 103 | "email": "tiberiuzuld@gmail.com" 104 | } 105 | } 106 | } 107 | }, 108 | "angular-busy2": { 109 | "projectType": "library", 110 | "root": "projects/angular-busy2", 111 | "sourceRoot": "projects/angular-busy2/src", 112 | "prefix": "lib", 113 | "architect": { 114 | "build": { 115 | "builder": "@angular-devkit/build-angular:ng-packagr", 116 | "options": { 117 | "project": "projects/angular-busy2/ng-package.json" 118 | }, 119 | "configurations": { 120 | "production": { 121 | "tsConfig": "projects/angular-busy2/tsconfig.lib.prod.json" 122 | }, 123 | "development": { 124 | "tsConfig": "projects/angular-busy2/tsconfig.lib.json" 125 | } 126 | }, 127 | "defaultConfiguration": "production" 128 | }, 129 | "test": { 130 | "builder": "@angular-devkit/build-angular:karma", 131 | "options": { 132 | "tsConfig": "projects/angular-busy2/tsconfig.spec.json", 133 | "polyfills": [ 134 | "zone.js", 135 | "zone.js/testing" 136 | ] 137 | } 138 | }, 139 | "lint": { 140 | "builder": "@angular-eslint/builder:lint", 141 | "options": { 142 | "lintFilePatterns": [ 143 | "projects/angular-busy2/**/*.ts", 144 | "projects/angular-busy2/**/*.html" 145 | ] 146 | } 147 | } 148 | } 149 | } 150 | }, 151 | "cli": { 152 | "analytics": "1f4c9dbf-755c-4ca9-a896-da7d97faf505", 153 | "schematicCollections": [ 154 | "@angular-eslint/schematics" 155 | ] 156 | }, 157 | "schematics": { 158 | "@angular-eslint/schematics:application": { 159 | "setParserOptionsProject": true 160 | }, 161 | "@angular-eslint/schematics:library": { 162 | "setParserOptionsProject": true 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-busy2", 3 | "version": "21.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "build-demo": "ng build", 12 | "build-npm": "ng build angular-busy2", 13 | "watch": "ng build --watch --configuration development", 14 | "deploy": "npm run build-npm && ng deploy" 15 | }, 16 | "sideEffects": false, 17 | "homepage": "https://tiberiuzuld.github.io/angular-busy/", 18 | "bugs": { 19 | "url": "https://github.com/tiberiuzuld/angular-busy/issues" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/tiberiuzuld/angular-busy.git" 24 | }, 25 | "description": "Angular Busy 2", 26 | "keywords": [ 27 | "angular", 28 | "angularjs", 29 | "typescript", 30 | "busy", 31 | "loading", 32 | "angular-busy2", 33 | "angular-busy" 34 | ], 35 | "authors": [ 36 | "Tiberiu Zuld" 37 | ], 38 | "dependencies": { 39 | "@angular/animations": "19.0.3", 40 | "@angular/cdk": "19.0.2", 41 | "@angular/common": "19.0.3", 42 | "@angular/compiler": "19.0.3", 43 | "@angular/core": "19.0.3", 44 | "@angular/forms": "19.0.3", 45 | "@angular/material": "19.0.2", 46 | "@angular/platform-browser": "19.0.3", 47 | "@angular/platform-browser-dynamic": "19.0.3", 48 | "@angular/router": "19.0.3", 49 | "rxjs": "7.8.1", 50 | "tslib": "2.8.1", 51 | "zone.js": "0.15.0" 52 | }, 53 | "devDependencies": { 54 | "@angular-devkit/build-angular": "19.0.3", 55 | "@angular-eslint/builder": "19.0.0", 56 | "@angular-eslint/eslint-plugin": "19.0.0", 57 | "@angular-eslint/eslint-plugin-template": "19.0.0", 58 | "@angular-eslint/schematics": "19.0.0", 59 | "@angular-eslint/template-parser": "19.0.0", 60 | "@angular/cli": "19.0.3", 61 | "@angular/compiler-cli": "19.0.3", 62 | "@types/jasmine": "5.1.5", 63 | "@types/node": "22.10.1", 64 | "angular-cli-ghpages": "2.0.3", 65 | "eslint": "9.16.0", 66 | "jasmine-core": "5.5.0", 67 | "karma": "6.4.4", 68 | "karma-chrome-launcher": "3.2.0", 69 | "karma-coverage": "2.2.1", 70 | "karma-jasmine": "5.1.0", 71 | "karma-jasmine-html-reporter": "2.1.0", 72 | "ng-packagr": "19.0.1", 73 | "typescript": "5.6.3", 74 | "typescript-eslint": "8.17.0" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /projects/angular-busy2/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../.eslintrc.json", 3 | "ignorePatterns": [ 4 | "!**/*" 5 | ], 6 | "overrides": [ 7 | { 8 | "files": [ 9 | "*.ts" 10 | ], 11 | "parserOptions": { 12 | "project": [ 13 | "projects/angular-busy2/tsconfig.lib.lint.json", 14 | "projects/angular-busy2/tsconfig.spec.json" 15 | ] 16 | }, 17 | "rules": { 18 | "@angular-eslint/directive-selector": [ 19 | "error", 20 | { 21 | "type": "attribute", 22 | "prefix": "cg", 23 | "style": "camelCase" 24 | } 25 | ], 26 | "@angular-eslint/component-selector": [ 27 | "error", 28 | { 29 | "type": "element", 30 | "prefix": "cg", 31 | "style": "kebab-case" 32 | } 33 | ] 34 | } 35 | }, 36 | { 37 | "files": [ 38 | "*.html" 39 | ], 40 | "rules": {} 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /projects/angular-busy2/LICENSE: -------------------------------------------------------------------------------- 1 | ../../LICENSE -------------------------------------------------------------------------------- /projects/angular-busy2/README.md: -------------------------------------------------------------------------------- 1 | ../../README.md -------------------------------------------------------------------------------- /projects/angular-busy2/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../dist/angular-busy2", 4 | "lib": { 5 | "entryFile": "src/public_api.ts" 6 | } 7 | } -------------------------------------------------------------------------------- /projects/angular-busy2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-busy2", 3 | "version": "21.0.0", 4 | "license": "MIT", 5 | "homepage": "https://tiberiuzuld.github.io/angular-busy/", 6 | "bugs": { 7 | "url": "https://github.com/tiberiuzuld/angular-busy/issues" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/tiberiuzuld/angular-busy.git" 12 | }, 13 | "description": "Angular Busy 2", 14 | "keywords": [ 15 | "angular", 16 | "angularjs", 17 | "typescript", 18 | "busy", 19 | "loading", 20 | "angular-busy2", 21 | "angular-busy" 22 | ], 23 | "authors": [ 24 | "Tiberiu Zuld" 25 | ], 26 | "sideEffects": false, 27 | "peerDependencies": { 28 | "@angular/common": "^19.0.0", 29 | "@angular/core": "^19.0.0" 30 | }, 31 | "dependencies": { 32 | "tslib": "^2.4.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /projects/angular-busy2/src/lib/cgBusy.component.css: -------------------------------------------------------------------------------- 1 | .cg-busy, .cg-busy .cg-busy-template, .cg-busy .cg-busy-backdrop { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | right: 0; 6 | bottom: 0; 7 | width: 100%; 8 | height: 100% 9 | } 10 | 11 | .cg-busy { 12 | z-index: 1001; 13 | text-align: center; 14 | } 15 | 16 | .cg-busy-animation.ng-hide-add, 17 | .cg-busy-animation.ng-hide-remove { 18 | transition: all .3s ease; 19 | display: block !important; 20 | } 21 | 22 | .cg-busy-animation.ng-hide-remove { 23 | opacity: 0; 24 | transform: translate(0px, -40px); 25 | } 26 | 27 | .cg-busy-animation.ng-hide-remove.ng-hide-remove-active { 28 | opacity: 1; 29 | transform: translate(0px, 0px); 30 | } 31 | 32 | .cg-busy-animation.ng-hide-add { 33 | opacity: 1; 34 | transform: translate(0px, 0px); 35 | } 36 | 37 | .cg-busy-animation.ng-hide-add.ng-hide-add-active { 38 | opacity: 0; 39 | transform: translate(0px, -40px); 40 | } 41 | 42 | .cg-busy-backdrop { 43 | background-color: white; 44 | opacity: .7; 45 | } 46 | 47 | .cg-busy-backdrop-animation.ng-hide-add, 48 | .cg-busy-backdrop-animation.ng-hide-remove { 49 | transition: opacity .3s ease; 50 | display: block !important; 51 | } 52 | 53 | .cg-busy-backdrop-animation.ng-hide { 54 | opacity: 0; 55 | } 56 | 57 | /* All styles below are for the default template. */ 58 | 59 | .cg-busy-default-sign { 60 | display: inline-block; 61 | position: relative; 62 | z-index: 1002; 63 | padding-bottom: 6px; 64 | color: #333333; 65 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); 66 | background-color: #e9eeee; 67 | border: 1px solid #dddddd; 68 | border-top-width: 0; 69 | border-radius: 7px; 70 | border-top-left-radius: 0; 71 | border-top-right-radius: 0; 72 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .2), 0 1px 2px rgba(0, 0, 0, .05); 73 | } 74 | 75 | .cg-busy-default-text { 76 | margin: 13px 12px 6px 49px; 77 | font-size: 16px; 78 | color: #555; 79 | text-align: left; 80 | max-width: 400px; 81 | } 82 | 83 | .cg-busy-default-spinner { 84 | position: absolute; 85 | width: 25px; 86 | height: 25px; 87 | display: inline-block; 88 | top: 12px; 89 | left: 14px; 90 | } 91 | 92 | .cg-busy-default-spinner div { 93 | width: 12%; 94 | height: 26%; 95 | background: #000; 96 | position: absolute; 97 | left: 44.5%; 98 | top: 37%; 99 | opacity: 0; 100 | animation: cg-busy-spinner-anim 1s linear infinite; 101 | border-radius: 50px; 102 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 103 | } 104 | 105 | .cg-busy-default-spinner div.bar1 { 106 | transform: rotate(0deg) translate(0, -142%); 107 | animation-delay: 0s; 108 | } 109 | 110 | .cg-busy-default-spinner div.bar2 { 111 | transform: rotate(30deg) translate(0, -142%); 112 | animation-delay: -0.9167s; 113 | } 114 | 115 | .cg-busy-default-spinner div.bar3 { 116 | transform: rotate(60deg) translate(0, -142%); 117 | animation-delay: -0.833s; 118 | } 119 | 120 | .cg-busy-default-spinner div.bar4 { 121 | transform: rotate(90deg) translate(0, -142%); 122 | animation-delay: -0.75s; 123 | } 124 | 125 | .cg-busy-default-spinner div.bar5 { 126 | transform: rotate(120deg) translate(0, -142%); 127 | animation-delay: -0.667s; 128 | } 129 | 130 | .cg-busy-default-spinner div.bar6 { 131 | transform: rotate(150deg) translate(0, -142%); 132 | animation-delay: -0.5833s; 133 | } 134 | 135 | .cg-busy-default-spinner div.bar7 { 136 | transform: rotate(180deg) translate(0, -142%); 137 | animation-delay: -0.5s; 138 | } 139 | 140 | .cg-busy-default-spinner div.bar8 { 141 | transform: rotate(210deg) translate(0, -142%); 142 | animation-delay: -0.41667s; 143 | } 144 | 145 | .cg-busy-default-spinner div.bar9 { 146 | transform: rotate(240deg) translate(0, -142%); 147 | animation-delay: -0.333s; 148 | } 149 | 150 | .cg-busy-default-spinner div.bar10 { 151 | transform: rotate(270deg) translate(0, -142%); 152 | animation-delay: -0.25s; 153 | } 154 | 155 | .cg-busy-default-spinner div.bar11 { 156 | transform: rotate(300deg) translate(0, -142%); 157 | animation-delay: -0.1667s; 158 | } 159 | 160 | .cg-busy-default-spinner div.bar12 { 161 | transform: rotate(330deg) translate(0, -142%); 162 | animation-delay: -0.0833s; 163 | } 164 | 165 | @keyframes cg-busy-spinner-anim { 166 | from { 167 | opacity: 1; 168 | } 169 | to { 170 | opacity: 0.25; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /projects/angular-busy2/src/lib/cgBusy.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
7 | 8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /projects/angular-busy2/src/lib/cgBusy.component.ts: -------------------------------------------------------------------------------- 1 | import {NgTemplateOutlet} from '@angular/common'; 2 | import {Component, Input, ViewEncapsulation} from '@angular/core'; 3 | import type {CgBusyOptions} from './cgBusy.interface'; 4 | import {CgBusyService} from './cgBusy.service'; 5 | 6 | @Component({ 7 | templateUrl: './cgBusy.component.html', 8 | styleUrls: ['./cgBusy.component.css'], 9 | selector: 'cg-busy', 10 | encapsulation: ViewEncapsulation.None, 11 | imports: [NgTemplateOutlet] 12 | }) 13 | export class CgBusyComponent { 14 | @Input() options: CgBusyOptions; 15 | @Input() tracker: CgBusyService; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /projects/angular-busy2/src/lib/cgBusy.directive.ts: -------------------------------------------------------------------------------- 1 | import {ComponentRef, Directive, ElementRef, Input, OnChanges, OnDestroy, Renderer2, SimpleChanges, ViewContainerRef} from '@angular/core'; 2 | import {Observable, Subscription} from 'rxjs'; 3 | import {CgBusyComponent} from './cgBusy.component'; 4 | import type {CgBusyOptions} from './cgBusy.interface'; 5 | import {CgBusyService} from './cgBusy.service'; 6 | import {CgBusyDefaults} from './cgBusyDefaults.service'; 7 | 8 | @Directive({selector: '[cgBusy]', standalone: true, exportAs: 'cgBusy'}) 9 | export class CgBusyDirective implements OnChanges, OnDestroy { 10 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 11 | @Input() cgBusy: boolean | number | Promise | Subscription | Observable | (Promise | Subscription | Observable)[]; 12 | @Input() cgBusyConfig: CgBusyOptions; 13 | tracker: CgBusyService; 14 | fakePromise: Promise; 15 | fakePromiseResolve: () => void; 16 | $options: CgBusyOptions; 17 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 18 | $promise: (Promise | Subscription | Observable)[]; 19 | componentRef: ComponentRef; 20 | 21 | constructor(private viewContainer: ViewContainerRef, private defaultOptions: CgBusyDefaults, 22 | private renderer: Renderer2, private el: ElementRef) { 23 | this.$options = {...this.defaultOptions}; 24 | this.$promise = []; 25 | this.renderer.setStyle(this.el.nativeElement.parentNode, 'position', 'relative'); 26 | this.componentRef = this.viewContainer.createComponent(CgBusyComponent); 27 | this.tracker = new CgBusyService(); 28 | this.tracker.detectChanges = () => this.componentRef.changeDetectorRef.detectChanges(); 29 | this.componentRef.instance.tracker = this.tracker; 30 | this.componentRef.instance.options = this.$options; 31 | } 32 | 33 | ngOnChanges(changes: SimpleChanges): void { 34 | if (changes.cgBusyConfig) { 35 | this.$options = { 36 | ...this.defaultOptions, 37 | ...this.$options, 38 | ...this.cgBusyConfig 39 | }; 40 | this.componentRef.instance.options = this.$options; 41 | } 42 | if (changes.cgBusy) { 43 | if (this.fakePromise) { 44 | this.fakePromiseResolve(); 45 | this.fakePromise = undefined; 46 | this.fakePromiseResolve = undefined; 47 | } 48 | 49 | if (Number.isFinite(this.cgBusy) || this.cgBusy === true || this.cgBusy === false) { 50 | this.fakePromise = new Promise((resolve) => { 51 | this.fakePromiseResolve = resolve; 52 | if (!this.cgBusy) { 53 | resolve(); 54 | } 55 | }); 56 | this.$promise = [this.fakePromise]; 57 | } else if (Array.isArray(this.cgBusy)) { 58 | this.$promise = this.cgBusy; 59 | } else { 60 | // @ts-ignore 61 | this.$promise = [this.cgBusy]; 62 | } 63 | } 64 | this.tracker.reset({ 65 | promises: this.$promise, 66 | delay: this.$options.delay || 0, 67 | minDuration: this.$options.minDuration || 0 68 | }); 69 | } 70 | 71 | ngOnDestroy(): void { 72 | this.tracker.destroy(); 73 | delete this.tracker; 74 | this.componentRef.destroy(); 75 | delete this.componentRef; 76 | this.$promise = []; 77 | this.fakePromise = undefined; 78 | this.fakePromiseResolve = undefined; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /projects/angular-busy2/src/lib/cgBusy.interface.ts: -------------------------------------------------------------------------------- 1 | import {TemplateRef} from '@angular/core'; 2 | 3 | export interface CgBusyOptions { 4 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 5 | templateRef?: TemplateRef; 6 | message?: string; 7 | wrapperClass?: string; 8 | backdrop?: boolean; 9 | delay?: number; 10 | minDuration?: number; 11 | } 12 | -------------------------------------------------------------------------------- /projects/angular-busy2/src/lib/cgBusy.module.ts: -------------------------------------------------------------------------------- 1 | import { ModuleWithProviders, NgModule } from '@angular/core'; 2 | import { CgBusyDirective } from './cgBusy.directive'; 3 | import { CgBusyOptions } from './cgBusy.interface'; 4 | import { BUSY_OPTIONS, CgBusyDefaults } from './cgBusyDefaults.service'; 5 | 6 | export function cgBusyDefaultsFactory(busyOptions?: CgBusyOptions): CgBusyDefaults { 7 | return new CgBusyDefaults(busyOptions); 8 | } 9 | 10 | @NgModule({ 11 | imports: [CgBusyDirective], 12 | exports: [CgBusyDirective] 13 | }) 14 | export class CgBusyModule { 15 | static forRoot(busyOptions?: CgBusyOptions): ModuleWithProviders { 16 | return { 17 | ngModule: CgBusyModule, 18 | providers: [ 19 | { 20 | provide: CgBusyDefaults, 21 | useFactory: cgBusyDefaultsFactory, 22 | deps: [BUSY_OPTIONS] 23 | }, 24 | { 25 | provide: BUSY_OPTIONS, 26 | useValue: busyOptions 27 | } 28 | ] 29 | }; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /projects/angular-busy2/src/lib/cgBusy.service.ts: -------------------------------------------------------------------------------- 1 | import {finalize, Observable, Subscription} from 'rxjs'; 2 | 3 | export interface TrackerOptions { 4 | minDuration: number; 5 | delay: number; 6 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 7 | promises: any[]; 8 | } 9 | 10 | export class CgBusyService { 11 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 12 | promises: any[]; 13 | subscriptions: Subscription[]; 14 | delayPromise: number; 15 | durationPromise: number; 16 | minDuration: number; 17 | detectChanges: () => void | null; 18 | 19 | constructor() { 20 | this.promises = []; 21 | this.subscriptions = []; 22 | } 23 | 24 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 25 | static isPromise(promiseThing: PromiseLike): boolean { 26 | return promiseThing && (promiseThing instanceof Promise || promiseThing instanceof Observable || promiseThing instanceof Subscription); 27 | } 28 | 29 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 30 | callThen(promiseThing: any, callback: () => void): void { 31 | if (promiseThing.finally) { 32 | promiseThing.finally(callback); 33 | } else if (promiseThing.then) { 34 | promiseThing.then(callback, callback); 35 | } else if (promiseThing instanceof Observable) { 36 | promiseThing.pipe(finalize(callback)); 37 | } else if (promiseThing instanceof Subscription) { 38 | promiseThing.add(callback); 39 | } else { 40 | throw new Error('cgBusy expects a Promise ,an Observable, a Subscription, a number or a boolean'); 41 | } 42 | } 43 | 44 | reset(options: TrackerOptions): void { 45 | this.minDuration = options.minDuration; 46 | 47 | this.promises = []; 48 | options.promises.forEach((p) => { 49 | if (!p || p.$cgBusyFulfilled) { 50 | return; 51 | } 52 | this.addPromiseLikeThing(p); 53 | }); 54 | 55 | if (this.promises.length === 0) { 56 | // if we have no promises then don't do the delay or duration stuff 57 | return; 58 | } 59 | 60 | if (options.delay) { 61 | this.delayPromise = window.setTimeout(() => { 62 | this.delayPromise = null; 63 | if (this.detectChanges) { 64 | this.detectChanges(); 65 | } 66 | this.createMinDuration(options); 67 | }, options.delay); 68 | } else { 69 | this.createMinDuration(options); 70 | } 71 | } 72 | 73 | createMinDuration(options: TrackerOptions): void { 74 | if (options.minDuration) { 75 | this.durationPromise = window.setTimeout(() => { 76 | this.durationPromise = null; 77 | if (this.detectChanges) { 78 | this.detectChanges(); 79 | } 80 | }, options.minDuration); 81 | } 82 | } 83 | 84 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 85 | addPromiseLikeThing(promise: any): void { 86 | 87 | if (!CgBusyService.isPromise(promise)) { 88 | throw new Error('cgBusy expects a Promise ,an Observable, a Subscription, a number or a boolean'); 89 | } 90 | 91 | if (this.promises.indexOf(promise) !== -1) { 92 | return; 93 | } 94 | this.promises.push(promise); 95 | 96 | this.callThen(promise, () => { 97 | promise.$cgBusyFulfilled = true; 98 | if (this.promises.indexOf(promise) === -1) { 99 | return; 100 | } 101 | this.promises.splice(this.promises.indexOf(promise), 1); 102 | if (this.delayPromise && this.promises.length === 0) { 103 | clearTimeout(this.delayPromise); 104 | this.delayPromise = null; 105 | } 106 | if (this.detectChanges) { 107 | this.detectChanges(); 108 | } 109 | }); 110 | } 111 | 112 | active(): boolean { 113 | return !this.delayPromise && (!!this.durationPromise || this.promises.length > 0); 114 | } 115 | 116 | destroy(): void { 117 | if (this.delayPromise) { 118 | clearTimeout(this.delayPromise); 119 | this.delayPromise = null; 120 | } 121 | if (this.durationPromise) { 122 | clearTimeout(this.durationPromise); 123 | this.durationPromise = null; 124 | } 125 | this.promises = []; 126 | this.detectChanges = null; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /projects/angular-busy2/src/lib/cgBusyDefaults.service.ts: -------------------------------------------------------------------------------- 1 | import {Inject, Injectable, InjectionToken, TemplateRef} from '@angular/core'; 2 | import type {CgBusyOptions} from './cgBusy.interface'; 3 | 4 | export const BUSY_OPTIONS = new InjectionToken('BUSY_OPTIONS'); 5 | 6 | @Injectable() 7 | export class CgBusyDefaults implements CgBusyOptions { 8 | delay: number; 9 | minDuration: number; 10 | backdrop: boolean; 11 | message: string; 12 | wrapperClass: string; 13 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 14 | templateRef: TemplateRef; 15 | 16 | constructor(@Inject(BUSY_OPTIONS) busyOptions?: CgBusyOptions) { 17 | 18 | if (!busyOptions) { 19 | busyOptions = {}; 20 | } 21 | 22 | this.delay = busyOptions.delay || 0; 23 | this.minDuration = busyOptions.minDuration || 0; 24 | this.backdrop = busyOptions.backdrop !== undefined ? busyOptions.backdrop : true; 25 | this.message = busyOptions.message || 'Please Wait...'; 26 | this.wrapperClass = busyOptions.wrapperClass || ''; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /projects/angular-busy2/src/public_api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of angular-busy2 3 | */ 4 | 5 | export type {CgBusyOptions} from './lib/cgBusy.interface'; 6 | export {CgBusyModule} from './lib/cgBusy.module'; 7 | export {CgBusyDefaults} from './lib/cgBusyDefaults.service'; 8 | export {CgBusyDirective} from './lib/cgBusy.directive'; 9 | -------------------------------------------------------------------------------- /projects/angular-busy2/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "../../tsconfig.json", 5 | "compilerOptions": { 6 | "outDir": "../../out-tsc/lib", 7 | "declarationMap": true, 8 | "module": "ES2022", 9 | "moduleResolution": "bundler", 10 | "declaration": true, 11 | "sourceMap": true, 12 | "inlineSources": true, 13 | "emitDecoratorMetadata": true, 14 | "experimentalDecorators": true, 15 | "importHelpers": true, 16 | "types": [] 17 | }, 18 | "exclude": [ 19 | "**/*.spec.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /projects/angular-busy2/tsconfig.lib.lint.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "./tsconfig.lib.json", 5 | "include": [ 6 | // adjust "includes" to what makes sense for you and your project 7 | "src/**/*.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /projects/angular-busy2/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "./tsconfig.lib.json", 5 | "compilerOptions": { 6 | "declarationMap": false 7 | }, 8 | "angularCompilerOptions": { 9 | "compilationMode": "partial" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/angular-busy2/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "../../tsconfig.json", 5 | "compilerOptions": { 6 | "outDir": "../../out-tsc/spec", 7 | "types": [ 8 | "jasmine" 9 | ] 10 | }, 11 | "include": [ 12 | "**/*.spec.ts", 13 | "**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- 1 | mat-grid-list { 2 | min-width: 400px; 3 | } 4 | 5 | .custom-template { 6 | background: url('../assets/finalfantasy.gif') no-repeat 50% 20px; 7 | width: 100%; 8 | height: 100%; 9 | position: absolute; 10 | } 11 | 12 | .custom-message { 13 | text-align: center; 14 | font-size: 26px; 15 | position: absolute; 16 | top: 100px; 17 | width: 100%; 18 | text-shadow: 1px 1px 2px white, -1px -1px 2px white, -4px 4px 4px white, -4px 4px 4px white; 19 | } 20 | 21 | .mat-select { 22 | margin-top: 25px; 23 | } 24 | 25 | .flex { 26 | flex: 1 auto; 27 | } 28 | 29 | .layout-column { 30 | display: flex; 31 | flex-direction: column; 32 | } 33 | 34 | .layout-row { 35 | display: flex; 36 | flex-direction: row; 37 | } 38 | 39 | @media (min-width: 1280px) { 40 | .layout-gt-md-row { 41 | display: flex; 42 | flex-direction: row; 43 | } 44 | } 45 | 46 | .layout-align-space-between { 47 | justify-content: space-between; 48 | } 49 | 50 | .layout-align-end-center { 51 | align-items: center; 52 | justify-content: flex-end; 53 | } 54 | 55 | :host { 56 | padding: 8px; 57 | width: 100%; 58 | height: 100%; 59 | display: flex; 60 | flex-direction: column; 61 | box-sizing: border-box; 62 | } 63 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

angular-busy2

4 |

Show busy/loading indicators on any Observable, Subscription, Promise, Boolean, Number

5 |
6 |
7 |
8 | 9 | 10 | Delay (ms) 11 | 12 | 13 | 14 | Min Duration (ms) 15 | 16 | 17 | 18 | Message 19 | 20 | 21 | Show Backdrop 22 | Show Custom Template 23 | 24 | Promise type 25 | 26 | @for (promiseType of promiseTypes; track promiseType) { 27 | {{promiseType.label}} 28 | } 29 | 30 | 31 |
32 | 35 |
36 |
37 | 38 |
39 | 41 | 42 | # 43 | 44 | 45 | First Name 46 | 47 | 48 | Last Name 49 | 50 | 51 | Username 52 | 53 | 54 |
1
55 |
56 | 57 |
Mark
58 |
59 | 60 |
Otto
61 |
62 | 63 |
@mdo
64 |
65 | 66 |
2
67 |
68 | 69 |
Mark
70 |
71 | 72 |
Otto
73 |
74 | 75 |
@TwBootstrap
76 |
77 | 78 |
3
79 |
80 | 81 |
Jacob
82 |
83 | 84 |
Thornton
85 |
86 | 87 |
@fat
88 |
89 | 90 |
4
91 |
92 | 93 |
Larry
94 |
95 | 96 |
the Bird
97 |
98 | 99 |
@twitter
100 |
101 |
102 |
103 |
104 |
105 | 106 |
107 |
108 |
109 |
110 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {HttpClient} from '@angular/common/http'; 2 | import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core'; 3 | import {FormsModule} from '@angular/forms'; 4 | import {MatButtonModule} from '@angular/material/button'; 5 | import {MatCheckboxModule} from '@angular/material/checkbox'; 6 | import {MatGridListModule} from '@angular/material/grid-list'; 7 | import {MatInputModule} from '@angular/material/input'; 8 | import {MatSelectModule} from '@angular/material/select'; 9 | import {CgBusyDirective} from 'angular-busy2'; 10 | import {Observable, Subscription} from 'rxjs'; 11 | 12 | @Component({ 13 | selector: 'app-cg-busy', 14 | templateUrl: './app.component.html', 15 | styleUrl: './app.component.css', 16 | changeDetection: ChangeDetectionStrategy.OnPush, 17 | imports: [ 18 | FormsModule, 19 | MatButtonModule, 20 | MatCheckboxModule, 21 | MatGridListModule, 22 | MatInputModule, 23 | MatSelectModule, 24 | CgBusyDirective 25 | ] 26 | }) 27 | export class AppComponent implements OnInit { 28 | delay: number; 29 | minDuration: number; 30 | message: string; 31 | backdrop: boolean; 32 | showCustomTemplate: boolean; 33 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 34 | promise: any; 35 | templateUrl: string; 36 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 37 | promiseTypes: {id: number, label: string, value: any}[]; 38 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 39 | promiseType: {id: number, label: string, value: any}; 40 | 41 | constructor(private http: HttpClient) { 42 | this.showCustomTemplate = false; 43 | } 44 | 45 | ngOnInit(): void { 46 | this.delay = 0; 47 | this.minDuration = 0; 48 | this.message = 'Please Wait...'; 49 | this.backdrop = true; 50 | this.promise = null; 51 | this.templateUrl = ''; 52 | 53 | this.promiseTypes = [ 54 | {id: 0, label: 'Promise', value: this.getHttp.bind(this)}, 55 | {id: 1, label: 'Observable', value: this.getHttpObserver.bind(this)}, 56 | {id: 1, label: 'Subscription', value: this.getHttpSubscription.bind(this)}, 57 | {id: 2, label: 'Number', value: 1}, 58 | {id: 3, label: 'Number `falsy`', value: 0}, 59 | {id: 4, label: 'Boolean', value: true}, 60 | {id: 5, label: 'Boolean false', value: false} 61 | ]; 62 | 63 | this.promiseType = this.promiseTypes[0]; 64 | } 65 | 66 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 67 | getHttp(): Promise { 68 | return this.http.get('https://httpbin.org/delay/3').toPromise(); 69 | } 70 | 71 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 72 | getHttpObserver(): Observable { 73 | return this.http.get('https://httpbin.org/delay/3'); 74 | } 75 | 76 | getHttpSubscription(): Subscription { 77 | return this.http.get('https://httpbin.org/delay/3').subscribe(() => { 78 | }); 79 | } 80 | 81 | demo(): void { 82 | if (typeof this.promiseType.value === 'function') { 83 | this.promise = this.promiseType.value(); 84 | } else { 85 | this.promise = this.promiseType.value; 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/app/app.config.ts: -------------------------------------------------------------------------------- 1 | import {provideHttpClient} from '@angular/common/http'; 2 | import {ApplicationConfig, importProvidersFrom, provideZoneChangeDetection} from '@angular/core'; 3 | import {provideAnimationsAsync} from '@angular/platform-browser/animations/async'; 4 | import {CgBusyModule} from 'angular-busy2'; 5 | 6 | export const appConfig: ApplicationConfig = { 7 | providers: [ 8 | provideZoneChangeDetection({ eventCoalescing: true }), 9 | provideAnimationsAsync(), 10 | provideHttpClient(), 11 | importProvidersFrom(CgBusyModule.forRoot()) 12 | ] 13 | }; 14 | -------------------------------------------------------------------------------- /src/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiberiuzuld/angular-busy/728a33a4885b3b501d43ca99c2549c18b185abd3/src/assets/favicon.ico -------------------------------------------------------------------------------- /src/assets/finalfantasy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tiberiuzuld/angular-busy/728a33a4885b3b501d43ca99c2549c18b185abd3/src/assets/finalfantasy.gif -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular Busy 2 6 | 7 | 8 | 9 | 13 | 14 | 15 |
16 |
17 | Star on GitHub 18 |
19 |
20 | Loading... 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import {bootstrapApplication} from '@angular/platform-browser'; 2 | import {AppComponent} from './app/app.component'; 3 | import {appConfig} from './app/app.config'; 4 | 5 | bootstrapApplication(AppComponent, appConfig).catch(err => console.log(err)); 6 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | html, body { 4 | height: 100vh; 5 | margin: 0; 6 | padding: 0; 7 | } 8 | 9 | body { 10 | display: flex; 11 | flex-direction: column; 12 | margin: 0; 13 | font-family: Roboto, 'Helvetica Neue', sans-serif; 14 | } 15 | 16 | /* Left will inherit from right (so we don't need to duplicate code) */ 17 | .github-fork-ribbon { 18 | /* The right and left classes determine the side we attach our banner to */ 19 | position: absolute; 20 | 21 | /* Add a bit of padding to give some substance outside the "stitching" */ 22 | padding: 2px 0; 23 | 24 | /* Set the base colour */ 25 | background-color: #a00; 26 | 27 | /* Set a gradient: transparent black at the top to almost-transparent black at the bottom */ 28 | background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.15))); 29 | background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 30 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 31 | background-image: -ms-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 32 | background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 33 | background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.15)); 34 | 35 | /* Add a drop shadow */ 36 | -webkit-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.5); 37 | -moz-box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.5); 38 | box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.5); 39 | 40 | z-index: 9999; 41 | pointer-events: auto; 42 | } 43 | 44 | .github-fork-ribbon a, 45 | .github-fork-ribbon a:hover { 46 | /* Set the font */ 47 | font: 700 13px "Helvetica Neue", Helvetica, Arial, sans-serif; 48 | color: #fff; 49 | 50 | /* Set the text properties */ 51 | text-decoration: none; 52 | text-shadow: 0 -1px rgba(0, 0, 0, 0.5); 53 | text-align: center; 54 | 55 | /* Set the geometry. If you fiddle with these you'll also need 56 | to tweak the top and right values in .github-fork-ribbon. */ 57 | width: 200px; 58 | line-height: 20px; 59 | 60 | /* Set the layout properties */ 61 | display: inline-block; 62 | padding: 2px 0; 63 | 64 | /* Add "stitching" effect */ 65 | border-width: 1px 0; 66 | border-style: dotted; 67 | border-color: #fff; 68 | border-color: rgba(255, 255, 255, 0.7); 69 | } 70 | 71 | .github-fork-ribbon-wrapper { 72 | width: 150px; 73 | height: 150px; 74 | position: absolute; 75 | overflow: hidden; 76 | top: 0; 77 | z-index: 9999; 78 | pointer-events: none; 79 | } 80 | 81 | .github-fork-ribbon-wrapper.fixed { 82 | position: fixed; 83 | } 84 | 85 | .github-fork-ribbon-wrapper.left { 86 | left: 0; 87 | } 88 | 89 | .github-fork-ribbon-wrapper.right { 90 | right: 0; 91 | } 92 | 93 | .github-fork-ribbon-wrapper.left-bottom { 94 | position: fixed; 95 | top: inherit; 96 | bottom: 0; 97 | left: 0; 98 | } 99 | 100 | .github-fork-ribbon-wrapper.right-bottom { 101 | position: fixed; 102 | top: inherit; 103 | bottom: 0; 104 | right: 0; 105 | } 106 | 107 | .github-fork-ribbon-wrapper.right .github-fork-ribbon { 108 | top: 42px; 109 | right: -43px; 110 | 111 | -webkit-transform: rotate(45deg); 112 | -moz-transform: rotate(45deg); 113 | -ms-transform: rotate(45deg); 114 | -o-transform: rotate(45deg); 115 | transform: rotate(45deg); 116 | } 117 | 118 | .github-fork-ribbon-wrapper.left .github-fork-ribbon { 119 | top: 42px; 120 | left: -43px; 121 | 122 | -webkit-transform: rotate(-45deg); 123 | -moz-transform: rotate(-45deg); 124 | -ms-transform: rotate(-45deg); 125 | -o-transform: rotate(-45deg); 126 | transform: rotate(-45deg); 127 | } 128 | 129 | .github-fork-ribbon-wrapper.left-bottom .github-fork-ribbon { 130 | top: 80px; 131 | left: -43px; 132 | 133 | -webkit-transform: rotate(45deg); 134 | -moz-transform: rotate(45deg); 135 | -ms-transform: rotate(45deg); 136 | -o-transform: rotate(45deg); 137 | transform: rotate(45deg); 138 | } 139 | 140 | .github-fork-ribbon-wrapper.right-bottom .github-fork-ribbon { 141 | top: 80px; 142 | right: -43px; 143 | 144 | -webkit-transform: rotate(-45deg); 145 | -moz-transform: rotate(-45deg); 146 | -ms-transform: rotate(-45deg); 147 | -o-transform: rotate(-45deg); 148 | transform: rotate(-45deg); 149 | } 150 | -------------------------------------------------------------------------------- /src/theme.scss: -------------------------------------------------------------------------------- 1 | @use '@angular/material' as mat; 2 | // Plus imports for other components in your app. 3 | 4 | // Define the theme object. 5 | $busy-app-theme: mat.define-theme( 6 | ( 7 | color: ( 8 | theme-type: light, 9 | primary: mat.$blue-palette 10 | ), 11 | density: ( 12 | scale: 0 13 | ) 14 | ) 15 | ); 16 | 17 | // Include the base styles for Angular Material core. We include this here so that you only 18 | // have to load a single css file for Angular Material in your app. 19 | @include mat.all-component-typographies(); 20 | @include mat.elevation-classes(); 21 | @include mat.app-background(); 22 | 23 | // Include theme styles for core and each component used in your app. 24 | // Alternatively, you can import and @include the theme mixins for each component 25 | // that you are using. 26 | :root { 27 | @include mat.all-component-themes($busy-app-theme); 28 | } 29 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "./tsconfig.json", 5 | "compilerOptions": { 6 | "outDir": "./out-tsc/app", 7 | "types": [] 8 | }, 9 | "files": [ 10 | "src/main.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "compileOnSave": false, 5 | "compilerOptions": { 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "noImplicitReturns": true, 9 | "noFallthroughCasesInSwitch": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "sourceMap": true, 13 | "declaration": false, 14 | "emitDecoratorMetadata": true, 15 | "experimentalDecorators": true, 16 | "moduleResolution": "bundler", 17 | "importHelpers": true, 18 | "target": "ES2022", 19 | "module": "ES2022", 20 | "paths": { 21 | "angular-busy2": [ 22 | "./dist/angular-busy2", 23 | "./projects/angular-busy2/src/public_api.ts" 24 | ] 25 | } 26 | }, 27 | "angularCompilerOptions": { 28 | "strictInjectionParameters": true, 29 | "strictInputAccessModifiers": true, 30 | "strictTemplates": true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "./tsconfig.app.json", 5 | "include": [ 6 | // adjust "includes" to what makes sense for you and your project 7 | "src/**/*.ts" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ 2 | /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ 3 | { 4 | "extends": "./tsconfig.json", 5 | "compilerOptions": { 6 | "outDir": "./out-tsc/spec", 7 | "types": [ 8 | "jasmine" 9 | ] 10 | }, 11 | "include": [ 12 | "src/**/*.spec.ts", 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | --------------------------------------------------------------------------------