@euro-ombudsman/ngx-modal-dialog 13.2.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Greentube I.E.S. GmbH
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,269 @@
1
+ # ngx modal dialog
2
+ [![Build Status](https://travis-ci.org/Greentube/ngx-modal.svg?branch=master)](https://travis-ci.org/Greentube/ngx-modal)
3
+ [![npm version](https://img.shields.io/npm/v/ngx-modal-dialog.svg)](https://www.npmjs.com/package/ngx-modal-dialog)
4
+ > Dynamic modal dialog for Angular that does not sit on DOM waiting to be triggered, but rather gets injected upon need.
5
+
6
+ Made with Bootstrap 4 styles in mind, but configurable to any framework or custom set of styles.
7
+ Simple demo can be found [here](https://greentube.github.io/ngx-modal/demo).
8
+
9
+ > This documentation is for version 4.x.x and Angular 10+. If you are using older version of Angular please use [3.x version for v6-v8](https://github.com/Greentube/ngx-modal/tree/v3.x.x) or [2.x version for v2-v5](https://github.com/Greentube/ngx-modal/tree/v2.x.x).
10
+
11
+ # Table of contents:
12
+ - [Installation](#installation)
13
+ - [How it works](#how-it-works)
14
+ - [Styles and visuals](#styles-and-visuals)
15
+ - [Usage](#usage)
16
+ - [API](#api)
17
+ - [ModalDialogService](#modaldialogservice)
18
+ - [IModalDialog](#imodaldialog)
19
+ - [IModalDialogOptions](#imodaldialogoptions)
20
+ - [IModalDialogButton](#imodaldialogbutton)
21
+ - [IModalDialogSettings](#imodaldialogsettings)
22
+ - [License](#license)
23
+
24
+ ## Installation
25
+
26
+ ```
27
+ npm install --save ngx-modal-dialog
28
+ ```
29
+ ## How it works
30
+ Modal dialog uses `ComponentFactoryResolver` to inject the given child component to the dialog.
31
+ [ModalDialogService](#modaldialogservice) makes sure that only one instance of a modal dialog is opened at a time.
32
+ With [IModalDialogOptions](#imodaldialogoptions) you can define which component will be rendered inside the dialog and configure it based on your needs.
33
+
34
+ You can further use action buttons to control modal dialog from external component or child component. If action performed on button click is successful, modal dialog will close. Otherwise it will alert user.
35
+
36
+ ## Styles and visuals
37
+
38
+ `Ngx-modal-dialog` is intended to be used with Bootstrap 4, however you can apply your custom styles from your desired UI framework by providing class names in [IModalDialogSettings](#imodaldialogsettings).
39
+
40
+ ## Usage
41
+
42
+ 1. Include the `ngx-modal` module in your application at any place. The recommended way is to add `forRoot` initialization in the main app module.
43
+ ```ts
44
+ import { BrowserModule } from '@angular/platform-browser';
45
+ import { ModalDialogModule } from 'ngx-modal-dialog';
46
+
47
+ @NgModule({
48
+ imports: [
49
+ BrowserModule,
50
+ ModalDialogModule.forRoot()
51
+ ],
52
+ bootstrap: [AppComponent]
53
+ })
54
+ export class AppModule { }
55
+ ```
56
+ 2. Create a custom component that implements `IModalDialog` or use the `SimpleModalDialog` as a child component.
57
+
58
+ Custom component should be inserted into both `declarations` and `entryComponents` in the NgModule they are part of. `entryComponents` has to be used since component is dynamically inserted onto the page and Angular is not aware of it.
59
+
60
+ 3. Inject the `ModalDialogService` where you want to open the dialog. Call `openDialog` passing parent `ViewContainerRef` and partial `IModalDialogOptions` object:
61
+ ```ts
62
+ constructor(modalService: ModalDialogService, viewRef: ViewContainerRef) { }
63
+
64
+ openNewDialog() {
65
+ this.modalService.openDialog(this.viewRef, {
66
+ title: 'Some modal title',
67
+ childComponent: SimpleModalComponent
68
+ });
69
+ }
70
+ ```
71
+ 4. Arbitrary define `actionButtons` in modal dialog options or child component to control modal dialog.
72
+
73
+ ```ts
74
+ class MyModalComponent implements IModalDialog {
75
+ actionButtons: IModalDialogButton[];
76
+
77
+ constructor() {
78
+ this.actionButtons = [
79
+ { text: 'Close' }, // no special processing here
80
+ { text: 'I will always close', onAction: () => true },
81
+ { text: 'I never close', onAction: () => false }
82
+ ];
83
+ }
84
+
85
+ dialogInit(reference: ComponentRef<IModalDialog>, options: Partial<IModalDialogOptions<any>>) {
86
+ // no processing needed
87
+ }
88
+ }
89
+ ```
90
+
91
+ Action button can be of two types:
92
+ - with return value
93
+ Used for controlling the dialog life.
94
+ If value is `truthful` (true, successful Promise or Observable) than it will close the dialog
95
+ If value is `falsy` (false, rejected Promise or failed Observable) it will trigger alert style and not close the dialog.
96
+ - without return value
97
+ Has no direct effect on dialog. Can be used to trigger some arbitrary functionality (e.g. copy values to clipboard)
98
+
99
+ ## API
100
+
101
+ ### ModalDialogService
102
+ #### Methods:
103
+ - `openDialog(target: ViewContainerRef, options: Partial<IModalDialogOptions<T>> = {})`: Closes existing and opens a new modal dialog according to IModalDialogOptions.
104
+ `T` represents a type of options `data` field. If you don't care about strong typing just pass `any`.
105
+
106
+ ### IModalDialog
107
+ Every component that is used as modal dialog must implement `IModalDialog`.
108
+ #### Methods:
109
+ - `dialogInit(reference: ComponentRef<IModalDialog>, options: Partial<IModalDialogOptions<any>>) => void`
110
+ Mandatory: `true`
111
+ Default: -
112
+ This method is called after initialization of child component. Purpose of the method is to pass necessary information from outer scope to child component.
113
+ #### Properties:
114
+ - `actionButtons`
115
+ Mandatory: `false`
116
+ Default: -
117
+ Type: `string`
118
+ Modal heading text
119
+
120
+ ### IModalDialogOptions
121
+ #### Interface:
122
+ ```ts
123
+ interface IModalDialogOptions<T> {
124
+ title: string;
125
+ childComponent: IModalDialog;
126
+ onClose: ModalDialogOnAction;
127
+ actionButtons: IModalDialogButton[];
128
+ data: T;
129
+ placeOnTop: boolean;
130
+ settings: IModalDialogSettings;
131
+ closeDialogSubject: Subject<void>;
132
+ }
133
+ ```
134
+ This is generic interface, where `T` is arbitrary type of `data` section.
135
+ #### Interface details:
136
+ - title: `string`
137
+ Modal heading text
138
+
139
+ - childComponent: `any`
140
+ Component type that will be rendered as a content of modal dialog. Component must implement `IModalDialog` interface.
141
+
142
+ - onClose(): `ModalDialogOnAction`
143
+ Function to be called on close button click. In case of Promise and Observable, modal dialog will not close unless successful resolve happens. In case of boolean, modal dialog will close only if result is `truthful`.
144
+
145
+ - actionButtons: `Array<IModalDialogButton>`
146
+ Footer action buttons for control of modal dialog. See [IModalDialogButton](#imodaldialogbutton).
147
+ Action buttons defined in child component have priority over action buttons defined via options.
148
+ Action buttons close the modal dialog upon successful operation.
149
+
150
+ - data: `T`
151
+ Arbitrary data that will be passed to child component via `dialogInit` method.
152
+
153
+ - placeOnTop: `boolean`
154
+ Flag stating whether opening the modal dialog should close all the other modal dialogs, or modal should be rendered on top of existing ones.
155
+
156
+
157
+ - settings: `IModalDialogSettings`
158
+ Additional settings for granular configuration of modal dialog. See [IModalDialogSettings](#imodaldialogsettings).
159
+
160
+ - closeDialogSubject:`Subject<void>`
161
+ Custom modal closing subject. Can be used to manually trigger modal dialog close from within the child component.
162
+
163
+ ### IModalDialogButton
164
+ #### Interface:
165
+ ```ts
166
+ interface IModalDialogButton {
167
+ text: string;
168
+ buttonClass?: string;
169
+ onAction?: ModalDialogOnAction;
170
+ }
171
+ ```
172
+ #### Interface details:
173
+ - text: `string`
174
+ Caption/text on the button
175
+ - buttonClass: `string`
176
+ Default: `btn btn-primary`
177
+ Class name of button
178
+ - onAction(): `Promise<any> | Observable<any> | boolean`
179
+ Function to be called on button click. In case of Promise and Observable, modal dialog will not close unless successful resolve happens. In case of boolean, modal dialog will close only if result is `truthful`.
180
+ #### ModalDialogOnAction type
181
+ ```ts
182
+ type ModalDialogOnAction = () => Promise<any> | Observable<any> | boolean | void;
183
+ ```
184
+ Function returning Promise, Observable, boolean or no value. Modal dialog will close automatically if return of action is:
185
+ * Promise, once promise gets resolved
186
+ * Observable, once observable successfully finishes
187
+ * boolean and value is `true`
188
+
189
+ Action button will initiate alert behavior if return is:
190
+ * Promise, once promise gets rejected
191
+ * Observable, once observable fails or throws error
192
+ * boolean and value is `false`
193
+
194
+ If action button returns `void`, there are no side effects.
195
+
196
+ ### IModalDialogSettings
197
+ #### Interface
198
+ ```ts
199
+ interface IModalDialogSettings {
200
+ overlayClass: string;
201
+ overlayAnimationTriggerClass: string;
202
+ modalClass: string;
203
+ modalAnimationTriggerClass: string;
204
+ contentClass: string;
205
+ headerClass: string;
206
+ headerTitleClass: string;
207
+ closeButtonClass: string;
208
+ closeButtonTitle: string;
209
+ bodyClass: string;
210
+ footerClass: string;
211
+ alertClass: string;
212
+ alertDuration: number;
213
+ buttonClass: string;
214
+ notifyWithAlert: boolean;
215
+ }
216
+ ```
217
+
218
+ #### Interface details:
219
+ - overlayClass: `string`
220
+ Default: `modal-backdrop fade show`
221
+ Style of the backdrop overlay layer
222
+ - overlayAnimationTriggerClass: `string`
223
+ Default: `show`
224
+ Class that triggers the initial/ending animation of modal overlay
225
+ - modalClass: `string`
226
+ Default: `modal fade ngx-modal`
227
+ Style of modal wrapper
228
+ - modalAnimationTriggerClass: `string`
229
+ Default: `show`
230
+ Class that triggers the initial/ending animation of modal wrapper
231
+ - modalDialogClass: `string`
232
+ Default: `modal-dialog modal-dialog-centered`
233
+ Style of modal dialog
234
+ - contentClass: `string`
235
+ Default: `modal-content`
236
+ Modal dialog inner content class
237
+ - headerClass: `string`
238
+ Default: `modal-header`
239
+ Modal dialog header class
240
+ - headerTitleClass: `string`
241
+ Default: `modal-title`
242
+ Modal dialog header title class
243
+ - closeButtonClass: `string`
244
+ Default: `close glyphicon glyphicon-remove`
245
+ Modal dialog header close button class
246
+ - closeButtonTitle: `string`
247
+ Default: `CLOSE`
248
+ Close button title
249
+ - bodyClass: `string`
250
+ Default: `modal-body`
251
+ Modal dialog body class
252
+ - footerClass: `string`
253
+ Default: `modal-footer`
254
+ Modal dialog footer class
255
+ - alertClass: `string`
256
+ Default: `ngx-modal-shake`
257
+ Style to be appended to dialog once alert happens
258
+ - alertDuration: `number`
259
+ Default: `250`
260
+ Duration of alert animation
261
+ - buttonClass: `string`
262
+ Default: `btn btn-primary`
263
+ Style of footer action buttons
264
+ - notifyWithAlert: `number`
265
+ Default: `true`
266
+ Define whether modal should alert user when action fails
267
+
268
+ ## License
269
+ Licensed under MIT
package/demo/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # Demo
2
+
3
+ This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.8.
4
+
5
+ ## Development server
6
+
7
+ Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
8
+
9
+ ## Code scaffolding
10
+
11
+ Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12
+
13
+ ## Build
14
+
15
+ Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
16
+
17
+ ## Running unit tests
18
+
19
+ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20
+
21
+ ## Running end-to-end tests
22
+
23
+ Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
24
+
25
+ ## Further help
26
+
27
+ To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './public-api';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXVyby1vbWJ1ZHNtYW4tbmd4LW1vZGFsLWRpYWxvZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ldXJvLW9tYnVkc21hbi1uZ3gtbW9kYWwtZGlhbG9nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxjQUFjLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vcHVibGljLWFwaSc7XG4iXX0=
@@ -0,0 +1,44 @@
1
+ import { Injectable } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ export class ModalDialogInstanceService {
4
+ constructor() {
5
+ /**
6
+ * Used to make sure there is exactly one instance of Modal Dialog
7
+ */
8
+ this.componentRefs = [];
9
+ }
10
+ /**
11
+ * Closes existing modal dialog
12
+ */
13
+ closeAnyExistingModalDialog() {
14
+ while (this.componentRefs.length) {
15
+ this.componentRefs[this.componentRefs.length - 1].destroy();
16
+ }
17
+ }
18
+ /**
19
+ * Save component ref for future comparison
20
+ * @param componentRef
21
+ */
22
+ saveExistingModalDialog(componentRef) {
23
+ // remove overlay from top element
24
+ this.setOverlayForTopDialog(false);
25
+ // add new component
26
+ this.componentRefs = [...this.componentRefs, componentRef];
27
+ componentRef.instance.showOverlay = true;
28
+ componentRef.onDestroy(() => {
29
+ this.componentRefs.pop();
30
+ this.setOverlayForTopDialog(true);
31
+ });
32
+ }
33
+ setOverlayForTopDialog(value) {
34
+ if (this.componentRefs.length) {
35
+ this.componentRefs[this.componentRefs.length - 1].instance.showOverlay = value;
36
+ }
37
+ }
38
+ }
39
+ ModalDialogInstanceService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModalDialogInstanceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
40
+ ModalDialogInstanceService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModalDialogInstanceService });
41
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ModalDialogInstanceService, decorators: [{
42
+ type: Injectable
43
+ }] });
44
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kYWwtZGlhbG9nLWluc3RhbmNlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbW9kYWwtZGlhbG9nLWluc3RhbmNlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFnQixVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBSXpELE1BQU0sT0FBTywwQkFBMEI7SUFEdkM7UUFFRTs7V0FFRztRQUNLLGtCQUFhLEdBQXlDLEVBQUUsQ0FBQztLQWlDbEU7SUEvQkM7O09BRUc7SUFDSCwyQkFBMkI7UUFDekIsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRTtZQUNoQyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1NBQzdEO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNILHVCQUF1QixDQUFDLFlBQWdEO1FBQ3RFLGtDQUFrQztRQUNsQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbkMsb0JBQW9CO1FBQ3BCLElBQUksQ0FBQyxhQUFhLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFDM0QsWUFBWSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1FBRXpDLFlBQVksQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQzFCLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDekIsSUFBSSxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3BDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELHNCQUFzQixDQUFDLEtBQWM7UUFDbkMsSUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRTtZQUM3QixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO1NBQ2hGO0lBQ0gsQ0FBQzs7dUhBcENVLDBCQUEwQjsySEFBMUIsMEJBQTBCOzJGQUExQiwwQkFBMEI7a0JBRHRDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnRSZWYsIEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE1vZGFsRGlhbG9nQ29tcG9uZW50IH0gZnJvbSAnLi9tb2RhbC1kaWFsb2cuY29tcG9uZW50JztcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIE1vZGFsRGlhbG9nSW5zdGFuY2VTZXJ2aWNlIHtcbiAgLyoqXG4gICAqIFVzZWQgdG8gbWFrZSBzdXJlIHRoZXJlIGlzIGV4YWN0bHkgb25lIGluc3RhbmNlIG9mIE1vZGFsIERpYWxvZ1xuICAgKi9cbiAgcHJpdmF0ZSBjb21wb25lbnRSZWZzOiBDb21wb25lbnRSZWY8TW9kYWxEaWFsb2dDb21wb25lbnQ+W10gPSBbXTtcblxuICAvKipcbiAgICogQ2xvc2VzIGV4aXN0aW5nIG1vZGFsIGRpYWxvZ1xuICAgKi9cbiAgY2xvc2VBbnlFeGlzdGluZ01vZGFsRGlhbG9nKCkge1xuICAgIHdoaWxlICh0aGlzLmNvbXBvbmVudFJlZnMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmNvbXBvbmVudFJlZnNbdGhpcy5jb21wb25lbnRSZWZzLmxlbmd0aCAtIDFdLmRlc3Ryb3koKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2F2ZSBjb21wb25lbnQgcmVmIGZvciBmdXR1cmUgY29tcGFyaXNvblxuICAgKiBAcGFyYW0gY29tcG9uZW50UmVmXG4gICAqL1xuICBzYXZlRXhpc3RpbmdNb2RhbERpYWxvZyhjb21wb25lbnRSZWY6IENvbXBvbmVudFJlZjxNb2RhbERpYWxvZ0NvbXBvbmVudD4pIHtcbiAgICAvLyByZW1vdmUgb3ZlcmxheSBmcm9tIHRvcCBlbGVtZW50XG4gICAgdGhpcy5zZXRPdmVybGF5Rm9yVG9wRGlhbG9nKGZhbHNlKTtcbiAgICAvLyBhZGQgbmV3IGNvbXBvbmVudFxuICAgIHRoaXMuY29tcG9uZW50UmVmcyA9IFsuLi50aGlzLmNvbXBvbmVudFJlZnMsIGNvbXBvbmVudFJlZl07XG4gICAgY29tcG9uZW50UmVmLmluc3RhbmNlLnNob3dPdmVybGF5ID0gdHJ1ZTtcblxuICAgIGNvbXBvbmVudFJlZi5vbkRlc3Ryb3koKCkgPT4ge1xuICAgICAgdGhpcy5jb21wb25lbnRSZWZzLnBvcCgpO1xuICAgICAgdGhpcy5zZXRPdmVybGF5Rm9yVG9wRGlhbG9nKHRydWUpO1xuICAgIH0pO1xuICB9XG5cbiAgc2V0T3ZlcmxheUZvclRvcERpYWxvZyh2YWx1ZTogYm9vbGVhbikge1xuICAgIGlmICh0aGlzLmNvbXBvbmVudFJlZnMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmNvbXBvbmVudFJlZnNbdGhpcy5jb21wb25lbnRSZWZzLmxlbmd0aCAtIDFdLmluc3RhbmNlLnNob3dPdmVybGF5ID0gdmFsdWU7XG4gICAgfVxuICB9XG59XG4iXX0=