;
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 |
16 |
17 |
26 |
27 |
28 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
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 |
82 | Loading start (actionDelay: 0ms)
83 |
84 |
85 | Loading stop (actionDelay: 0ms, hideDelay: 200ms)
86 |
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 |
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 |
10 |
11 |
15 |
18 |
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 |
12 |
13 |
14 |
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 |
14 |
15 |
16 |
17 |
18 |
Loading ? : {{ loader.isLoading('myLoaderMulti2') ? 'Yes!' : 'Nope.' }}
19 |
20 |
23 |
24 |
25 |
26 |
27 |
Loading ? : {{ loader.isLoading('myLoaderMulti3') ? 'Yes!' : 'Nope.' }}
28 |
29 |
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 |
64 | Loading start (actionDelay:0ms)
65 |
66 |
67 | Loading stop (actionDelay: 0ms,hideDelay: 200ms)
68 |
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 |
24 | `;
25 |
26 | this.code.two = `
27 |
28 |
31 | `;
32 |
33 | this.code.three = `
34 |
35 |
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 |
--------------------------------------------------------------------------------