├── .angular-cli.json ├── .codecov.yml ├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── e2e ├── app.e2e-spec.ts ├── app.po.ts └── tsconfig.e2e.json ├── karma.conf.js ├── package.json ├── protractor.conf.js ├── src ├── app │ ├── app-routing.module.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── autostart │ │ ├── autostart.component.html │ │ ├── autostart.component.scss │ │ ├── autostart.component.spec.ts │ │ └── autostart.component.ts │ ├── custom │ │ ├── custom.component.html │ │ ├── custom.component.scss │ │ ├── custom.component.spec.ts │ │ └── custom.component.ts │ ├── fork-me │ │ ├── fork-me.component.html │ │ ├── fork-me.component.scss │ │ ├── fork-me.component.spec.ts │ │ └── fork-me.component.ts │ ├── home │ │ ├── home.component.html │ │ ├── home.component.scss │ │ ├── home.component.spec.ts │ │ └── home.component.ts │ └── multi │ │ ├── multi.component.html │ │ ├── multi.component.scss │ │ ├── multi.component.spec.ts │ │ └── multi.component.ts ├── assets │ ├── .gitkeep │ └── banner.jpg ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── ngx-smart-loader │ ├── build.js │ ├── index.ts │ ├── karma.conf.js │ ├── license-banner.txt │ ├── package.json │ ├── public_api.ts │ ├── rollup.config.js │ ├── rollup.es.config.js │ ├── spec.bundle.js │ ├── src │ │ ├── components │ │ │ └── ngx-smart-loader.component.ts │ │ ├── modules │ │ │ └── ngx-smart-loader.module.ts │ │ ├── ngx-smart-loader.css │ │ ├── ngx-smart-loader.scss │ │ ├── ngx-smart-loader.ts │ │ └── services │ │ │ ├── loader-instance.ts │ │ │ └── ngx-smart-loader.service.ts │ ├── tests │ │ ├── components │ │ │ └── ngx-smart-loader.component.spec.ts │ │ └── services │ │ │ └── ngx-smart-loader.service.spec.ts │ ├── tsconfig-build.json │ ├── tsconfig.json │ ├── tslint.json │ └── yarn.lock ├── polyfills.ts ├── styles.scss ├── test.ts ├── tsconfig.app.json ├── tsconfig.spec.json └── typings.d.ts ├── tsconfig.json ├── tslint.json └── yarn.lock /.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "ngx-smart-loader" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "polyfills": "polyfills.ts", 17 | "test": "test.ts", 18 | "tsconfig": "tsconfig.app.json", 19 | "testTsconfig": "tsconfig.spec.json", 20 | "prefix": "app", 21 | "styles": [ 22 | "styles.scss" 23 | ], 24 | "scripts": [], 25 | "environmentSource": "environments/environment.ts", 26 | "environments": { 27 | "dev": "environments/environment.ts", 28 | "prod": "environments/environment.prod.ts" 29 | } 30 | } 31 | ], 32 | "e2e": { 33 | "protractor": { 34 | "config": "./protractor.conf.js" 35 | } 36 | }, 37 | "lint": [ 38 | { 39 | "project": "src/tsconfig.app.json", 40 | "exclude": "**/node_modules/**" 41 | }, 42 | { 43 | "project": "src/tsconfig.spec.json", 44 | "exclude": "**/node_modules/**" 45 | }, 46 | { 47 | "project": "e2e/tsconfig.e2e.json", 48 | "exclude": "**/node_modules/**" 49 | } 50 | ], 51 | "test": { 52 | "karma": { 53 | "config": "./karma.conf.js" 54 | } 55 | }, 56 | "defaults": { 57 | "styleExt": "scss", 58 | "component": {} 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: auto 6 | threshold: 10 7 | base: auto 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = stop 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | $ cat .gitignore 2 | **/node_modules 3 | **/dist 4 | **/documentation 5 | 6 | *.log 7 | *.tgz 8 | 9 | # See http://help.github.com/ignore-files/ for more about ignoring files. 10 | 11 | # compiled output 12 | /tmp 13 | /out-tsc 14 | 15 | # IDEs and editors 16 | /.idea 17 | .project 18 | .classpath 19 | .c9/ 20 | *.launch 21 | .settings/ 22 | *.sublime-workspace 23 | 24 | # IDE - VSCode 25 | .vscode/* 26 | !.vscode/settings.json 27 | !.vscode/tasks.json 28 | !.vscode/launch.json 29 | !.vscode/extensions.json 30 | 31 | # misc 32 | /.sass-cache 33 | /connect.lock 34 | **/coverage 35 | /libpeerconnection.log 36 | **/npm-debug.log 37 | testem.log 38 | **/typings 39 | 40 | # e2e 41 | /e2e/*.js 42 | /e2e/*.map 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | env: 4 | global: 5 | - CODACY_PROJECT_TOKEN=$CODACY_PROJECT_TOKEN 6 | addons: 7 | chrome: stable 8 | language: node_js 9 | node_js: 10 | - 11.10.0 11 | before_install: 12 | - echo "$TRAVIS_BRANCH" 13 | - echo "$TRAVIS_PULL_REQUEST" 14 | - npm i -g npm 15 | - npm i -g codecov 16 | - npm i -g codacy-coverage 17 | - npm i -g live-server@1 18 | - npm i -g node-gyp@3 19 | - cd src/ngx-smart-loader 20 | install: 21 | - npm install 22 | script: 23 | - npm run test 24 | - npm run build 25 | before_script: 26 | - export DISPLAY=:99.0 27 | - sh -e /etc/init.d/xvfb start 28 | - sleep 3 29 | after_success: 30 | - codecov -t $CODECOV_TOKEN 31 | - cat coverage/lcov.info | codacy-coverage 32 | - rm -r node_modules 33 | - cd ../.. 34 | - if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == false ]; then npm run ghpages; fi 35 | notifications: 36 | email: false 37 | deploy: 38 | provider: pages 39 | skip_cleanup: true 40 | local_dir: dist 41 | github_token: $PUSH_TOKEN 42 | on: 43 | branch: master 44 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # 2.0.0 (Feb 21, 2019) 3 | 4 | ### Bug Fixes 5 | * Fix the execution of loader methods in early Angular cycles such as ngOnInit (pull #12, fixes #8) 6 | 7 | ### Features 8 | * **BREAKING CHANGE**: remove the ability to declare several loaders with same identifier 9 | * **BREAKING CHANGE**: make `getLoader()` method private to avoid buggy cases (pull #12, fixes #10 #11) 10 | * Add new `onVisibleChange` event for any loader 11 | * Add a method to stop all runing loaders (pull #12, fixes #9) 12 | * Add a method to start all existing loaders 13 | 14 | ### Misc 15 | * Code refactoring 16 | * Code quality enhancements 17 | * Add more unit tests on the library service -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Maxime Lafarie 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 | ![ngx-smart-loader](src/assets/banner.jpg) 2 | 3 | [![Greenkeeper badge](https://badges.greenkeeper.io/maximelafarie/ngx-smart-loader.svg)](https://greenkeeper.io/) 4 | [![Build Status](https://travis-ci.org/maximelafarie/ngx-smart-loader.svg?branch=master)](https://travis-ci.org/maximelafarie/ngx-smart-loader) [![npm version](https://badge.fury.io/js/ngx-smart-loader.svg)](https://badge.fury.io/js/ngx-smart-loader) [![npm downloads](https://img.shields.io/npm/dm/ngx-smart-loader.svg)](https://npmjs.org/ngx-smart-loader) 5 | [![codecov](https://codecov.io/gh/maximelafarie/ngx-smart-loader/branch/master/graph/badge.svg)](https://codecov.io/gh/maximelafarie/ngx-smart-loader) 6 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/4106ddd7050148ad98c0843c9c6800f0)](https://www.codacy.com/app/maximelafarie/ngx-smart-loader?utm_source=github.com&utm_medium=referral&utm_content=maximelafarie/ngx-smart-loader&utm_campaign=Badge_Grade) 7 | 8 | `ngx-smart-loader` is a lightweight and very complete Angular component for managing loaders inside any Angular project. It was built for modern browsers using TypeScript, HTML5 and Angular >=2.0.0. 9 | 10 | ## Demo 11 | https://maximelafarie.com/ngx-smart-loader/ 12 | 13 | 14 | ## Powerful and so easy to use! 🤙 15 | Managing loaders has always been a big deal, mostly if you want to manage several loaders at the same time. With this library, it has never been so easy to do: a complete API to manage absolutely everything in your app. 16 | 17 | `ngx-smart-loader` also comes with a fancy default loader (demo default page's loader) in case you don't want to add your own. 18 | 19 | Check out the [documentation](https://maximelafarie.com/ngx-smart-loader) & [demos](https://maximelafarie.com/ngx-smart-loader/) for more information and tutorials! 20 | 21 | See the [changelog](https://maximelafarie.com/ngx-smart-loader/blob/master/src/ngx-smart-loader/CHANGELOG.md) for recent changes. 22 | 23 | ## Features 24 | - Handle large quantity of loaders anywhere in your app 25 | - Customize the style of your loaders through custom CSS classes 26 | - No external CSS library is used so you can easily add yours 27 | - Manipulate groups of loader at the same time 28 | - Events on `start` and `stop` for each loader 29 | - Manage all your loaders stack with very fast methods 30 | - Very smart `z-index` computation 31 | - Check for loader(s) activity 32 | - AoT compilation support 33 | 34 | ## Setup 35 | To use `ngx-smart-loader` in your project install it via [npm](https://www.npmjs.com/package/ngx-smart-loader): 36 | ``` 37 | npm i ngx-smart-loader --save 38 | ``` 39 | or 40 | ``` 41 | yarn add ngx-smart-loader 42 | ``` 43 | 44 | Then add `NgxSmartLoaderModule` (with `.forRoot()` or `.forChild()` depending if the module which you import the library into is the main module of your project or a nested module) and `NgxSmartLoaderService` to your project's `NgModule` 45 | ```js 46 | import { BrowserModule } from '@angular/platform-browser'; 47 | import { NgModule } from '@angular/core'; 48 | import { NgxSmartLoaderModule, NgxSmartLoaderService } from 'ngx-smart-loader'; 49 | 50 | import { AppComponent } from './app.component'; 51 | 52 | @NgModule({ 53 | declarations: [ 54 | AppComponent 55 | ], 56 | imports: [ 57 | BrowserModule, 58 | NgxSmartLoaderModule.forRoot() 59 | ], 60 | providers: [ NgxSmartLoaderService ], 61 | bootstrap: [ AppComponent ] 62 | }) 63 | export class AppModule { } 64 | ``` 65 | 66 | And import `ngx-smart-loader.scss` or `ngx-smart-loader.css` in a global style file (e.g. `styles.scss` or `styles.css` in classic Angular projects or any other scss/css file it imports): 67 | Example with **styles.scss**: 68 | ```css 69 | /* You can add global styles to this file, and also import other style files */ 70 | @import "~ngx-smart-loader/ngx-smart-loader"; 71 | @import "app/app.component"; 72 | ... 73 | ``` 74 | 75 | ## Parameters / Options 76 | `ngx-smart-loader` comes with some parameters / options in order to make it fit your needs. The following parameters / options needs to be used like this: `` 77 | 78 | The below documentation will use the following pattern: 79 | > `parameter/option name` (type) | default value | required? ― _description_ 80 | 81 | - `identifier` (string) | `undefined` | **REQUIRED** ― _The identifiant of the loader instance. Retrieve a loader easily by its identifier._ 82 | 83 | - `force` (boolean) | false ― _If true and if you declare another loader instance with the same identifier that another, the service will override it by the new you declare in the loader stack. By default, it allows you to declare multiple loaders with same identifier in order to manipulate them at once._ 84 | 85 | - `customClass` (string) | `''` ― _All the additional classes you want to add to the loader (e.g.: for your custom loaders). You can add several classes by giving a string with space-separated classnames_ 86 | 87 | - `delayIn` (number) | `0` ― _In milliseconds. Define the time after which you want to display your loader. The `.active` class only append to loader after this time. The `.enter` class append to the loader instantly and disappears after this delay._ 88 | 89 | - `delayOut` (number) | `0` ― _In milliseconds. Define the time after which you want to hide your loader. The `.active` class only disappears from the loader after this time. The `.leave` class append to the loader instantly and disappears after this delay._ 90 | 91 | ## Manipulate loaders 92 | First, you need to add a loader to any template at any level in your app (all examples will use the default library built-in loader). 93 | ```html 94 | 95 |
96 |
97 |
98 |
99 | ``` 100 | At this point, the loader instance is stored in the `NgxSmartLoaderService`. You can do absolutely what you want with it, anywhere in your app. For example, from a component (here we're starting the loader automatically after one second): 101 | ```js 102 | import { Component, OnInit } from '@angular/core'; 103 | 104 | import { NgxSmartLoaderService } from 'ngx-smart-loader'; 105 | 106 | @Component({ 107 | ... 108 | }) 109 | export class HomeComponent implements OnInit { 110 | 111 | constructor(public loader: NgxSmartLoaderService) { 112 | } 113 | 114 | ngOnInit() { 115 | this.loader.start('myLoader'); 116 | } 117 | } 118 | ``` 119 | 120 | ## Http calls 121 | Following the same example as above, you can use the `NgxSmartLoaderService` to start a loader. Here's a more concrete example: 122 | 123 | Let's imagine you have a function that makes an Http request to retrieve a user list (this example uses the [rxjs Observable](https://github.com/ReactiveX/rxjs/blob/master/doc/observable.md). This is an example, you need to adapt it to your needs): 124 | ```js 125 | public users: User[] = []; 126 | 127 | getUsers (): User[] { 128 | this.loader.start('myLoader'); 129 | return this.http.get('api/v2/users') 130 | .subscribe( 131 | users => this.users = users, 132 | err => console.error('something wrong occurred: ' + err), 133 | () => this.loader.stop('myLoader'); 134 | ); 135 | } 136 | ``` 137 | As you can see above, we're starting the loader before Http request. Then in the `subscribe()` we're stopping when the request finished. 138 | 139 | ## Handle events 140 | `ngx-smart-loader` comes with built-in events: `onStart`, `onStop` and `onVisibleChange`. 141 | 142 | - `onStart`: loader has been opened 143 | - `onStop`: loader has been closed 144 | - `onVisibleChange`: loader has been opened or closed 145 | 146 | You can handle events directly from the view... 147 | ```html 148 | 149 |
150 |
151 |
152 |
153 | ``` 154 | ...and execute component functions: 155 | ```js 156 | @Component({ 157 | ... 158 | }) 159 | export class AppComponent { 160 | constructor() { 161 | } 162 | 163 | public onStart(event) { 164 | } 165 | 166 | public onStop(event) { 167 | } 168 | 169 | public onVisibleChange(event) { 170 | } 171 | } 172 | ``` 173 | 174 | ## Contribute 175 | Firstly fork this repo, then clone it and go inside the root of the freshly forked project. 176 | `ng serve` to start the angular-cli demo. 177 | To modify the package, go into `./src/ngx-smart-loader` and do some code! 🤓 178 | When you finished commit and push it to your fork repo, make a PR! 179 | Thank you for your support, you rock! 🤘🎸 180 | 181 | -------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('ngx-smart-loader App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('Welcome to app!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular/cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | angularCli: { 23 | environment: 'dev' 24 | }, 25 | reporters: ['progress', 'kjhtml'], 26 | port: 9876, 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: true, 30 | browsers: ['Chrome'], 31 | singleRun: false 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-smart-loader-demo", 3 | "description": "Angular-CLI demo of ngx-smart-loader", 4 | "version": "1.0.0", 5 | "license": "MIT", 6 | "scripts": { 7 | "ng": "ng", 8 | "start": "ng serve", 9 | "build": "ng build", 10 | "test": "ng test", 11 | "lint": "ng lint", 12 | "e2e": "ng e2e", 13 | "ghpages": "yarn && ng build --prod --aot --no-progress --baseHref='/ngx-smart-loader/'" 14 | }, 15 | "private": true, 16 | "dependencies": { 17 | "@angular/animations": "^5.0.0", 18 | "@angular/common": "^5.0.0", 19 | "@angular/compiler": "^5.0.0", 20 | "@angular/core": "^5.0.0", 21 | "@angular/forms": "^5.0.0", 22 | "@angular/http": "^5.0.0", 23 | "@angular/platform-browser": "^5.0.0", 24 | "@angular/platform-browser-dynamic": "^5.0.0", 25 | "@angular/router": "^5.0.0", 26 | "core-js": "^2.4.1", 27 | "rxjs": "^5.5.2", 28 | "zone.js": "^0.8.14" 29 | }, 30 | "devDependencies": { 31 | "@angular/cli": "1.5.0", 32 | "@angular/compiler-cli": "^5.0.0", 33 | "@angular/language-service": "^5.0.0", 34 | "@types/jasmine": "~2.5.53", 35 | "@types/jasminewd2": "~2.0.2", 36 | "@types/node": "~6.0.60", 37 | "codelyzer": "~3.2.0", 38 | "jasmine-core": "~2.6.2", 39 | "jasmine-spec-reporter": "~4.1.0", 40 | "karma": "~1.7.0", 41 | "karma-chrome-launcher": "~2.1.1", 42 | "karma-cli": "~1.0.1", 43 | "karma-coverage-istanbul-reporter": "^1.2.1", 44 | "karma-jasmine": "~1.1.0", 45 | "karma-jasmine-html-reporter": "^0.2.2", 46 | "node-sass": "^4.11.0", 47 | "protractor": "~5.1.2", 48 | "ts-node": "~3.2.0", 49 | "tslint": "~5.7.0", 50 | "typescript": "~2.4.2" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | import { HomeComponent } from './home/home.component'; 5 | import { MultiComponent } from './multi/multi.component'; 6 | import { CustomComponent } from './custom/custom.component'; 7 | import { AutostartComponent } from './autostart/autostart.component'; 8 | 9 | const routes: Routes = [ 10 | { pathMatch: 'full', path: '', redirectTo: 'default' }, 11 | { path: 'default', component: HomeComponent }, 12 | { path: 'multi', component: MultiComponent }, 13 | { path: 'custom', component: CustomComponent }, 14 | { path: 'autostart', component: AutostartComponent }, 15 | { pathMatch: 'full', path: '**', redirectTo: 'default' }, 16 | ]; 17 | 18 | @NgModule({ 19 | imports: [RouterModule.forRoot(routes, { useHash: true })], 20 | exports: [RouterModule] 21 | }) 22 | export class AppRoutingModule { 23 | } 24 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

ngx-smart-loader

4 | 5 | 17 |
18 | 19 | 20 | 21 |
22 | 25 | 36 | 37 | 39 | 40 | 42 | 43 | 45 | 46 | 48 | 49 | 50 | 52 | 53 | 55 | 56 | 58 | 59 | 61 | 62 | 64 | 65 | 67 | 68 | 69 | 70 | 71 |
72 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | .ml-watermark { 2 | position: absolute; 3 | right: 6px; 4 | bottom: 0; 5 | z-index: 3; 6 | 7 | #ml-link { 8 | display: block; 9 | opacity: .5; 10 | 11 | &:hover, 12 | &:focus, 13 | &:active { 14 | opacity: 1; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | imports: [ 8 | RouterTestingModule 9 | ], 10 | declarations: [ 11 | AppComponent 12 | ], 13 | }).compileComponents(); 14 | })); 15 | it('should create the app', async(() => { 16 | const fixture = TestBed.createComponent(AppComponent); 17 | const app = fixture.debugElement.componentInstance; 18 | expect(app).toBeTruthy(); 19 | })); 20 | it(`should have as title 'app'`, async(() => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app.title).toEqual('app'); 24 | })); 25 | it('should render title in a h1 tag', async(() => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); 30 | })); 31 | }); 32 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | } 10 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { CommonModule } from '@angular/common'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { NgModule } from '@angular/core'; 5 | 6 | import { AppRoutingModule } from './app-routing.module'; 7 | 8 | import { NgxSmartLoaderModule } from '../ngx-smart-loader'; 9 | 10 | import { AppComponent } from './app.component'; 11 | import { HomeComponent } from './home/home.component'; 12 | import { MultiComponent } from './multi/multi.component'; 13 | import { CustomComponent } from './custom/custom.component'; 14 | import { AutostartComponent } from './autostart/autostart.component'; 15 | import { ForkMeComponent } from './fork-me/fork-me.component'; 16 | 17 | @NgModule({ 18 | declarations: [ 19 | AppComponent, 20 | HomeComponent, 21 | MultiComponent, 22 | CustomComponent, 23 | AutostartComponent, 24 | ForkMeComponent 25 | ], 26 | imports: [ 27 | BrowserModule, 28 | CommonModule, 29 | FormsModule, 30 | AppRoutingModule, 31 | NgxSmartLoaderModule.forRoot() 32 | ], 33 | bootstrap: [AppComponent] 34 | }) 35 | export class AppModule { } 36 | -------------------------------------------------------------------------------- /src/app/autostart/autostart.component.html: -------------------------------------------------------------------------------- 1 | 3 |
4 |
5 |
6 |
7 | -------------------------------------------------------------------------------- /src/app/autostart/autostart.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximelafarie/ngx-smart-loader/6d6613101e58b9b6890f5fe974886d8900fa152c/src/app/autostart/autostart.component.scss -------------------------------------------------------------------------------- /src/app/autostart/autostart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AutostartComponent } from './autostart.component'; 4 | 5 | describe('AutostartComponent', () => { 6 | let component: AutostartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AutostartComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AutostartComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/autostart/autostart.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-autostart', 5 | templateUrl: './autostart.component.html', 6 | styleUrls: ['./autostart.component.scss'] 7 | }) 8 | export class AutostartComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/custom/custom.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Loading ? : 3 | {{ loader.isLoading(['myCustomLoader1', 'myCustomLoader2', 'myCustomLoader3']) ? 'Yes!' : 'Nope.' }} 4 |

5 |
6 |
7 |
8 | 13 |
14 |
15 |
16 | 17 |
18 | 20 |
21 |
22 |
23 |
24 |
25 |
26 | 27 |
28 | 30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 | 47 |
48 |

Redirecting

49 |
50 |
51 |
52 | 53 | 54 |
55 |
56 |
57 |
58 |         {{ code.one }}
59 |       
60 |
61 |
62 | 63 |
64 |
65 |
66 |         {{ code.two }}
67 |       
68 |
69 |
70 | 71 |
72 |
73 |
74 |         {{ code.three }}
75 |       
76 |
77 |
78 |
79 | 80 |
81 | 84 | 87 |
88 | -------------------------------------------------------------------------------- /src/app/custom/custom.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximelafarie/ngx-smart-loader/6d6613101e58b9b6890f5fe974886d8900fa152c/src/app/custom/custom.component.scss -------------------------------------------------------------------------------- /src/app/custom/custom.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CustomComponent } from './custom.component'; 4 | 5 | describe('CustomComponent', () => { 6 | let component: CustomComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CustomComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CustomComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/custom/custom.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { NgxSmartLoaderService } from '../../ngx-smart-loader/src/ngx-smart-loader'; 3 | 4 | @Component({ 5 | selector: 'app-custom', 6 | templateUrl: './custom.component.html', 7 | styleUrls: ['./custom.component.scss'] 8 | }) 9 | export class CustomComponent implements OnInit { 10 | 11 | public code = { 12 | one: null, 13 | two: null, 14 | three: null 15 | }; 16 | 17 | constructor(public loader: NgxSmartLoaderService) { 18 | 19 | this.code.one = ` 20 | 21 |
22 |
`; 23 | 24 | this.code.two = ` 25 | 26 |
27 |
28 |
29 |
30 |
`; 31 | 32 | this.code.three = ` 33 | 34 | ... 35 | `; 36 | 37 | } 38 | 39 | ngOnInit() { 40 | } 41 | 42 | onStart(event) { 43 | console.log('loader started', event); 44 | } 45 | 46 | onStop(event) { 47 | console.log('loader stopped', event); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/app/fork-me/fork-me.component.html: -------------------------------------------------------------------------------- 1 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /src/app/fork-me/fork-me.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | .github-corner:hover .octo-arm { 3 | animation: octocat-wave 560ms ease-in-out 4 | } 5 | 6 | @keyframes octocat-wave { 7 | 0%, 100% { 8 | transform: rotate(0) 9 | } 10 | 20%, 60% { 11 | transform: rotate(-25deg) 12 | } 13 | 40%, 80% { 14 | transform: rotate(10deg) 15 | } 16 | } 17 | 18 | @media (max-width: 500px) { 19 | .github-corner:hover .octo-arm { 20 | animation: none 21 | } 22 | 23 | .github-corner .octo-arm { 24 | animation: octocat-wave 560ms ease-in-out 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/fork-me/fork-me.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ForkMeComponent } from './fork-me.component'; 4 | 5 | describe('ForkMeComponent', () => { 6 | let component: ForkMeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ForkMeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ForkMeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/fork-me/fork-me.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-fork-me', 5 | templateUrl: './fork-me.component.html', 6 | styleUrls: ['./fork-me.component.scss'] 7 | }) 8 | export class ForkMeComponent implements OnInit { 9 | 10 | constructor() { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Loading ? : {{ loader.isLoading('myLoader') ? 'Yes!' : 'Nope.' }}

3 |
4 | 5 | 9 |
10 |
11 |
12 |
13 | 14 |
15 | 16 |
17 | 18 | 25 | 26 | 27 | 28 | 37 | 38 | 39 |
40 | 41 | 44 | 47 |
48 | -------------------------------------------------------------------------------- /src/app/home/home.component.scss: -------------------------------------------------------------------------------- 1 | .row { 2 | max-width: 800px; 3 | margin: 0 auto; 4 | padding: 60px 30px 0; 5 | text-align: center; 6 | 7 | span { 8 | position: relative; 9 | display: inline-block; 10 | margin: 30px 10px; 11 | } 12 | } 13 | 14 | .balloon { 15 | // As suggested by https://twitter.com/dbox/status/365888496486985728 16 | display: inline-block; 17 | width: 215px; 18 | padding: 10px 0; 19 | text-align: right; 20 | font-weight: 400; 21 | font-size: .8rem; 22 | color: #536dfe; 23 | background: #fff; 24 | border: 0; 25 | border-radius: 3px; 26 | outline: 0; 27 | text-indent: 60px; // Arbitrary. 28 | transition: all .3s ease-in-out; 29 | 30 | &::-webkit-input-placeholder { 31 | color: #efefef; 32 | text-indent: 0; 33 | font-weight: 300; 34 | } 35 | 36 | & + label { 37 | display: inline-block; 38 | position: absolute; 39 | top: 8px; 40 | left: 0; 41 | bottom: 8px; 42 | padding: 3px 15px; 43 | color: #536dfe; 44 | font-size: 11px; 45 | font-weight: 700; 46 | text-transform: uppercase; 47 | text-shadow: 0 1px 0 rgba(19, 74, 70, 0); 48 | transition: all .3s ease-in-out; 49 | border-radius: 3px; 50 | background: #fff; 51 | 52 | &:after { 53 | position: absolute; 54 | content: ""; 55 | width: 0; 56 | height: 0; 57 | top: 100%; 58 | left: 50%; 59 | margin-left: -3px; 60 | border-left: 3px solid transparent; 61 | border-right: 3px solid transparent; 62 | border-top: 3px solid rgba(122, 184, 147, 0); 63 | transition: all .3s ease-in-out; 64 | } 65 | } 66 | 67 | &.disabled { 68 | opacity: .4; 69 | 70 | & + label { 71 | background-color: transparent; 72 | } 73 | } 74 | } 75 | 76 | .balloon:focus { 77 | color: #536dfe; 78 | text-indent: 0; 79 | background: #fff; 80 | 81 | &::-webkit-input-placeholder { 82 | color: #aaa; 83 | } 84 | & + label { 85 | color: #536dfe; 86 | // text-shadow: 0 1px 0 rgba(19, 74, 70, .4); 87 | background: #fff; 88 | transform: translateY(-40px); 89 | 90 | &:after { 91 | border-top: 4px solid #fafafa; 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HomeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { NgxSmartLoaderService } from '../../ngx-smart-loader/src/ngx-smart-loader'; 3 | 4 | @Component({ 5 | selector: 'app-home', 6 | templateUrl: './home.component.html', 7 | styleUrls: ['./home.component.scss'] 8 | }) 9 | export class HomeComponent implements OnInit { 10 | public demoOptions = { 11 | actionDelay: 0, 12 | hideDelay: 200, 13 | noHideDelay: false 14 | }; 15 | 16 | constructor(public loader: NgxSmartLoaderService) { 17 | } 18 | 19 | ngOnInit(): void { 20 | this.loader.start('myLoader'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/app/multi/multi.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | Loading ? : {{ loader.isLoading(['myLoaderMulti1', 'myLoaderMulti2', 'myLoaderMulti3']) ? 'Yes!' : 'Nope.' }} 4 |

5 |
6 | 7 |
8 |
9 |

Loading ? : {{ loader.isLoading('myLoaderMulti1') ? 'Yes!' : 'Nope.' }}

10 | 11 |
12 |
13 |
14 |
15 |
16 | 17 |
18 |

Loading ? : {{ loader.isLoading('myLoaderMulti2') ? 'Yes!' : 'Nope.' }}

19 | 20 |
21 |
22 |
23 |
24 |
25 | 26 |
27 |

Loading ? : {{ loader.isLoading('myLoaderMulti3') ? 'Yes!' : 'Nope.' }}

28 | 29 |
30 |
31 |
32 |
33 |
34 |
35 | 36 |
37 |
38 |
39 |
40 |         {{ code.one }}
41 |       
42 |
43 |
44 | 45 |
46 |
47 |
48 |         {{ code.two }}
49 |       
50 |
51 |
52 | 53 |
54 |
55 |
56 |         {{ code.three }}
57 |       
58 |
59 |
60 |
61 | 62 |
63 | 66 | 69 |
70 | -------------------------------------------------------------------------------- /src/app/multi/multi.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximelafarie/ngx-smart-loader/6d6613101e58b9b6890f5fe974886d8900fa152c/src/app/multi/multi.component.scss -------------------------------------------------------------------------------- /src/app/multi/multi.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MultiComponent } from './multi.component'; 4 | 5 | describe('MultiComponent', () => { 6 | let component: MultiComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ MultiComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MultiComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/multi/multi.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { NgxSmartLoaderService } from '../../ngx-smart-loader/src/ngx-smart-loader'; 3 | 4 | @Component({ 5 | selector: 'app-multi', 6 | templateUrl: './multi.component.html', 7 | styleUrls: ['./multi.component.scss'] 8 | }) 9 | export class MultiComponent { 10 | 11 | public code = { 12 | one: null, 13 | two: null, 14 | three: null 15 | }; 16 | 17 | constructor(public loader: NgxSmartLoaderService) { 18 | 19 | this.code.one = ` 20 | 21 |
22 |
23 |
24 |
`; 25 | 26 | this.code.two = ` 27 | 28 |
29 |
30 |
31 |
`; 32 | 33 | this.code.three = ` 34 | 35 |
36 |
37 |
38 |
`; 39 | 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximelafarie/ngx-smart-loader/6d6613101e58b9b6890f5fe974886d8900fa152c/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximelafarie/ngx-smart-loader/6d6613101e58b9b6890f5fe974886d8900fa152c/src/assets/banner.jpg -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximelafarie/ngx-smart-loader/6d6613101e58b9b6890f5fe974886d8900fa152c/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NgxSmartLoader Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/build.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const shell = require('shelljs'); 4 | const chalk = require('chalk'); 5 | 6 | const PACKAGE = `ngx-smart-loader`; 7 | const NPM_DIR = `dist`; 8 | const ESM2015_DIR = `${NPM_DIR}/esm2015`; 9 | const ESM5_DIR = `${NPM_DIR}/esm5`; 10 | const BUNDLES_DIR = `${NPM_DIR}/bundles`; 11 | const OUT_DIR_ESM5 = `${NPM_DIR}/package/esm5`; 12 | 13 | shell.echo(`Start building...`); 14 | 15 | shell.rm(`-Rf`, `${NPM_DIR}/*`); 16 | shell.mkdir(`-p`, `./${ESM2015_DIR}`); 17 | shell.mkdir(`-p`, `./${ESM5_DIR}`); 18 | shell.mkdir(`-p`, `./${BUNDLES_DIR}`); 19 | shell.echo(shell.pwd()); 20 | shell.cp('-R', 'src/ngx-smart-loader.scss', `${NPM_DIR}/`); 21 | shell.cp('-R', 'src/ngx-smart-loader.css', `${NPM_DIR}/`); 22 | 23 | /* TSLint with Codelyzer */ 24 | // https://github.com/palantir/tslint/blob/master/src/configs/recommended.ts 25 | // https://github.com/mgechev/codelyzer 26 | shell.echo(`Start TSLint`); 27 | shell.exec(`tslint -c tslint.json -t stylish src/**/*.ts`); 28 | shell.echo(chalk.green(`TSLint completed`)); 29 | 30 | /* AoT compilation */ 31 | shell.echo(`Start AoT compilation`); 32 | if (shell.exec(`ngc -p tsconfig-build.json`).code !== 0) { 33 | shell.echo(chalk.red(`Error: AoT compilation failed`)); 34 | shell.exit(1); 35 | } 36 | shell.echo(chalk.green(`AoT compilation completed`)); 37 | 38 | /* BUNDLING PACKAGE */ 39 | shell.echo(`Start bundling`); 40 | shell.echo(`Rollup package`); 41 | if (shell.exec(`rollup -c rollup.es.config.js -i ${NPM_DIR}/${PACKAGE}.js -o ${ESM2015_DIR}/${PACKAGE}.js`).code !== 0) { 42 | shell.echo(chalk.red(`Error: Rollup package failed`)); 43 | shell.exit(1); 44 | } 45 | 46 | shell.echo(`Produce ESM5 version`); 47 | shell.exec(`ngc -p tsconfig-build.json --target es5 -d false --outDir ${OUT_DIR_ESM5} --importHelpers true --sourceMap`); 48 | if (shell.exec(`rollup -c rollup.es.config.js -i ${OUT_DIR_ESM5}/${PACKAGE}.js -o ${ESM5_DIR}/${PACKAGE}.js`).code !== 0) { 49 | shell.echo(chalk.red(`Error: ESM5 version failed`)); 50 | shell.exit(1); 51 | } 52 | 53 | shell.echo(`Run Rollup conversion on package`); 54 | if (shell.exec(`rollup -c rollup.config.js -i ${ESM5_DIR}/${PACKAGE}.js -o ${BUNDLES_DIR}/${PACKAGE}.umd.js`).code !== 0) { 55 | shell.echo(chalk.red(`Error: Rollup conversion failed`)); 56 | shell.exit(1); 57 | } 58 | 59 | shell.echo(`Minifying`); 60 | shell.cd(`${BUNDLES_DIR}`); 61 | shell.exec(`uglifyjs ${PACKAGE}.umd.js -c --comments -o ${PACKAGE}.umd.min.js --source-map "filename='${PACKAGE}.umd.min.js.map', includeSources"`); 62 | shell.cd(`..`); 63 | shell.cd(`..`); 64 | 65 | shell.echo(chalk.green(`Bundling completed`)); 66 | 67 | shell.rm(`-Rf`, `${NPM_DIR}/package`); 68 | shell.rm(`-Rf`, `${NPM_DIR}/node_modules`); 69 | shell.rm(`-Rf`, `${NPM_DIR}/*.js`); 70 | shell.rm(`-Rf`, `${NPM_DIR}/*.js.map`); 71 | shell.rm(`-Rf`, `${NPM_DIR}/src/**/*.js`); 72 | shell.rm(`-Rf`, `${NPM_DIR}/src/**/*.js.map`); 73 | 74 | shell.cp(`-Rf`, [`package.json`, `../../LICENSE`, `../../README.md`], `${NPM_DIR}`); 75 | 76 | shell.echo(chalk.green(`End building`)); 77 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public_api'; 2 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration for Unit testing 2 | 3 | const path = require('path'); 4 | 5 | module.exports = function (config) { 6 | 7 | const configuration = { 8 | 9 | // base path that will be used to resolve all patterns (eg. files, exclude) 10 | basePath: '', 11 | 12 | // frameworks to use 13 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 14 | frameworks: ['jasmine'], 15 | 16 | plugins: [ 17 | require('karma-jasmine'), 18 | require('karma-chrome-launcher'), 19 | require('karma-webpack'), 20 | require('karma-sourcemap-loader'), 21 | require('karma-spec-reporter'), 22 | require('karma-coverage-istanbul-reporter'), 23 | require("istanbul-instrumenter-loader") 24 | ], 25 | 26 | // list of files / patterns to load in the browser 27 | files: [ 28 | { pattern: 'spec.bundle.js', watched: false } 29 | ], 30 | 31 | // list of files to exclude 32 | exclude: [ 33 | ], 34 | 35 | // preprocess matching files before serving them to the browser 36 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 37 | preprocessors: { 38 | 'spec.bundle.js': ['webpack', 'sourcemap'] 39 | }, 40 | 41 | // webpack 42 | webpack: { 43 | resolve: { 44 | extensions: ['.ts', '.js'] 45 | }, 46 | module: { 47 | rules: [ 48 | { 49 | test: /\.ts/, 50 | use: [ 51 | { loader: 'ts-loader' }, 52 | { loader: 'source-map-loader' } 53 | ], 54 | exclude: /node_modules/ 55 | }, 56 | { 57 | enforce: 'post', 58 | test: /\.ts/, 59 | use: [ 60 | { 61 | loader: 'istanbul-instrumenter-loader', 62 | options: { esModules: true } 63 | } 64 | ], 65 | exclude: [ 66 | /\.spec.ts/, 67 | /node_modules/ 68 | ] 69 | } 70 | ], 71 | exprContextCritical: false 72 | }, 73 | devtool: 'inline-source-map', 74 | performance: { hints: false } 75 | }, 76 | 77 | webpackServer: { 78 | noInfo: true 79 | }, 80 | 81 | 82 | // test results reporter to use 83 | // possible values: 'dots', 'progress' 84 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 85 | reporters: ['spec', 'coverage-istanbul'], 86 | 87 | coverageIstanbulReporter: { 88 | reports: ['html', 'lcovonly'], 89 | dir: path.join(__dirname, 'coverage'), 90 | fixWebpackSourcePaths: true 91 | }, 92 | 93 | 94 | // web server port 95 | port: 9876, 96 | 97 | 98 | // enable / disable colors in the output (reporters and logs) 99 | colors: true, 100 | 101 | 102 | // level of logging 103 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 104 | logLevel: config.LOG_INFO, 105 | 106 | 107 | // enable / disable watching file and executing tests whenever any file changes 108 | autoWatch: true, 109 | 110 | 111 | // start these browsers 112 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 113 | browsers: ['Chrome'], 114 | 115 | 116 | // Continuous Integration mode 117 | // if true, Karma captures browsers, runs the tests and exits 118 | singleRun: true 119 | 120 | }; 121 | 122 | config.set(configuration); 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/license-banner.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license ngx-smart-loader 3 | * MIT license 4 | */ 5 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx-smart-loader", 3 | "version": "2.0.0", 4 | "description": "Smart loader handler to manage loaders everywhere in Angular apps.", 5 | "main": "./bundles/ngx-smart-loader.umd.js", 6 | "module": "./esm5/ngx-smart-loader.js", 7 | "es2015": "./esm2015/ngx-smart-loader.js", 8 | "scripts": { 9 | "build": "node build.js", 10 | "test": "karma start --coverage", 11 | "pack-lib": "npm pack ./dist", 12 | "publish-lib": "npm publish ./dist", 13 | "publish-lib:next": "npm publish --tag next ./dist", 14 | "compodoc": "compodoc -p tsconfig.json", 15 | "compodoc-serve": "compodoc -s", 16 | "lint": "tslint -c tslint.json -t stylish src/**/*.ts" 17 | }, 18 | "typings": "./ngx-smart-loader.d.ts", 19 | "author": "Maxime LAFARIE ", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://maximelafarie.com/ngx-smart-loader.git" 23 | }, 24 | "bugs": { 25 | "url": "https://maximelafarie.com/ngx-smart-loader/issues" 26 | }, 27 | "homepage": "https://maximelafarie.com/ngx-smart-loader", 28 | "keywords": [ 29 | "ngx-smart-loader", 30 | "smart", 31 | "loader", 32 | "load", 33 | "loading", 34 | "typescript", 35 | "angular", 36 | "angular2", 37 | "angular4", 38 | "angular5", 39 | "ngx" 40 | ], 41 | "license": "MIT", 42 | "peerDependencies": { 43 | "@angular/common": ">= 5.0.0", 44 | "@angular/core": ">= 5.0.0" 45 | }, 46 | "devDependencies": { 47 | "@angular/animations": "5.0.0", 48 | "@angular/common": "5.0.0", 49 | "@angular/compiler": "5.0.0", 50 | "@angular/compiler-cli": "5.0.0", 51 | "@angular/core": "5.0.0", 52 | "@angular/platform-browser": "5.0.0", 53 | "@angular/platform-browser-dynamic": "5.0.0", 54 | "@angular/platform-server": "5.0.0", 55 | "@compodoc/compodoc": "1.0.3", 56 | "@types/jasmine": "2.6.2", 57 | "@types/node": "8.0.47", 58 | "chalk": "2.3.0", 59 | "codelyzer": "4.0.0", 60 | "core-js": "2.5.1", 61 | "jasmine-core": "2.8.0", 62 | "karma": "1.7.1", 63 | "karma-chrome-launcher": "2.2.0", 64 | "karma-jasmine": "1.1.0", 65 | "karma-sourcemap-loader": "0.3.7", 66 | "karma-spec-reporter": "0.0.31", 67 | "karma-webpack": "2.0.5", 68 | "karma-coverage-istanbul-reporter": "1.3.0", 69 | "istanbul-instrumenter-loader": "3.0.0", 70 | "reflect-metadata": "0.1.10", 71 | "rollup": "0.50.0", 72 | "rollup-plugin-node-resolve": "3.0.0", 73 | "rollup-plugin-sourcemaps": "0.4.2", 74 | "rollup-plugin-license": "0.5.0", 75 | "rxjs": "5.5.2", 76 | "shelljs": "0.7.8", 77 | "source-map-loader": "0.2.3", 78 | "ts-loader": "3.1.1", 79 | "tslib": "^1.7.1", 80 | "tslint": "5.8.0", 81 | "typescript": "2.4.2", 82 | "uglify-js": "3.1.6", 83 | "webpack": "3.8.1", 84 | "zone.js": "0.8.18" 85 | }, 86 | "greenkeeper": { 87 | "emails": false 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/public_api.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Entry point for all public APIs of the package. 3 | */ 4 | export * from './src/ngx-smart-loader'; 5 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve'; 2 | import sourcemaps from 'rollup-plugin-sourcemaps'; 3 | 4 | /** 5 | * Add here external dependencies that actually you use. 6 | * 7 | * About RxJS 8 | * Each RxJS functionality that you use in the library must be added as external dependency. 9 | * - For main classes use 'Rx': 10 | * e.g. import { Observable } from 'rxjs/Observable'; => 'rxjs/Observable': 'Rx' 11 | * - For observable methods use 'Rx.Observable': 12 | * e.g. import 'rxjs/add/observable/merge'; => 'rxjs/add/observable/merge': 'Rx.Observable' 13 | * or for lettable operators: 14 | * e.g. import { merge } from 'rxjs/observable/merge'; => 'rxjs/observable/merge': 'Rx.Observable' 15 | * - For operators use 'Rx.Observable.prototype': 16 | * e.g. import 'rxjs/add/operator/map'; => 'rxjs/add/operator/map': 'Rx.Observable.prototype' 17 | * or for lettable operators: 18 | * e.g. import { map } from 'rxjs/operators'; => 'rxjs/operators': 'Rx.Observable.prototype' 19 | */ 20 | const globals = { 21 | '@angular/core': 'ng.core', 22 | '@angular/common': 'ng.common', 23 | 'rxjs/Observable': 'Rx', 24 | 'rxjs/Observer': 'Rx' 25 | }; 26 | 27 | export default { 28 | external: Object.keys(globals), 29 | plugins: [resolve(), sourcemaps()], 30 | onwarn: () => { return }, 31 | output: { 32 | format: 'umd', 33 | name: 'ng.ngxSmartLoader', 34 | globals: globals, 35 | sourcemap: true, 36 | exports: 'named' 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/rollup.es.config.js: -------------------------------------------------------------------------------- 1 | import sourcemaps from 'rollup-plugin-sourcemaps'; 2 | import license from 'rollup-plugin-license'; 3 | 4 | const path = require('path'); 5 | 6 | export default { 7 | output: { 8 | format: 'es', 9 | sourcemap: true 10 | }, 11 | plugins: [ 12 | sourcemaps(), 13 | license({ 14 | sourceMap: true, 15 | 16 | banner: { 17 | file: path.join(__dirname, 'license-banner.txt'), 18 | encoding: 'utf-8', 19 | } 20 | }) 21 | ], 22 | onwarn: () => { return } 23 | } 24 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/spec.bundle.js: -------------------------------------------------------------------------------- 1 | import 'core-js'; 2 | import 'zone.js/dist/zone'; 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | 10 | import { getTestBed } from '@angular/core/testing'; 11 | import { 12 | BrowserDynamicTestingModule, 13 | platformBrowserDynamicTesting 14 | } from '@angular/platform-browser-dynamic/testing'; 15 | 16 | import 'rxjs'; 17 | 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | 23 | const testContext = require.context('./tests', true, /\.spec\.ts/); 24 | 25 | function requireAll(requireContext) { 26 | return requireContext.keys().map(requireContext); 27 | } 28 | 29 | const modules = requireAll(testContext); 30 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/src/components/ngx-smart-loader.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | OnInit, 4 | Input, 5 | OnDestroy, 6 | ChangeDetectorRef, 7 | Output, 8 | EventEmitter 9 | } from '@angular/core'; 10 | 11 | import { LoaderInstance } from './../services/loader-instance'; 12 | import { NgxSmartLoaderService } from "../services/ngx-smart-loader.service"; 13 | 14 | @Component({ 15 | selector: 'ngx-smart-loader', 16 | template: ` 17 |
19 | 20 |
21 | ` 22 | }) 23 | export class NgxSmartLoaderComponent implements OnInit, OnDestroy { 24 | 25 | @Input() public identifier: string = ''; 26 | @Input() public customClass: string = ''; 27 | @Input() public force: boolean = false; 28 | @Input() public delayIn: number = 0; 29 | @Input() public delayOut: number = 0; 30 | @Input() public autostart: boolean = false; 31 | 32 | @Output() public onStart = new EventEmitter(); 33 | @Output() public onStop = new EventEmitter(); 34 | @Output() public onVisibleChange = new EventEmitter(); 35 | 36 | public loading: boolean = false; 37 | public visible: boolean = false; 38 | public layerPosition: number = 999; 39 | 40 | private _debouncer: any; 41 | private _isProcessing: boolean = false; 42 | 43 | private _loaderBodyClass = 'loader-open'; 44 | private _enterClass = 'enter'; 45 | private _leaveClass = 'leave'; 46 | 47 | constructor(public ngxSmartLoaderService: NgxSmartLoaderService, private changeDetectorRef: ChangeDetectorRef) { 48 | } 49 | 50 | public ngOnInit(): void { 51 | try { 52 | const loader = new LoaderInstance(this); 53 | 54 | this.ngxSmartLoaderService.addLoader(loader, this.force); 55 | 56 | this.layerPosition += this.ngxSmartLoaderService.getLoaderStackCount(); 57 | this.addCustomClass(this.identifier.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()); 58 | 59 | if (this.autostart) { 60 | this.ngxSmartLoaderService.start(this.identifier); 61 | } else { 62 | this.ngxSmartLoaderService.executeAction(this.identifier, 'start'); 63 | } 64 | } catch (error) { 65 | throw (error); 66 | } 67 | } 68 | 69 | public ngOnDestroy(): void { 70 | this.ngxSmartLoaderService.removeLoader(this.identifier); 71 | } 72 | 73 | public start(top?: boolean): void { 74 | this._isProcessing = true; 75 | 76 | clearInterval(this._debouncer); 77 | 78 | this.visible = true; 79 | 80 | setTimeout(() => { 81 | this.addCustomClass(this._enterClass); 82 | }); 83 | 84 | this._debouncer = setTimeout(() => { 85 | if (top) { 86 | this.layerPosition = this.ngxSmartLoaderService.getHigherIndex(); 87 | } 88 | 89 | if (!document.body.classList.contains(this._loaderBodyClass)) { 90 | document.body.classList.add(this._loaderBodyClass); 91 | } 92 | 93 | this.loading = true; 94 | 95 | this.onStart.emit(this); 96 | this.onVisibleChange.emit(this); 97 | 98 | this.removeCustomClass(this._enterClass); 99 | this._isProcessing = false; 100 | }, this.delayIn); 101 | } 102 | 103 | public stop(): void { 104 | if (this._isProcessing) { 105 | this.visible = false; 106 | this.loading = false; 107 | } 108 | 109 | clearInterval(this._debouncer); 110 | 111 | this.addCustomClass(this._leaveClass); 112 | this.loading = false; 113 | this._debouncer = setTimeout(() => { 114 | if (document.body.classList.contains(this._loaderBodyClass)) { 115 | document.body.classList.remove(this._loaderBodyClass); 116 | } 117 | 118 | this.visible = false; 119 | 120 | this.onStop.emit(this); 121 | this.onVisibleChange.emit(this); 122 | 123 | this.removeCustomClass(this._leaveClass); 124 | setTimeout(() => { 125 | this.changeDetectorRef.markForCheck(); 126 | }); 127 | }, this.delayOut); 128 | } 129 | 130 | public addCustomClass(className: string): void { 131 | if (!this.customClass.length) { 132 | this.customClass = className; 133 | } else { 134 | if (this.customClass.indexOf(className) === -1) { 135 | this.customClass += ' ' + className; 136 | } 137 | } 138 | } 139 | 140 | public removeCustomClass(className?: string): void { 141 | if (className) { 142 | this.customClass = this.customClass.replace(className, '').trim(); 143 | } else { 144 | this.customClass = ''; 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/src/modules/ngx-smart-loader.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule, ModuleWithProviders } from '@angular/core'; 3 | 4 | import { NgxSmartLoaderService } from '../services/ngx-smart-loader.service'; 5 | import { NgxSmartLoaderComponent } from '../components/ngx-smart-loader.component'; 6 | 7 | @NgModule({ 8 | declarations: [NgxSmartLoaderComponent], 9 | exports: [NgxSmartLoaderComponent], 10 | imports: [CommonModule] 11 | }) 12 | export class NgxSmartLoaderModule { 13 | 14 | /** 15 | * Use in AppModule: new instance of NgxSmartLoader. 16 | */ 17 | public static forRoot(): ModuleWithProviders { 18 | return { 19 | ngModule: NgxSmartLoaderModule, 20 | providers: [NgxSmartLoaderService] 21 | }; 22 | } 23 | 24 | /** 25 | * Use in features modules with lazy loading: new instance of NgxSmartLoader. 26 | */ 27 | public static forChild(): ModuleWithProviders { 28 | return { 29 | ngModule: NgxSmartLoaderModule, 30 | providers: [NgxSmartLoaderService] 31 | }; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/src/ngx-smart-loader.css: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a default style. If you want to use the default ngx-smart-loader loader, 3 | * simply copy the HTML code in the documentation. 4 | **/ 5 | 6 | .loader-container .loader { 7 | display: block; 8 | height: 80px; 9 | width: 80px; 10 | position: absolute; 11 | left: 0; 12 | right: 0; 13 | margin: auto; 14 | bottom: 0; 15 | top: 0; 16 | } 17 | 18 | .loader-container .loader .circle { 19 | display: block; 20 | position: absolute; 21 | left: 0; 22 | top: 0; 23 | width: 100%; 24 | height: 100%; 25 | background: #fff; 26 | border-radius: 50%; 27 | transition: all 180ms linear; 28 | opacity: 0; 29 | transform: translateY(0%); 30 | } 31 | 32 | .loader-container .loader .circle:after { 33 | content: ''; 34 | display: block; 35 | position: absolute; 36 | width: 30px; 37 | height: 30px; 38 | border: 3px solid #5677fc; 39 | border-radius: 50%; 40 | border-left-color: transparent; 41 | border-top-color: transparent; 42 | left: 50%; 43 | top: 50%; 44 | transform: translate3d(-50%, -50%, 0); 45 | animation: RotateIt 1s linear infinite; 46 | } 47 | 48 | .loader-container .loader .circle:before { 49 | content: ''; 50 | display: block; 51 | position: absolute; 52 | width: 30px; 53 | height: 30px; 54 | border: 3px solid #efefef; 55 | border-radius: 50%; 56 | left: 50%; 57 | top: 50%; 58 | transform: translate3d(-50%, -50%, 0); 59 | } 60 | 61 | .loader-container.active .loader .circle { 62 | opacity: 1; 63 | animation: hop 500ms cubic-bezier(0.5, 1.25, 0.5, 1.25); 64 | } 65 | 66 | @keyframes hop { 67 | 0% { 68 | transform: translateY(150%); 69 | opcatiy: 0; 70 | } 71 | 100% { 72 | transform: translateY(0%); 73 | opcatiy: 1; 74 | } 75 | } 76 | 77 | @keyframes RotateIt { 78 | 0% { 79 | transform: translate3d(-50%, -50%, 0) rotate(0deg); 80 | } 81 | 100% { 82 | transform: translate3d(-50%, -50%, 0) rotate(720deg); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/src/ngx-smart-loader.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a default style. If you want to use the default ngx-smart-loader loader, 3 | * simply copy the HTML code in the documentation. 4 | **/ 5 | 6 | .loader-container { 7 | 8 | .loader { 9 | display: block; 10 | height: 80px; 11 | width: 80px; 12 | position: absolute; 13 | left: 0; 14 | right: 0; 15 | margin: auto; 16 | bottom: 0; 17 | top: 0; 18 | 19 | .circle { 20 | display: block; 21 | position: absolute; 22 | left: 0; 23 | top: 0; 24 | width: 100%; 25 | height: 100%; 26 | background: #fff; 27 | border-radius: 50%; 28 | transition: all 180ms linear; 29 | opacity: 0; 30 | 31 | &:before { 32 | content: ''; 33 | display: block; 34 | position: absolute; 35 | width: 30px; 36 | height: 30px; 37 | border: 3px solid #efefef; 38 | border-radius: 50%; 39 | left: 50%; 40 | top: 50%; 41 | transform: translate3d(-50%, -50%, 0); 42 | } 43 | 44 | &:after { 45 | content: ''; 46 | display: block; 47 | position: absolute; 48 | width: 30px; 49 | height: 30px; 50 | border: 3px solid #5677fc; 51 | border-radius: 50%; 52 | border-left-color: transparent; 53 | border-top-color: transparent; 54 | left: 50%; 55 | top: 50%; 56 | transform: translate3d(-50%, -50%, 0); 57 | animation: RotateIt 1s linear infinite; 58 | } 59 | } 60 | } 61 | 62 | &.active { 63 | .loader { 64 | .circle { 65 | opacity: 1; 66 | animation: hop 500ms cubic-bezier(0.5, 1.25, 0.5, 1.25); 67 | transform: translateY(0%); 68 | } 69 | } 70 | } 71 | 72 | &.leave { 73 | .loader { 74 | .circle { 75 | opacity: 0; 76 | animation: poh 500ms cubic-bezier(0.5, 1.25, 0.5, 1.25); 77 | } 78 | } 79 | } 80 | } 81 | 82 | @keyframes hop { 83 | 0% { 84 | transform: translateY(150%); 85 | opacity: 0; 86 | } 87 | 100% { 88 | transform: translateY(0%); 89 | opacity: 1; 90 | } 91 | } 92 | @keyframes poh { 93 | 0% { 94 | transform: translateY(0%); 95 | opacity: 1; 96 | } 97 | 100% { 98 | transform: translateY(150%); 99 | opacity: 0; 100 | } 101 | } 102 | 103 | @keyframes RotateIt { 104 | 0% { 105 | transform: translate3d(-50%, -50%, 0) rotate(0deg); 106 | } 107 | 100% { 108 | transform: translate3d(-50%, -50%, 0) rotate(720deg); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/src/ngx-smart-loader.ts: -------------------------------------------------------------------------------- 1 | // Public classes. 2 | export { NgxSmartLoaderService } from './services/ngx-smart-loader.service'; 3 | export { NgxSmartLoaderComponent } from './components/ngx-smart-loader.component'; 4 | export { NgxSmartLoaderModule } from './modules/ngx-smart-loader.module'; 5 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/src/services/loader-instance.ts: -------------------------------------------------------------------------------- 1 | import { NgxSmartLoaderComponent } from '../components/ngx-smart-loader.component'; 2 | 3 | export class LoaderInstance { 4 | public id: string; 5 | public component: NgxSmartLoaderComponent; 6 | 7 | constructor(component: NgxSmartLoaderComponent) { 8 | this.id = component.identifier; 9 | this.component = component; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/src/services/ngx-smart-loader.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | import { LoaderInstance } from './loader-instance'; 4 | 5 | @Injectable() 6 | export class NgxSmartLoaderService { 7 | private _loaderStack: LoaderInstance[] = []; 8 | private _actions: Array<{ identifier: string, action: string }> = []; 9 | 10 | /** 11 | * Add a new loader instance. This step is essential and allows to retrieve any loader at any time. 12 | * It stores an object that contains the given loader identifier and the loader itself directly in the `loaderStack`. 13 | * 14 | * @param loaderInstance The object that contains the given loader identifier and the loader itself. 15 | * @param force Optional parameter that forces the overriding of loader instance if it already exists. 16 | * @returns Returns nothing special. 17 | */ 18 | public addLoader(loaderInstance: LoaderInstance, force?: boolean): void { 19 | if (force) { 20 | const i: number = this._loaderStack.findIndex((o: LoaderInstance) => { 21 | return o.id === loaderInstance.id; 22 | }); 23 | if (i > -1) { 24 | this._loaderStack[i].component = loaderInstance.component; 25 | } else { 26 | this._loaderStack.push(loaderInstance); 27 | } 28 | return; 29 | } 30 | let loader; 31 | if (loader = this._getLoader(loaderInstance.id)) { 32 | throw (new Error('Loader with ' + loaderInstance.id + ' identifier already exist')); 33 | } else { 34 | this._loaderStack.push(loaderInstance); 35 | } 36 | } 37 | 38 | /** 39 | * Remove a loader instance from the loader stack. 40 | * 41 | * @param id The loader identifier. 42 | */ 43 | public removeLoader(id: string): void { 44 | this._loaderStack = this._loaderStack.filter((loader) => loader.id !== id); 45 | 46 | this._removeAction(id, '*'); 47 | } 48 | 49 | /** 50 | * Retrieve all the created loaders. 51 | * 52 | * @returns Returns an array that contains all loader instances. 53 | */ 54 | public getLoaderStack(): LoaderInstance[] { 55 | return this._loaderStack; 56 | } 57 | 58 | /** 59 | * It gives the number of loader instances. It's helpful to know if the loader stack is empty or not. 60 | * 61 | * @returns Returns the number of loader instances. 62 | */ 63 | public getLoaderStackCount(): number { 64 | return this._loaderStack.length; 65 | } 66 | 67 | /** 68 | * Retrieve all the opened loaders. It looks for all loader instances with their `visible` property set to `true`. 69 | * 70 | * @returns Returns an array that contains all the opened loaders. 71 | */ 72 | public getOpenedLoaders(): LoaderInstance[] { 73 | return this._loaderStack.filter((loader) => loader.component.visible); 74 | } 75 | 76 | /** 77 | * Retrieve all the active loaders. It looks for all loader instances with their `loading` property set to `true`. 78 | * 79 | * @returns Returns an array that contains all the active loaders. 80 | */ 81 | public getActiveLoaders(): LoaderInstance[] { 82 | return this._loaderStack.filter((loader) => loader.component.loading); 83 | } 84 | 85 | /** 86 | * Get the higher `z-index` value between all the loader instances. It iterates over the `LoaderStack` array and 87 | * calculates a higher value (it takes the highest index value between all the loader instances and adds 1). 88 | * Use it to make a loader appear foreground. 89 | * 90 | * @returns Returns a higher index from all the existing loader instances. 91 | */ 92 | public getHigherIndex(): number { 93 | const index: number[] = this.getOpenedLoaders().map((loader) => loader.component.layerPosition); 94 | 95 | return Math.max(...index) + 1; 96 | } 97 | 98 | /** 99 | * Enable loading state to one or several loaders. 100 | * 101 | * @param id The loader identifier. 102 | */ 103 | public start(id: string | string[]): void { 104 | let loader; 105 | 106 | if (Array.isArray(id)) { 107 | id.forEach((i: string) => { 108 | this.start(i); 109 | }); 110 | } else if (loader = this._getLoader(id)) { 111 | loader.component.start(); 112 | this._removeAction(id, 'start'); 113 | } else { 114 | this._addAction(id, 'start'); 115 | } 116 | } 117 | 118 | /** 119 | * Enable loading state to all loaders. 120 | */ 121 | public startAll(): void { 122 | this._loaderStack.forEach((loader) => this.start(loader.id)); 123 | } 124 | 125 | /** 126 | * Disable loading state to one or several loaders. 127 | * 128 | * @param id The loader identifier. 129 | */ 130 | public stop(id: string | string[]): void { 131 | let loader; 132 | 133 | if (Array.isArray(id)) { 134 | id.forEach((i: string) => { 135 | this.stop(i); 136 | }); 137 | } else if (loader = this._getLoader(id)) { 138 | loader.component.stop(); 139 | this._removeAction(id, 'stop'); 140 | } else { 141 | this._addAction(id, 'stop'); 142 | } 143 | } 144 | 145 | /** 146 | * Disable loading state to all loaders. 147 | */ 148 | public stopAll(): void { 149 | this._loaderStack.forEach((loader) => this.stop(loader.id)); 150 | } 151 | 152 | public isLoading(id: string | string[]): boolean { 153 | let loader; 154 | if (Array.isArray(id)) { 155 | const tmp: any = []; 156 | 157 | id.forEach((i: string) => { 158 | this._loaderStack.forEach((load) => { 159 | if (load.id === i) { 160 | tmp.push(load.component.loading); 161 | } 162 | }); 163 | }); 164 | return tmp.indexOf(false) === -1; 165 | } else if (loader = this._getLoader(id)) { 166 | return loader.component.loading; 167 | } else { 168 | return false; 169 | } 170 | } 171 | 172 | /** 173 | * Execute an action on loaders 174 | * 175 | * @param id The loader identifier. 176 | * @param action Name of the action. 177 | */ 178 | public executeAction(id: string, action: string): void { 179 | if (this._actions.find((act) => act.identifier === id && act.action === action)) { 180 | switch (action) { 181 | case 'start': 182 | this.start(id); 183 | break; 184 | case 'stop': 185 | this.stop(id); 186 | break; 187 | } 188 | } 189 | } 190 | 191 | /** 192 | * Retrieve a loader instance by its identifier. 193 | * If there's several loaders with same identifier, the first is returned. 194 | * 195 | * @param id The loader identifier used at creation time. 196 | */ 197 | private _getLoader(id: string): LoaderInstance | null { 198 | return this._loaderStack.find((load) => load.id === id) || null; 199 | } 200 | 201 | /** 202 | * Adds an action on one or more loaders 203 | * 204 | * @param id The loader identifier. 205 | * @param action Name of the action. 206 | */ 207 | private _addAction(id: string | string[], action: string): void { 208 | if (Array.isArray(id)) { 209 | id.forEach((i: string) => { 210 | this._addAction(i, action); 211 | }); 212 | } else { 213 | this._actions.push({ identifier: id, action: action }); 214 | } 215 | } 216 | 217 | /** 218 | * Remove an action on one or more loaders 219 | * 220 | * @param id The loader identifier. 221 | * @param action Name of the action. 222 | */ 223 | private _removeAction(id: string | string[], action: string): void { 224 | if (Array.isArray(id)) { 225 | id.forEach((i: string) => { 226 | this._removeAction(i, action); 227 | }); 228 | } else { 229 | this._actions = this._actions.filter((act) => act.identifier !== id || (act.action !== action && action !== '*')); 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/tests/components/ngx-smart-loader.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async, inject } from '@angular/core/testing'; 2 | import { NgxSmartLoaderComponent, NgxSmartLoaderService } from './../../index'; 3 | 4 | describe('NgxSmartLoaderComponent', () => { 5 | 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [ 9 | NgxSmartLoaderComponent 10 | ], 11 | providers: [ 12 | NgxSmartLoaderService 13 | ] 14 | }).compileComponents(); 15 | })); 16 | 17 | it('should create a loader', async(() => { 18 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 19 | const app = fixture.debugElement.componentInstance; 20 | app.identifier = 'myLoader'; 21 | expect(app).toBeTruthy(); 22 | })); 23 | 24 | it('should start and stop the loader directly', async(() => { 25 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 26 | const app = fixture.debugElement.componentInstance; 27 | app.identifier = 'myLoader'; 28 | app.start(); 29 | app.onStart.subscribe(() => { 30 | expect(app.loading).toBeTruthy(); 31 | expect(app.visible).toBeTruthy(); 32 | app.stop(); 33 | }); 34 | 35 | app.onStop.subscribe(() => { 36 | expect(app.loading).toBeFalsy(); 37 | expect(app.visible).toBeFalsy(); 38 | }); 39 | })); 40 | 41 | it('should add additional class to the loader', async(() => { 42 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 43 | const app = fixture.debugElement.componentInstance; 44 | app.identifier = 'myLoader'; 45 | app.addCustomClass('firstClass'); 46 | app.addCustomClass('secondClass'); 47 | app.start(); 48 | app.onStart.subscribe(() => { 49 | const firstRef = app.customClass.includes('firstClass'); 50 | const secondRef = app.customClass.includes('secondClass'); 51 | expect(firstRef).toBeTruthy(); 52 | expect(secondRef).toBeTruthy(); 53 | }); 54 | })); 55 | 56 | it('should remove additional class of the loader', async(() => { 57 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 58 | const app = fixture.debugElement.componentInstance; 59 | app.identifier = 'myLoader'; 60 | app.addCustomClass('firstClass'); 61 | app.addCustomClass('secondClass'); 62 | app.removeCustomClass('firstClass'); 63 | app.start(); 64 | app.onStart.subscribe(() => { 65 | const firstRef = app.customClass.includes('firstClass'); 66 | const secondRef = app.customClass.includes('secondClass'); 67 | expect(firstRef).toBeFalsy(); 68 | expect(secondRef).toBeTruthy(); 69 | }); 70 | })); 71 | 72 | it('should remove loader from service on destroy', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 73 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 74 | const app = fixture.debugElement.componentInstance; 75 | app.identifier = 'myLoader'; 76 | 77 | spyOn(service, 'removeLoader'); 78 | 79 | app.ngOnDestroy(); 80 | 81 | expect(service.removeLoader).toHaveBeenCalledWith('myLoader'); 82 | }) 83 | ); 84 | 85 | 86 | it('should autostart loader', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 87 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 88 | const app = fixture.debugElement.componentInstance; 89 | app.identifier = 'myLoader'; 90 | app.layerPosition = 1; 91 | app.autostart = true; 92 | 93 | spyOn(service, 'getLoaderStackCount').and.returnValue(2); 94 | spyOn(app, 'addCustomClass'); 95 | spyOn(service, 'start'); 96 | 97 | app.ngOnInit(); 98 | 99 | expect(service.getLoaderStackCount).toHaveBeenCalled(); 100 | expect(app.addCustomClass).toHaveBeenCalledWith('my-loader'); 101 | expect(service.start).toHaveBeenCalledWith('myLoader'); 102 | expect(app.layerPosition).toEqual(3); 103 | }) 104 | ); 105 | 106 | }); 107 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/tests/services/ngx-smart-loader.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { inject, TestBed, async } from '@angular/core/testing'; 2 | 3 | import { NgxSmartLoaderComponent, NgxSmartLoaderService } from './../../index'; 4 | import { LoaderInstance } from "../../src/services/loader-instance"; 5 | 6 | describe('NgxSmartLoaderService', () => { 7 | 8 | beforeEach(async(() => { 9 | TestBed.configureTestingModule({ 10 | declarations: [ 11 | NgxSmartLoaderComponent 12 | ], 13 | providers: [ 14 | NgxSmartLoaderService 15 | ], 16 | }).compileComponents(); 17 | })); 18 | 19 | it('should be created', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 20 | expect(service).toBeTruthy(); 21 | })); 22 | 23 | it('should addLoader', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 24 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 25 | const loader = fixture.debugElement.componentInstance; 26 | loader.id = 'myLoader'; 27 | 28 | service.addLoader(loader); 29 | 30 | expect(service.getLoaderStack()[0]).toEqual(loader); 31 | })); 32 | 33 | it('should addLoader with force', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 34 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 35 | const loader = fixture.debugElement.componentInstance; 36 | loader.id = 'myLoader'; 37 | 38 | service.addLoader(loader); 39 | 40 | service.addLoader(loader, true); 41 | 42 | expect(service.getLoaderStack().length).toEqual(1); 43 | expect(service.getLoaderStack()[0]).toEqual(loader); 44 | })); 45 | 46 | it('should addLoader with same identifier', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 47 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 48 | const loader = fixture.debugElement.componentInstance; 49 | loader.id = 'myLoader'; 50 | 51 | service.addLoader(loader); 52 | 53 | expect(() => { service.addLoader(loader); }).toThrow(new Error('Loader with myLoader identifier already exist')); 54 | })); 55 | 56 | it('should removeLoader', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 57 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 58 | const loader = fixture.debugElement.componentInstance; 59 | loader.id = 'myLoader'; 60 | 61 | service.addLoader(loader); 62 | 63 | spyOn(service, '_removeAction'); 64 | 65 | service.removeLoader('myLoader'); 66 | 67 | expect(service.getLoaderStack().length).toEqual(0); 68 | expect((service)._removeAction).toHaveBeenCalledWith('myLoader', '*'); 69 | })); 70 | 71 | it('should getLoaderStackCount', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 72 | expect(service.getLoaderStackCount()).toEqual(0); 73 | 74 | const fixture = TestBed.createComponent(NgxSmartLoaderComponent); 75 | const loader = fixture.debugElement.componentInstance; 76 | loader.id = 'myLoader'; 77 | 78 | service.addLoader(loader); 79 | 80 | expect(service.getLoaderStackCount()).toEqual(1); 81 | })); 82 | 83 | it('should getOpenedLoaders', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 84 | (service)._loaderStack = [ 85 | { component: { visible: true } }, 86 | { component: { visible: true } }, 87 | { component: { visible: false } } 88 | ] 89 | 90 | expect(service.getOpenedLoaders().length).toEqual(2); 91 | })); 92 | 93 | it('should getActiveLoaders', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 94 | (service)._loaderStack = [ 95 | { component: { loading: true } }, 96 | { component: { loading: true } }, 97 | { component: { loading: false } } 98 | ] 99 | 100 | expect(service.getActiveLoaders().length).toEqual(2); 101 | })); 102 | 103 | it('should getHigherIndex', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 104 | (service)._loaderStack = [ 105 | { component: { layerPosition: 10, visible: true } }, 106 | { component: { layerPosition: 50, visible: false } }, 107 | { component: { layerPosition: 2, visible: true } } 108 | ] 109 | 110 | expect(service.getHigherIndex()).toEqual(11); 111 | })); 112 | 113 | it('should start ( with array )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 114 | spyOn(service, 'start').and.callThrough(); 115 | 116 | service.start(['1', '2']); 117 | 118 | expect(service.start).toHaveBeenCalledWith('1'); 119 | expect(service.start).toHaveBeenCalledWith('2'); 120 | })); 121 | 122 | it('should start ( with existing loader )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 123 | spyOn(service, '_getLoader').and.returnValue({ component: { start: () => { } } }); 124 | spyOn(service, '_removeAction') 125 | 126 | service.start('myLoader'); 127 | 128 | expect((service)._getLoader).toHaveBeenCalledWith('myLoader'); 129 | expect((service)._removeAction).toHaveBeenCalledWith('myLoader', 'start'); 130 | })); 131 | 132 | it('should startAll', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 133 | (service)._loaderStack = [ 134 | { id: '1' }, 135 | { id: '2' } 136 | ] 137 | 138 | spyOn(service, 'start'); 139 | 140 | service.startAll(); 141 | 142 | expect(service.start).toHaveBeenCalledWith('1'); 143 | expect(service.start).toHaveBeenCalledWith('2'); 144 | })); 145 | 146 | it('should stop ( with array )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 147 | spyOn(service, 'stop').and.callThrough(); 148 | 149 | service.stop(['1', '2']); 150 | 151 | expect(service.stop).toHaveBeenCalledWith('1'); 152 | expect(service.stop).toHaveBeenCalledWith('2'); 153 | })); 154 | 155 | it('should stop ( with existing loader )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 156 | spyOn(service, '_getLoader').and.returnValue({ component: { stop: () => { } } }); 157 | spyOn(service, '_removeAction') 158 | 159 | service.stop('myLoader'); 160 | 161 | expect((service)._getLoader).toHaveBeenCalledWith('myLoader'); 162 | expect((service)._removeAction).toHaveBeenCalledWith('myLoader', 'stop'); 163 | })); 164 | 165 | it('should stopAll', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 166 | (service)._loaderStack = [ 167 | { id: '1' }, 168 | { id: '2' } 169 | ] 170 | 171 | spyOn(service, 'stop'); 172 | 173 | service.stopAll(); 174 | 175 | expect(service.stop).toHaveBeenCalledWith('1'); 176 | expect(service.stop).toHaveBeenCalledWith('2'); 177 | })); 178 | 179 | it('should isLoading ( with array )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 180 | (service)._loaderStack = [ 181 | { id: '1', component: { loading: true } }, 182 | { id: '2', component: { loading: false } }, 183 | ] 184 | 185 | expect(service.isLoading(['1', '2'])).toEqual(false); 186 | })); 187 | 188 | it('should isLoading', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 189 | (service)._loaderStack = [ 190 | { id: '2', component: { loading: true } }, 191 | ] 192 | 193 | expect(service.isLoading('2')).toEqual(true); 194 | })); 195 | 196 | it('should _addAction', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 197 | (service)._addAction('1', 'start'); 198 | 199 | expect((service)._actions).toEqual([{ identifier: '1', action: 'start' }]); 200 | })); 201 | 202 | it('should _addAction ( with array )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 203 | (service)._addAction(['1', '2'], 'start'); 204 | 205 | expect((service)._actions).toEqual([{ identifier: '1', action: 'start' }, { identifier: '2', action: 'start' }]); 206 | })); 207 | 208 | it('should _removeAction', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 209 | (service)._actions = [{ identifier: '1', action: 'start' }]; 210 | 211 | (service)._removeAction('1', 'start'); 212 | 213 | expect((service)._actions).toEqual([]); 214 | })); 215 | 216 | it('should _removeAction ( with array )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 217 | (service)._actions = [{ identifier: '1', action: 'start' }, { identifier: '2', action: 'start' }]; 218 | 219 | (service)._removeAction(['1', '2'], 'start'); 220 | 221 | expect((service)._actions).toEqual([]); 222 | })); 223 | 224 | it('should _removeAction ( all action )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 225 | (service)._actions = [{ identifier: '1', action: 'start' }, { identifier: '1', action: 'stop' }]; 226 | 227 | (service)._removeAction('1', '*'); 228 | 229 | expect((service)._actions).toEqual([]); 230 | })); 231 | 232 | it('should executeAction ( case start )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 233 | (service)._actions = [{ identifier: '1', action: 'start' }]; 234 | 235 | spyOn(service, 'start'); 236 | 237 | service.executeAction('1', 'start'); 238 | 239 | expect(service.start).toHaveBeenCalledWith('1'); 240 | })); 241 | 242 | it('should executeAction ( case stop )', inject([NgxSmartLoaderService], (service: NgxSmartLoaderService) => { 243 | (service)._actions = [{ identifier: '1', action: 'stop' }]; 244 | 245 | spyOn(service, 'stop'); 246 | 247 | service.executeAction('1', 'stop'); 248 | 249 | expect(service.stop).toHaveBeenCalledWith('1'); 250 | })); 251 | }); 252 | -------------------------------------------------------------------------------- /src/ngx-smart-loader/tsconfig-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": ".", 4 | "baseUrl": ".", 5 | "paths": { 6 | "@angular/*": [ 7 | "node_modules/@angular/*" 8 | ] 9 | }, 10 | "outDir": "dist", 11 | "declaration": true, 12 | "strict": true, 13 | "moduleResolution": "node", 14 | "module": "es2015", 15 | "target": "es2015", 16 | "lib": [ 17 | "es2015", 18 | "dom" 19 | ], 20 | "skipLibCheck": true, 21 | "types": [], 22 | "experimentalDecorators": true, 23 | "emitDecoratorMetadata": true, 24 | "sourceMap": true, 25 | "inlineSources": true 26 | }, 27 | "files": [ 28 | "public_api.ts", 29 | "node_modules/zone.js/dist/zone.js.d.ts" 30 | ], 31 | "angularCompilerOptions": { 32 | "skipTemplateCodegen": true, 33 | "annotateForClosureCompiler": true, 34 | "strictMetadataEmit": true, 35 | "flatModuleOutFile": "ngx-smart-loader.js", 36 | "flatModuleId": "ngx-smart-loader" 37 | } 38 | } -------------------------------------------------------------------------------- /src/ngx-smart-loader/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "emitDecoratorMetadata": true, 5 | "experimentalDecorators": true, 6 | "strict": true, 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "rootDir": ".", 10 | "sourceMap": true, 11 | "inlineSources": true, 12 | "target": "es5", 13 | "skipLibCheck": true, 14 | "lib": [ 15 | "es2015", 16 | "dom" 17 | ], 18 | "typeRoots": [ 19 | "./node_modules/@types/" 20 | ] 21 | }, 22 | "exclude": [ 23 | "node_modules" 24 | ] 25 | } -------------------------------------------------------------------------------- /src/ngx-smart-loader/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [ 4 | "node_modules/codelyzer" 5 | ], 6 | "rules": { 7 | "no-trailing-whitespace": false, 8 | "angular-whitespace": [ 9 | true, 10 | "check-interpolation", 11 | "check-pipe" 12 | ], 13 | "banana-in-box": true, 14 | "templates-no-negated-async": true, 15 | "directive-selector": [ 16 | true, 17 | "attribute", 18 | [ 19 | "dir-prefix1", 20 | "dir-prefix2" 21 | ], 22 | "camelCase" 23 | ], 24 | "component-selector": [ 25 | true, 26 | "element", 27 | [ 28 | "ngx-smart-loader" 29 | ], 30 | "kebab-case" 31 | ], 32 | "use-input-property-decorator": true, 33 | "use-output-property-decorator": true, 34 | "use-host-property-decorator": true, 35 | "no-attribute-parameter-decorator": true, 36 | "no-input-rename": true, 37 | "no-output-rename": true, 38 | "no-forward-ref": true, 39 | "use-view-encapsulation": false, 40 | "use-life-cycle-interface": true, 41 | "use-pipe-transform-interface": true, 42 | "pipe-naming": [ 43 | true, 44 | "camelCase", 45 | "Pipe" 46 | ], 47 | "component-class-suffix": [ 48 | true, 49 | "Component" 50 | ], 51 | "directive-class-suffix": [ 52 | true, 53 | "Directive" 54 | ], 55 | "ordered-imports": [ 56 | false 57 | ], 58 | "quotemark": [ 59 | false 60 | ], 61 | "trailing-comma": [ 62 | false 63 | ] 64 | } 65 | } -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support start SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | import 'reflect-metadata'; 49 | 50 | 51 | /** 52 | * Required to support Web Animations `@angular/platform-browser/animations`. 53 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 54 | **/ 55 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 56 | 57 | 58 | 59 | /*************************************************************************************************** 60 | * Zone JS is required by Angular itself. 61 | */ 62 | import 'zone.js/dist/zone'; // Included with Angular CLI. 63 | 64 | 65 | 66 | /*************************************************************************************************** 67 | * APPLICATION IMPORTS 68 | */ 69 | 70 | /** 71 | * Date, currency, decimal and percent pipes. 72 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 73 | */ 74 | // import 'intl'; // Run `npm install --save intl`. 75 | /** 76 | * Need to import at least one locale-data with intl. 77 | */ 78 | // import 'intl/locale-data/jsonp/en'; 79 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | /* Import ngx-smart-loader default loader style */ 3 | @import "ngx-smart-loader/src/ngx-smart-loader"; 4 | 5 | // colors 6 | $indigo: #536dfe; 7 | $blue: #5677fc; 8 | 9 | // font import 10 | @import url(https://fonts.googleapis.com/css?family=Roboto:400,700,500); 11 | 12 | // prismJS theme 13 | @import url(https://cdnjs.cloudflare.com/ajax/libs/prism/1.6.0/themes/prism-okaidia.min.css); 14 | 15 | // font 16 | $font-face: 'Roboto', sans-serif; 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | position: relative; 24 | height: 100%; 25 | margin: 0; 26 | padding: 0; 27 | } 28 | 29 | body { 30 | font-family: $font-face; 31 | background: #536dfe; 32 | color: #fff; 33 | } 34 | 35 | .top { 36 | padding-top: 50px; 37 | text-align: center; 38 | 39 | nav { 40 | ul { 41 | list-style: none; 42 | display: flex; 43 | justify-content: center; 44 | 45 | li { 46 | 47 | a { 48 | color: #fff; 49 | padding: 5px 12px; 50 | text-decoration: none; 51 | 52 | &:hover { 53 | text-decoration: underline; 54 | } 55 | 56 | &.active { 57 | font-weight: 700; 58 | text-decoration: underline; 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | .container { 67 | display: flex; 68 | align-items: flex-start; 69 | justify-content: center; 70 | 71 | .item { 72 | position: relative; 73 | overflow: hidden; 74 | flex: 1; 75 | margin: 20px 20px 0; 76 | min-height: 250px; 77 | background-color: #34495e; 78 | 79 | h3 { 80 | text-align: center; 81 | font-size: 16px; 82 | } 83 | } 84 | .item-white { 85 | background-color: #fff; 86 | 87 | h3 { 88 | color: #34495e; 89 | } 90 | } 91 | .item-blank { 92 | background-color: transparent; 93 | 94 | h3 { 95 | color: #34495e; 96 | } 97 | } 98 | } 99 | 100 | .btn-container { 101 | position: fixed; 102 | left: 0; 103 | right: 0; 104 | bottom: 0; 105 | margin: auto; 106 | text-align: center; 107 | padding: 40px; 108 | 109 | button { 110 | display: inline-block; 111 | background: transparent; 112 | border: 2px solid #fff; 113 | color: #fff; 114 | outline: none; 115 | box-shadow: none; 116 | padding: 17px 20px; 117 | text-transform: uppercase; 118 | font-weight: bold; 119 | position: relative; 120 | box-shadow: inset 0 0 0 0 #fff; 121 | transition: all 180ms linear; 122 | margin: 0 10px; 123 | 124 | &:hover, &.active { 125 | box-shadow: inset 0 0 0 50px #fff; 126 | color: $indigo; 127 | cursor: pointer; 128 | } 129 | } 130 | } 131 | 132 | /* CODE SNIPPETS STYLE */ 133 | 134 | pre { 135 | white-space: pre-wrap; 136 | white-space: -moz-pre-wrap; 137 | white-space: -o-pre-wrap; 138 | word-wrap: break-word; 139 | } 140 | 141 | code { 142 | font-family: Courier, 'New Courier', monospace; 143 | font-size: 14px; 144 | } 145 | 146 | .code-snippet { 147 | border-radius: 5px; 148 | -moz-border-radius: 5px; 149 | -webkit-border-radius: 5px; 150 | margin: 1em 0; 151 | padding: 14px; 152 | background-color: #2c3e50; 153 | color: #2ecc71; 154 | } 155 | 156 | /**/ 157 | /* RUBIKS CUBE LOADER */ 158 | /**/ 159 | .rubik-loader { 160 | width: 64px; 161 | height: 64px; 162 | position: absolute; 163 | left: 50%; 164 | top: 50%; 165 | transform: translate(-50%, -50%); 166 | background: url(http://i.giphy.com/3og0ISeflb7vrNzy2A.gif) no-repeat center; 167 | transition: all 2s linear; 168 | opacity: 0; 169 | } 170 | 171 | .active { 172 | .rubik-loader { 173 | opacity: 1; 174 | } 175 | } 176 | 177 | .leave { 178 | .rubik-loader { 179 | opacity: 0; 180 | } 181 | } 182 | 183 | .enter { 184 | .rubik-loader { 185 | opacity: 1; 186 | } 187 | } 188 | 189 | /**/ 190 | /* JELLY LOADER */ 191 | /**/ 192 | 193 | .loader-container { 194 | #jelly-loader { 195 | position: absolute; 196 | top: calc(50% - 20px); 197 | left: calc(50% - 20px); 198 | transition: all 180ms linear; 199 | opacity: 0; 200 | 201 | #box { 202 | width: 50px; 203 | height: 50px; 204 | background: purple; 205 | animation: animate .5s linear infinite; 206 | position: absolute; 207 | top: 0; 208 | left: 0; 209 | border-radius: 3px; 210 | } 211 | 212 | #shadow { 213 | width: 50px; 214 | height: 5px; 215 | background: #000; 216 | opacity: 0.1; 217 | position: absolute; 218 | top: 59px; 219 | left: 0; 220 | border-radius: 50%; 221 | animation: shadow .5s linear infinite; 222 | } 223 | } 224 | 225 | &.active { 226 | #jelly-loader { 227 | opacity: 1; 228 | } 229 | } 230 | 231 | &.leave { 232 | #jelly-loader { 233 | opacity: 0; 234 | } 235 | } 236 | 237 | @keyframes loader { 238 | 0% { 239 | left: -100px 240 | } 241 | 100% { 242 | left: 110%; 243 | } 244 | } 245 | 246 | @keyframes animate { 247 | 17% { 248 | border-bottom-right-radius: 3px; 249 | } 250 | 25% { 251 | transform: translateY(9px) rotate(22.5deg); 252 | } 253 | 50% { 254 | transform: translateY(18px) scale(1, .9) rotate(45deg); 255 | border-bottom-right-radius: 40px; 256 | } 257 | 75% { 258 | transform: translateY(9px) rotate(67.5deg); 259 | } 260 | 100% { 261 | transform: translateY(0) rotate(90deg); 262 | } 263 | } 264 | 265 | @keyframes shadow { 266 | 50% { 267 | transform: scale(1.2, 1); 268 | } 269 | } 270 | } 271 | 272 | .loader-container { 273 | .body { 274 | position: absolute; 275 | top: 50%; 276 | margin-left: -50px; 277 | left: 50%; 278 | animation: speeder .4s linear infinite; 279 | transition: all 180ms linear; 280 | opacity: 0; 281 | 282 | > span { 283 | height: 5px; 284 | width: 35px; 285 | background: #000; 286 | position: absolute; 287 | top: -19px; 288 | left: 60px; 289 | border-radius: 2px 10px 1px 0; 290 | } 291 | } 292 | 293 | h1 { 294 | position: absolute; 295 | font-family: $font-face; 296 | color: #000; 297 | font-weight: 600; 298 | font-size: 12px; 299 | text-transform: uppercase; 300 | left: 50%; 301 | top: 58%; 302 | margin-left: -20px; 303 | } 304 | 305 | .base { 306 | span { 307 | position: absolute; 308 | width: 0; 309 | height: 0; 310 | border-top: 6px solid transparent; 311 | border-right: 100px solid #000; 312 | border-bottom: 6px solid transparent; 313 | 314 | &:before { 315 | content: ""; 316 | height: 22px; 317 | width: 22px; 318 | border-radius: 50%; 319 | background: #000; 320 | position: absolute; 321 | right: -110px; 322 | top: -16px; 323 | } 324 | 325 | &:after { 326 | content: ""; 327 | position: absolute; 328 | width: 0; 329 | height: 0; 330 | border-top: 0 solid transparent; 331 | border-right: 55px solid #000; 332 | border-bottom: 16px solid transparent; 333 | top: -16px; 334 | right: -98px; 335 | } 336 | } 337 | } 338 | 339 | .face { 340 | position: absolute; 341 | height: 12px; 342 | width: 20px; 343 | background: #000; 344 | border-radius: 20px 20px 0 0; 345 | transform: rotate(-40deg); 346 | right: -125px; 347 | top: -15px; 348 | 349 | &:after { 350 | content: ""; 351 | height: 12px; 352 | width: 12px; 353 | background: #000; 354 | right: 4px; 355 | top: 7px; 356 | position: absolute; 357 | transform: rotate(40deg); 358 | transform-origin: 50% 50%; 359 | border-radius: 0 0 0 2px; 360 | } 361 | } 362 | 363 | .body > span > span:nth-child(1), 364 | .body > span > span:nth-child(2), 365 | .body > span > span:nth-child(3), 366 | .body > span > span:nth-child(4) { 367 | width: 30px; 368 | height: 1px; 369 | background: #000; 370 | position: absolute; 371 | animation: fazer1 .2s linear infinite; 372 | } 373 | 374 | .body > span > span:nth-child(2) { 375 | top: 3px; 376 | animation: fazer2 .4s linear infinite; 377 | } 378 | 379 | .body > span > span:nth-child(3) { 380 | top: 1px; 381 | animation: fazer3 .4s linear infinite; 382 | animation-delay: -1s; 383 | } 384 | 385 | .body > span > span:nth-child(4) { 386 | top: 4px; 387 | animation: fazer4 1s linear infinite; 388 | animation-delay: -1s; 389 | } 390 | 391 | @keyframes fazer1 { 392 | 0% { 393 | left: 0; 394 | } 395 | 100% { 396 | left: -80px; 397 | opacity: 0; 398 | } 399 | } 400 | 401 | @keyframes fazer2 { 402 | 0% { 403 | left: 0; 404 | } 405 | 100% { 406 | left: -100px; 407 | opacity: 0; 408 | } 409 | } 410 | 411 | @keyframes fazer3 { 412 | 0% { 413 | left: 0; 414 | } 415 | 100% { 416 | left: -50px; 417 | opacity: 0; 418 | } 419 | } 420 | 421 | @keyframes fazer4 { 422 | 0% { 423 | left: 0; 424 | } 425 | 100% { 426 | left: -150px; 427 | opacity: 0; 428 | } 429 | } 430 | 431 | @keyframes speeder { 432 | 0% { 433 | transform: translate(2px, 1px) rotate(0deg); 434 | } 435 | 10% { 436 | transform: translate(-1px, -3px) rotate(-1deg); 437 | } 438 | 20% { 439 | transform: translate(-2px, 0px) rotate(1deg); 440 | } 441 | 30% { 442 | transform: translate(1px, 2px) rotate(0deg); 443 | } 444 | 40% { 445 | transform: translate(1px, -1px) rotate(1deg); 446 | } 447 | 50% { 448 | transform: translate(-1px, 3px) rotate(-1deg); 449 | } 450 | 60% { 451 | transform: translate(-1px, 1px) rotate(0deg); 452 | } 453 | 70% { 454 | transform: translate(3px, 1px) rotate(-1deg); 455 | } 456 | 80% { 457 | transform: translate(-2px, -1px) rotate(1deg); 458 | } 459 | 90% { 460 | transform: translate(2px, 1px) rotate(0deg); 461 | } 462 | 100% { 463 | transform: translate(1px, -2px) rotate(-1deg); 464 | } 465 | } 466 | 467 | .longfazers { 468 | position: absolute; 469 | width: 100%; 470 | height: 100%; 471 | 472 | span { 473 | position: absolute; 474 | height: 2px; 475 | width: 20%; 476 | background: #000; 477 | 478 | &:nth-child(1) { 479 | top: 20%; 480 | animation: lf .6s linear infinite; 481 | animation-delay: -5s; 482 | } 483 | 484 | &:nth-child(2) { 485 | top: 40%; 486 | animation: lf2 .8s linear infinite; 487 | animation-delay: -1s; 488 | } 489 | 490 | &:nth-child(3) { 491 | top: 60%; 492 | animation: lf3 .6s linear infinite; 493 | } 494 | 495 | &:nth-child(4) { 496 | top: 80%; 497 | animation: lf4 .5s linear infinite; 498 | animation-delay: -3s; 499 | } 500 | } 501 | } 502 | 503 | @keyframes lf { 504 | 0% { 505 | left: 200%; 506 | } 507 | 100% { 508 | left: -200%; 509 | opacity: 0; 510 | } 511 | } 512 | @keyframes lf2 { 513 | 0% { 514 | left: 200%; 515 | } 516 | 100% { 517 | left: -200%; 518 | opacity: 0; 519 | } 520 | } 521 | @keyframes lf3 { 522 | 0% { 523 | left: 200%; 524 | } 525 | 100% { 526 | left: -100%; 527 | opacity: 0; 528 | } 529 | } 530 | @keyframes lf4 { 531 | 0% { 532 | left: 200%; 533 | } 534 | 100% { 535 | left: -100%; 536 | opacity: 0; 537 | } 538 | } 539 | 540 | &.active { 541 | .body { 542 | opacity: 1; 543 | } 544 | } 545 | 546 | &.leave { 547 | .body { 548 | opacity: 0; 549 | } 550 | } 551 | } 552 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare const __karma__: any; 17 | declare const require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "eofline": true, 15 | "forin": true, 16 | "import-blacklist": [ 17 | true, 18 | "rxjs", 19 | "rxjs/Rx" 20 | ], 21 | "import-spacing": true, 22 | "indent": [ 23 | true, 24 | "spaces" 25 | ], 26 | "interface-over-type-literal": true, 27 | "label-position": true, 28 | "max-line-length": [ 29 | true, 30 | 140 31 | ], 32 | "member-access": false, 33 | "member-ordering": [ 34 | true, 35 | { 36 | "order": [ 37 | "static-field", 38 | "instance-field", 39 | "static-method", 40 | "instance-method" 41 | ] 42 | } 43 | ], 44 | "no-arg": true, 45 | "no-bitwise": true, 46 | "no-console": [ 47 | true, 48 | "debug", 49 | "info", 50 | "time", 51 | "timeEnd", 52 | "trace" 53 | ], 54 | "no-construct": true, 55 | "no-debugger": true, 56 | "no-duplicate-super": true, 57 | "no-empty": false, 58 | "no-empty-interface": true, 59 | "no-eval": true, 60 | "no-inferrable-types": [ 61 | true, 62 | "ignore-params" 63 | ], 64 | "no-misused-new": true, 65 | "no-non-null-assertion": true, 66 | "no-shadowed-variable": true, 67 | "no-string-literal": false, 68 | "no-string-throw": true, 69 | "no-switch-case-fall-through": true, 70 | "no-trailing-whitespace": false, 71 | "no-unnecessary-initializer": true, 72 | "no-unused-expression": true, 73 | "no-use-before-declare": true, 74 | "no-var-keyword": true, 75 | "object-literal-sort-keys": false, 76 | "one-line": [ 77 | true, 78 | "check-open-brace", 79 | "check-catch", 80 | "check-else", 81 | "check-whitespace" 82 | ], 83 | "prefer-const": true, 84 | "quotemark": [ 85 | true, 86 | "single" 87 | ], 88 | "radix": true, 89 | "semicolon": [ 90 | true, 91 | "always" 92 | ], 93 | "triple-equals": [ 94 | true, 95 | "allow-null-check" 96 | ], 97 | "typedef-whitespace": [ 98 | true, 99 | { 100 | "call-signature": "nospace", 101 | "index-signature": "nospace", 102 | "parameter": "nospace", 103 | "property-declaration": "nospace", 104 | "variable-declaration": "nospace" 105 | } 106 | ], 107 | "typeof-compare": true, 108 | "unified-signatures": true, 109 | "variable-name": false, 110 | "whitespace": [ 111 | true, 112 | "check-branch", 113 | "check-decl", 114 | "check-operator", 115 | "check-separator", 116 | "check-type" 117 | ], 118 | "directive-selector": [ 119 | true, 120 | "attribute", 121 | "app", 122 | "camelCase" 123 | ], 124 | "component-selector": [ 125 | true, 126 | "element", 127 | "app", 128 | "kebab-case" 129 | ], 130 | "use-input-property-decorator": true, 131 | "use-output-property-decorator": true, 132 | "use-host-property-decorator": true, 133 | "no-input-rename": true, 134 | "no-output-rename": true, 135 | "use-life-cycle-interface": true, 136 | "use-pipe-transform-interface": true, 137 | "component-class-suffix": true, 138 | "directive-class-suffix": true, 139 | "invoke-injectable": true 140 | } 141 | } 142 | --------------------------------------------------------------------------------