ngx-promise-buttons 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/ngx-promise-buttons.mjs +243 -0
- package/fesm2022/ngx-promise-buttons.mjs.map +1 -0
- package/package.json +38 -87
- package/types/ngx-promise-buttons.d.ts +76 -0
- package/.editorconfig +0 -13
- package/.github/FUNDING.yml +0 -12
- package/.travis.yml +0 -21
- package/CHANGELOG.md +0 -0
- package/CONTRIBUTING.md +0 -36
- package/angular.json +0 -180
- package/e2e/protractor.conf.js +0 -32
- package/e2e/src/app.e2e-spec.ts +0 -23
- package/e2e/src/app.po.ts +0 -11
- package/e2e/tsconfig.json +0 -13
- package/logo.png +0 -0
- package/projects/ngx-promise-buttons/karma.conf.js +0 -32
- package/projects/ngx-promise-buttons/ng-package.json +0 -10
- package/projects/ngx-promise-buttons/package.json +0 -26
- package/projects/ngx-promise-buttons/src/default-promise-btn-config.ts +0 -10
- package/projects/ngx-promise-buttons/src/index.ts +0 -2
- package/projects/ngx-promise-buttons/src/promise-btn-config.ts +0 -7
- package/projects/ngx-promise-buttons/src/promise-btn.directive.spec.ts +0 -597
- package/projects/ngx-promise-buttons/src/promise-btn.directive.ts +0 -247
- package/projects/ngx-promise-buttons/src/provider.ts +0 -14
- package/projects/ngx-promise-buttons/src/test.ts +0 -16
- package/projects/ngx-promise-buttons/src/user-cfg.ts +0 -3
- package/projects/ngx-promise-buttons/tsconfig.lib.json +0 -27
- package/projects/ngx-promise-buttons/tsconfig.lib.prod.json +0 -10
- package/projects/ngx-promise-buttons/tsconfig.spec.json +0 -17
- package/projects/ngx-promise-buttons/tslint.json +0 -25
- package/projects/ngx-promise-buttons/yarn.lock +0 -9
- package/projects/ngx-promise-buttons-demo/e2e/protractor.conf.js +0 -30
- package/projects/ngx-promise-buttons-demo/e2e/tsconfig.json +0 -14
- package/projects/ngx-promise-buttons-demo/karma.conf.js +0 -56
- package/projects/ngx-promise-buttons-demo/src/app/app.component.css +0 -6
- package/projects/ngx-promise-buttons-demo/src/app/app.component.html +0 -109
- package/projects/ngx-promise-buttons-demo/src/app/app.component.spec.ts +0 -29
- package/projects/ngx-promise-buttons-demo/src/app/app.component.ts +0 -208
- package/projects/ngx-promise-buttons-demo/src/assets/.gitkeep +0 -0
- package/projects/ngx-promise-buttons-demo/src/environments/environment.prod.ts +0 -3
- package/projects/ngx-promise-buttons-demo/src/environments/environment.ts +0 -8
- package/projects/ngx-promise-buttons-demo/src/favicon.ico +0 -0
- package/projects/ngx-promise-buttons-demo/src/index.html +0 -72
- package/projects/ngx-promise-buttons-demo/src/main.ts +0 -11
- package/projects/ngx-promise-buttons-demo/src/polyfills.ts +0 -63
- package/projects/ngx-promise-buttons-demo/src/styles.scss +0 -135
- package/projects/ngx-promise-buttons-demo/tsconfig.app.json +0 -14
- package/projects/ngx-promise-buttons-demo/tsconfig.spec.json +0 -18
- package/projects/ngx-promise-buttons-demo/tslint.json +0 -156
- package/scripts/copy-readme-to-demo.js +0 -15
- package/tsconfig.build-lib.json +0 -32
- package/tsconfig.json +0 -41
- package/wallaby.js +0 -90
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import {AfterContentInit, Directive, ElementRef, HostListener, Inject, Input, OnDestroy, Optional} from '@angular/core';
|
|
2
|
-
import {Observable, Subscription} from 'rxjs';
|
|
3
|
-
import {DEFAULT_CFG} from './default-promise-btn-config';
|
|
4
|
-
import {PromiseBtnConfig} from './promise-btn-config';
|
|
5
|
-
import {USER_CFG} from "./provider";
|
|
6
|
-
|
|
7
|
-
@Directive({
|
|
8
|
-
selector: '[promiseBtn]',
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
export class PromiseBtnDirective implements OnDestroy, AfterContentInit {
|
|
12
|
-
cfg: PromiseBtnConfig;
|
|
13
|
-
// the timeout used for min duration display
|
|
14
|
-
minDurationTimeout: number;
|
|
15
|
-
// boolean to determine minDurationTimeout state
|
|
16
|
-
isMinDurationTimeoutDone: boolean;
|
|
17
|
-
// boolean to determine if promise was resolved
|
|
18
|
-
isPromiseDone: boolean;
|
|
19
|
-
// the promise button button element
|
|
20
|
-
btnEl: HTMLElement;
|
|
21
|
-
// the promise itself or a function expression
|
|
22
|
-
// NOTE: we need the type any here as we might deal with custom promises like bluebird
|
|
23
|
-
promise: any;
|
|
24
|
-
|
|
25
|
-
// this is added to fix the overriding of the disabled state by the loading indicator button.
|
|
26
|
-
@Input('disabled')
|
|
27
|
-
set isDisabledFromTheOutsideSetter(v: boolean) {
|
|
28
|
-
this.isDisabledFromTheOutside = v;
|
|
29
|
-
if (v) {
|
|
30
|
-
// disabled means always disabled
|
|
31
|
-
this.btnEl.setAttribute('disabled', 'disabled');
|
|
32
|
-
} else if (this.isPromiseDone || this.isPromiseDone === undefined) {
|
|
33
|
-
this.btnEl.removeAttribute('disabled');
|
|
34
|
-
}
|
|
35
|
-
// else the button is loading, so do not change the disabled loading state.
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
isDisabledFromTheOutside: boolean;
|
|
39
|
-
|
|
40
|
-
private _fakePromiseResolve: (value: void) => void;
|
|
41
|
-
|
|
42
|
-
constructor(el: ElementRef,
|
|
43
|
-
@Optional() @Inject(USER_CFG) cfg?: PromiseBtnConfig) {
|
|
44
|
-
// provide configuration
|
|
45
|
-
this.cfg = Object.assign({}, DEFAULT_CFG, cfg);
|
|
46
|
-
|
|
47
|
-
// save element
|
|
48
|
-
this.btnEl = el.nativeElement;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@Input()
|
|
52
|
-
set promiseBtn(passedValue: any) {
|
|
53
|
-
const isObservable: boolean = passedValue instanceof Observable;
|
|
54
|
-
const isSubscription: boolean = passedValue instanceof Subscription;
|
|
55
|
-
const isBoolean: boolean = typeof passedValue === 'boolean';
|
|
56
|
-
const isPromise: boolean = passedValue instanceof Promise || (
|
|
57
|
-
passedValue !== null &&
|
|
58
|
-
typeof passedValue === 'object' &&
|
|
59
|
-
typeof passedValue.then === 'function' &&
|
|
60
|
-
typeof passedValue.catch === 'function'
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
if (isObservable) {
|
|
64
|
-
throw new TypeError('promiseBtn must be an instance of Subscription, instance of Observable given');
|
|
65
|
-
} else if (isSubscription) {
|
|
66
|
-
const sub: Subscription = passedValue;
|
|
67
|
-
if (!sub.closed) {
|
|
68
|
-
this.promise = new Promise((resolve) => {
|
|
69
|
-
sub.add(resolve);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
} else if (isPromise) {
|
|
73
|
-
this.promise = passedValue;
|
|
74
|
-
} else if (isBoolean) {
|
|
75
|
-
this.promise = this.createPromiseFromBoolean(passedValue);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
this.checkAndInitPromiseHandler(this.btnEl);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
ngAfterContentInit() {
|
|
82
|
-
this.prepareBtnEl(this.btnEl);
|
|
83
|
-
// trigger changes once to handle initial promises
|
|
84
|
-
this.checkAndInitPromiseHandler(this.btnEl);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
ngOnDestroy() {
|
|
88
|
-
// cleanup
|
|
89
|
-
if (this.minDurationTimeout) {
|
|
90
|
-
clearTimeout(this.minDurationTimeout);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
createPromiseFromBoolean(val: boolean): Promise<any> {
|
|
95
|
-
if (val) {
|
|
96
|
-
return new Promise((resolve) => {
|
|
97
|
-
this._fakePromiseResolve = resolve;
|
|
98
|
-
});
|
|
99
|
-
} else {
|
|
100
|
-
if (this._fakePromiseResolve) {
|
|
101
|
-
this._fakePromiseResolve();
|
|
102
|
-
}
|
|
103
|
-
return this.promise;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Initializes all html and event handlers
|
|
109
|
-
*/
|
|
110
|
-
prepareBtnEl(btnEl: HTMLElement) {
|
|
111
|
-
// handle promises passed via promiseBtn attribute
|
|
112
|
-
this.appendSpinnerTpl(btnEl);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Checks if all required parameters are there and inits the promise handler
|
|
117
|
-
*/
|
|
118
|
-
checkAndInitPromiseHandler(btnEl: HTMLElement) {
|
|
119
|
-
// check if element and promise is set
|
|
120
|
-
if (btnEl && this.promise) {
|
|
121
|
-
this.initPromiseHandler(btnEl);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Helper FN to add class
|
|
127
|
-
*/
|
|
128
|
-
addLoadingClass(el: any) {
|
|
129
|
-
if (typeof this.cfg.btnLoadingClass === 'string') {
|
|
130
|
-
el.classList.add(this.cfg.btnLoadingClass);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Helper FN to remove classes
|
|
136
|
-
*/
|
|
137
|
-
removeLoadingClass(el: any) {
|
|
138
|
-
if (typeof this.cfg.btnLoadingClass === 'string') {
|
|
139
|
-
el.classList.remove(this.cfg.btnLoadingClass);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Handles everything to be triggered when the button is set
|
|
145
|
-
* to loading state.
|
|
146
|
-
*/
|
|
147
|
-
initLoadingState(btnEl: HTMLElement) {
|
|
148
|
-
this.addLoadingClass(btnEl);
|
|
149
|
-
this.disableBtn(btnEl);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Handles everything to be triggered when loading is finished
|
|
154
|
-
*/
|
|
155
|
-
cancelLoadingStateIfPromiseAndMinDurationDone(btnEl: HTMLElement) {
|
|
156
|
-
if ((!this.cfg.minDuration || this.isMinDurationTimeoutDone) && this.isPromiseDone) {
|
|
157
|
-
this.removeLoadingClass(btnEl);
|
|
158
|
-
this.enableBtn(btnEl);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
disableBtn(btnEl: HTMLElement) {
|
|
163
|
-
if (this.cfg.disableBtn) {
|
|
164
|
-
btnEl.setAttribute('disabled', 'disabled');
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
enableBtn(btnEl: HTMLElement) {
|
|
169
|
-
if (this.cfg.disableBtn) {
|
|
170
|
-
if (this.isDisabledFromTheOutside) {
|
|
171
|
-
btnEl.setAttribute('disabled', 'disabled');
|
|
172
|
-
} else {
|
|
173
|
-
btnEl.removeAttribute('disabled');
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Initializes a watcher for the promise. Also takes
|
|
180
|
-
* this.cfg.minDuration into account if given.
|
|
181
|
-
*/
|
|
182
|
-
|
|
183
|
-
initPromiseHandler(btnEl: HTMLElement) {
|
|
184
|
-
const promise = this.promise;
|
|
185
|
-
|
|
186
|
-
// watch promise to resolve or fail
|
|
187
|
-
this.isMinDurationTimeoutDone = false;
|
|
188
|
-
this.isPromiseDone = false;
|
|
189
|
-
|
|
190
|
-
// create timeout if option is set
|
|
191
|
-
if (this.cfg.minDuration) {
|
|
192
|
-
this.minDurationTimeout = window.setTimeout(() => {
|
|
193
|
-
this.isMinDurationTimeoutDone = true;
|
|
194
|
-
this.cancelLoadingStateIfPromiseAndMinDurationDone(btnEl);
|
|
195
|
-
}, this.cfg.minDuration);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const resolveLoadingState = () => {
|
|
199
|
-
this.isPromiseDone = true;
|
|
200
|
-
this.cancelLoadingStateIfPromiseAndMinDurationDone(btnEl);
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
if (!this.cfg.handleCurrentBtnOnly) {
|
|
204
|
-
this.initLoadingState(btnEl);
|
|
205
|
-
}
|
|
206
|
-
// native Promise doesn't have finally
|
|
207
|
-
if (promise.finally) {
|
|
208
|
-
promise.finally(resolveLoadingState);
|
|
209
|
-
} else {
|
|
210
|
-
promise
|
|
211
|
-
.then(resolveLoadingState)
|
|
212
|
-
.catch(resolveLoadingState);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* $compile and append the spinner template to the button.
|
|
220
|
-
*/
|
|
221
|
-
appendSpinnerTpl(btnEl: HTMLElement) {
|
|
222
|
-
// TODO add some kind of compilation later on
|
|
223
|
-
btnEl.insertAdjacentHTML('beforeend', this.cfg.spinnerTpl as string);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Limit loading state to show only for the currently clicked button.
|
|
228
|
-
* Executed only if this.cfg.handleCurrentBtnOnly is set
|
|
229
|
-
*/
|
|
230
|
-
@HostListener('click')
|
|
231
|
-
handleCurrentBtnOnly() {
|
|
232
|
-
if (!this.cfg.handleCurrentBtnOnly) {
|
|
233
|
-
return true; // return true for testing
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Click triggers @Input update
|
|
237
|
-
// We need to use timeout to wait for @Input to update
|
|
238
|
-
window.setTimeout(() => {
|
|
239
|
-
// return if something else than a promise is passed
|
|
240
|
-
if (!this.promise) {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
this.initLoadingState(this.btnEl);
|
|
245
|
-
}, 0);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { InjectionToken, EnvironmentProviders, makeEnvironmentProviders, Optional, SkipSelf, inject } from '@angular/core';
|
|
2
|
-
import { PromiseBtnConfig } from './promise-btn-config';
|
|
3
|
-
|
|
4
|
-
export const USER_CFG = new InjectionToken<PromiseBtnConfig>('Promise Button Config');
|
|
5
|
-
|
|
6
|
-
export const DEFAULT_CONFIG: PromiseBtnConfig = {
|
|
7
|
-
// default values
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export function provideNgxPromiseButtons(config: PromiseBtnConfig = DEFAULT_CONFIG): EnvironmentProviders {
|
|
11
|
-
return makeEnvironmentProviders([
|
|
12
|
-
{ provide: USER_CFG, useValue: { ...DEFAULT_CONFIG, ...config } }
|
|
13
|
-
]);
|
|
14
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
|
2
|
-
|
|
3
|
-
import 'zone.js';
|
|
4
|
-
import 'zone.js/dist/async-test.js';
|
|
5
|
-
import 'zone.js/dist/proxy.js';
|
|
6
|
-
import 'zone.js/dist/sync-test';
|
|
7
|
-
import 'zone.js/dist/jasmine-patch';
|
|
8
|
-
|
|
9
|
-
import {getTestBed} from '@angular/core/testing';
|
|
10
|
-
import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing';
|
|
11
|
-
|
|
12
|
-
// First, initialize the Angular testing environment.
|
|
13
|
-
getTestBed().initTestEnvironment(
|
|
14
|
-
BrowserDynamicTestingModule,
|
|
15
|
-
platformBrowserDynamicTesting()
|
|
16
|
-
);
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "../../out-tsc/lib",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"inlineSources": true,
|
|
7
|
-
"types": [],
|
|
8
|
-
"lib": [
|
|
9
|
-
"dom",
|
|
10
|
-
"es2018"
|
|
11
|
-
]
|
|
12
|
-
},
|
|
13
|
-
"angularCompilerOptions": {
|
|
14
|
-
"annotateForClosureCompiler": false,
|
|
15
|
-
"skipTemplateCodegen": true,
|
|
16
|
-
"strictMetadataEmit": true,
|
|
17
|
-
"fullTemplateTypeCheck": true,
|
|
18
|
-
"strictInjectionParameters": true,
|
|
19
|
-
"enableResourceInlining": true,
|
|
20
|
-
"enableIvy": true,
|
|
21
|
-
"allowEmptyCodegenFiles": true,
|
|
22
|
-
},
|
|
23
|
-
"exclude": [
|
|
24
|
-
"src/test.ts",
|
|
25
|
-
"**/*.spec.ts"
|
|
26
|
-
]
|
|
27
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../ngx-promise-buttons-demo/tslint.json",
|
|
3
|
-
"rules": {
|
|
4
|
-
"directive-selector": [
|
|
5
|
-
false,
|
|
6
|
-
"attribute",
|
|
7
|
-
"lib",
|
|
8
|
-
"camelCase"
|
|
9
|
-
],
|
|
10
|
-
"component-selector": [
|
|
11
|
-
false,
|
|
12
|
-
"element",
|
|
13
|
-
"lib",
|
|
14
|
-
"kebab-case"
|
|
15
|
-
],
|
|
16
|
-
"variable-name": [
|
|
17
|
-
true,
|
|
18
|
-
"allow-pascal-case",
|
|
19
|
-
"allow-snake-case",
|
|
20
|
-
"ban-keywords",
|
|
21
|
-
"check-format",
|
|
22
|
-
"allow-leading-underscore"
|
|
23
|
-
]
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
2
|
-
# yarn lockfile v1
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"@ctrl/tinycolor@^2.6.0":
|
|
6
|
-
version "2.6.0"
|
|
7
|
-
resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-2.6.0.tgz#c269def5ed1f871913f299a475c01bdb39119eee"
|
|
8
|
-
integrity sha512-bvkszNAcbmR2zrjjkaHbTVbEj07Id44HsBWf57mugPcvJNIPaWLqxWV/GUJVJuXXayqFP2X09cZRqKrCy/v10Q==
|
|
9
|
-
|
|
@@ -1,30 +0,0 @@
|
|
|
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
|
-
beforeLaunch: function() {
|
|
23
|
-
require('ts-node').register({
|
|
24
|
-
project: 'e2e/tsconfig.e2e.json'
|
|
25
|
-
});
|
|
26
|
-
},
|
|
27
|
-
onPrepare() {
|
|
28
|
-
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
|
29
|
-
}
|
|
30
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
|
2
|
-
{
|
|
3
|
-
"extends": "../../../tsconfig.json",
|
|
4
|
-
"compilerOptions": {
|
|
5
|
-
"outDir": "../../../out-tsc/e2e",
|
|
6
|
-
"module": "commonjs",
|
|
7
|
-
"target": "es2018",
|
|
8
|
-
"types": [
|
|
9
|
-
"jasmine",
|
|
10
|
-
"jasminewd2",
|
|
11
|
-
"node"
|
|
12
|
-
]
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// Karma configuration file, see link for more information
|
|
2
|
-
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
|
3
|
-
|
|
4
|
-
module.exports = function (config) {
|
|
5
|
-
config.set({
|
|
6
|
-
basePath: '../..',
|
|
7
|
-
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
|
8
|
-
plugins: [
|
|
9
|
-
require('karma-jasmine'),
|
|
10
|
-
require('karma-chrome-launcher'),
|
|
11
|
-
require('karma-jasmine-html-reporter'),
|
|
12
|
-
require('karma-coverage-istanbul-reporter'),
|
|
13
|
-
require('@angular-devkit/build-angular/plugins/karma')
|
|
14
|
-
],
|
|
15
|
-
client: {
|
|
16
|
-
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
17
|
-
},
|
|
18
|
-
coverageIstanbulReporter: {
|
|
19
|
-
dir: require('path').join(__dirname, '../coverage'),
|
|
20
|
-
reports: ['html', 'lcovonly'],
|
|
21
|
-
fixWebpackSourcePaths: true
|
|
22
|
-
},
|
|
23
|
-
reporters: ['progress', 'kjhtml'],
|
|
24
|
-
port: 9876,
|
|
25
|
-
colors: true,
|
|
26
|
-
logLevel: config.LOG_INFO,
|
|
27
|
-
autoWatch: false,
|
|
28
|
-
browsers: ['ChromeHeadless'],
|
|
29
|
-
singleRun: true,
|
|
30
|
-
customLaunchers: {
|
|
31
|
-
'ChromeHeadless': {
|
|
32
|
-
base: 'Chrome',
|
|
33
|
-
flags: [
|
|
34
|
-
// We must disable the Chrome sandbox when running Chrome inside Docker
|
|
35
|
-
// (Chrome's sandbox needs more permissions than Docker allows by default)
|
|
36
|
-
'--headless',
|
|
37
|
-
'--no-sandbox',
|
|
38
|
-
'--disable-gpu',
|
|
39
|
-
'--no-default-browser-check',
|
|
40
|
-
'--no-first-run',
|
|
41
|
-
'--disable-default-apps',
|
|
42
|
-
'--disable-popup-blocking',
|
|
43
|
-
'--disable-translate',
|
|
44
|
-
'--disable-background-timer-throttling',
|
|
45
|
-
'--disable-renderer-backgrounding',
|
|
46
|
-
'--disable-device-discovery-notifications',
|
|
47
|
-
// Without a remote debugging port, Google Chrome exits immediately.
|
|
48
|
-
'--remote-debugging-port=9222',
|
|
49
|
-
'--disable-web-security',
|
|
50
|
-
],
|
|
51
|
-
debug: true
|
|
52
|
-
}
|
|
53
|
-
},
|
|
54
|
-
browserNoActivityTimeout: 120000,
|
|
55
|
-
});
|
|
56
|
-
};
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
<button class="btn btn-raised"
|
|
2
|
-
(click)="success($event)"
|
|
3
|
-
[promiseBtn]="successPromise">Success after delay
|
|
4
|
-
</button>
|
|
5
|
-
<button class="btn btn-raised"
|
|
6
|
-
(click)="error()"
|
|
7
|
-
[promiseBtn]="errorPromise">Error after delay
|
|
8
|
-
</button>
|
|
9
|
-
<br>
|
|
10
|
-
<br>
|
|
11
|
-
<button class="btn btn-raised"
|
|
12
|
-
(click)="endless()"
|
|
13
|
-
[promiseBtn]="endlessPromise">Never resolving promise
|
|
14
|
-
</button>
|
|
15
|
-
<button class="btn btn-raised"
|
|
16
|
-
[promiseBtn]="endlessInitialPromise">Loading initially and forever
|
|
17
|
-
</button>
|
|
18
|
-
|
|
19
|
-
<h3>Same promise buttons</h3>
|
|
20
|
-
<button class="btn btn-raised"
|
|
21
|
-
(click)="success($event)"
|
|
22
|
-
[promiseBtn]="successPromise">We
|
|
23
|
-
</button>
|
|
24
|
-
<button class="btn btn-raised"
|
|
25
|
-
(click)="success($event)"
|
|
26
|
-
[promiseBtn]="successPromise">share
|
|
27
|
-
</button>
|
|
28
|
-
|
|
29
|
-
<h3>Chained promise buttons</h3>
|
|
30
|
-
<button class="btn btn-raised"
|
|
31
|
-
(click)="chain()"
|
|
32
|
-
[promiseBtn]="chainedPromises">Load promise chain {{ promiseIndex }}
|
|
33
|
-
</button>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<h3>Inside a form</h3>
|
|
37
|
-
<form (submit)="submit()"
|
|
38
|
-
novalidate>
|
|
39
|
-
<button class="btn btn-raised"
|
|
40
|
-
type="submit"
|
|
41
|
-
[promiseBtn]="submitPromise">Submit
|
|
42
|
-
</button>
|
|
43
|
-
</form>
|
|
44
|
-
|
|
45
|
-
<div>
|
|
46
|
-
<h2>Observable</h2>
|
|
47
|
-
|
|
48
|
-
<button class="btn btn-raised"
|
|
49
|
-
(click)="initSuccessObservable()"
|
|
50
|
-
[promiseBtn]="successObservable">Success after delay
|
|
51
|
-
</button>
|
|
52
|
-
<button class="btn btn-raised"
|
|
53
|
-
(click)="initErrorObservable()"
|
|
54
|
-
[promiseBtn]="errorObservable">Error after delay
|
|
55
|
-
</button>
|
|
56
|
-
<br>
|
|
57
|
-
<br>
|
|
58
|
-
<button class="btn btn-raised"
|
|
59
|
-
(click)="initEndlessObservable()"
|
|
60
|
-
[promiseBtn]="endlessObservable">Never resolving Observable
|
|
61
|
-
</button>
|
|
62
|
-
<button class="btn btn-raised"
|
|
63
|
-
[promiseBtn]="endlessInitialObservable">Loading initially and forever
|
|
64
|
-
</button>
|
|
65
|
-
|
|
66
|
-
<h3>Same observable buttons</h3>
|
|
67
|
-
<button class="btn btn-raised"
|
|
68
|
-
(click)="initSuccessObservable()"
|
|
69
|
-
[promiseBtn]="successObservable">We
|
|
70
|
-
</button>
|
|
71
|
-
<button class="btn btn-raised"
|
|
72
|
-
(click)="initSuccessObservable()"
|
|
73
|
-
[promiseBtn]="successObservable">share
|
|
74
|
-
</button>
|
|
75
|
-
|
|
76
|
-
<h3>Chained observable button</h3>
|
|
77
|
-
<button class="btn btn-raised"
|
|
78
|
-
(click)="initChainedObservable()"
|
|
79
|
-
[promiseBtn]="chainedObservable">Observable chain {{ chainedObservableValue }}
|
|
80
|
-
</button>
|
|
81
|
-
</div>
|
|
82
|
-
|
|
83
|
-
<div>
|
|
84
|
-
<h2>Simple Boolean</h2>
|
|
85
|
-
<button class="btn btn-raised"
|
|
86
|
-
(click)="myBool=!myBool">Toggle loading ({{myBool}})
|
|
87
|
-
</button>
|
|
88
|
-
|
|
89
|
-
<button class="btn btn-raised"
|
|
90
|
-
[promiseBtn]="myBool">My Boolean Btn {{myBool}}
|
|
91
|
-
</button>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
<div>
|
|
96
|
-
<h2>Dynamic [disabled] </h2>
|
|
97
|
-
|
|
98
|
-
<button class="btn btn-raised"
|
|
99
|
-
(click)="isOutsideDisabled=!isOutsideDisabled">Toggle disabled via [disabled]={{isOutsideDisabled}}
|
|
100
|
-
</button>
|
|
101
|
-
|
|
102
|
-
<button class="btn btn-raised"
|
|
103
|
-
(click)="myBoolWithCustomDisabled=!myBoolWithCustomDisabled">Toggle promise button
|
|
104
|
-
</button>
|
|
105
|
-
|
|
106
|
-
<button class="btn btn-raised"
|
|
107
|
-
[disabled]="isOutsideDisabled"
|
|
108
|
-
[promiseBtn]="myBoolWithCustomDisabled">This is the button</button>
|
|
109
|
-
</div>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {async, TestBed} from '@angular/core/testing';
|
|
2
|
-
import {AppComponent} from './app.component';
|
|
3
|
-
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
|
4
|
-
|
|
5
|
-
// @Directive({
|
|
6
|
-
// selector: '[promiseBtn]'
|
|
7
|
-
// })
|
|
8
|
-
// class MockPromiseBtnDirective {
|
|
9
|
-
// @Input('promiseBtn') promise: Promise<any>;
|
|
10
|
-
// }
|
|
11
|
-
|
|
12
|
-
describe('AppComponent', () => {
|
|
13
|
-
beforeEach(async(() => {
|
|
14
|
-
TestBed.configureTestingModule({
|
|
15
|
-
declarations: [
|
|
16
|
-
AppComponent,
|
|
17
|
-
// MockPromiseBtnDirective
|
|
18
|
-
],
|
|
19
|
-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
20
|
-
}).compileComponents();
|
|
21
|
-
}));
|
|
22
|
-
|
|
23
|
-
it('should create the app', async(() => {
|
|
24
|
-
const fixture = TestBed.createComponent(AppComponent);
|
|
25
|
-
const app = fixture.debugElement.componentInstance;
|
|
26
|
-
expect(app).toBeTruthy();
|
|
27
|
-
}));
|
|
28
|
-
});
|
|
29
|
-
|