1 | import { EventEmitter, Injector, ElementRef, TemplateRef, ɵɵdefineInjectable, ɵɵinject, ComponentFactoryResolver, NgZone, INJECTOR, ApplicationRef, Injectable } from '@angular/core';
|
2 | import { listenToTriggersV2, registerOutsideClick, registerEscClick } from 'ngx-bootstrap/utils';
|
3 | import { PositioningService } from 'ngx-bootstrap/positioning';
|
4 |
|
5 | class BsComponentRef {
|
6 | }
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | class ContentRef {
|
13 | constructor(
|
14 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
15 | nodes, viewRef,
|
16 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
17 | componentRef) {
|
18 | this.nodes = nodes;
|
19 | this.viewRef = viewRef;
|
20 | this.componentRef = componentRef;
|
21 | }
|
22 | }
|
23 |
|
24 |
|
25 | class ComponentLoader {
|
26 | |
27 |
|
28 |
|
29 |
|
30 |
|
31 | constructor(_viewContainerRef, _renderer, _elementRef, _injector, _componentFactoryResolver, _ngZone, _applicationRef, _posService) {
|
32 | this._viewContainerRef = _viewContainerRef;
|
33 | this._renderer = _renderer;
|
34 | this._elementRef = _elementRef;
|
35 | this._injector = _injector;
|
36 | this._componentFactoryResolver = _componentFactoryResolver;
|
37 | this._ngZone = _ngZone;
|
38 | this._applicationRef = _applicationRef;
|
39 | this._posService = _posService;
|
40 | this.onBeforeShow = new EventEmitter();
|
41 | this.onShown = new EventEmitter();
|
42 | this.onBeforeHide = new EventEmitter();
|
43 | this.onHidden = new EventEmitter();
|
44 | this._providers = [];
|
45 | this._isHiding = false;
|
46 | |
47 |
|
48 |
|
49 | this.containerDefaultSelector = 'body';
|
50 | this._listenOpts = {};
|
51 | this._globalListener = Function.prototype;
|
52 | }
|
53 | get isShown() {
|
54 | if (this._isHiding) {
|
55 | return false;
|
56 | }
|
57 | return !!this._componentRef;
|
58 | }
|
59 | attach(compType) {
|
60 | this._componentFactory = this._componentFactoryResolver
|
61 | .resolveComponentFactory(compType);
|
62 | return this;
|
63 | }
|
64 |
|
65 | to(container) {
|
66 | this.container = container || this.container;
|
67 | return this;
|
68 | }
|
69 | position(opts) {
|
70 | if (!opts) {
|
71 | return this;
|
72 | }
|
73 | this.attachment = opts.attachment || this.attachment;
|
74 | this._elementRef = opts.target || this._elementRef;
|
75 | return this;
|
76 | }
|
77 | provide(provider) {
|
78 | this._providers.push(provider);
|
79 | return this;
|
80 | }
|
81 |
|
82 | show(opts = {}) {
|
83 | this._subscribePositioning();
|
84 | this._innerComponent = void 0;
|
85 | if (!this._componentRef) {
|
86 | this.onBeforeShow.emit();
|
87 | this._contentRef = this._getContentRef(opts.content, opts.context, opts.initialState);
|
88 | const injector = Injector.create({
|
89 | providers: this._providers,
|
90 | parent: this._injector
|
91 | });
|
92 | if (!this._componentFactory) {
|
93 | return;
|
94 | }
|
95 | this._componentRef = this._componentFactory.create(injector, this._contentRef.nodes);
|
96 | this._applicationRef.attachView(this._componentRef.hostView);
|
97 |
|
98 |
|
99 | this.instance = this._componentRef.instance;
|
100 | Object.assign(this._componentRef.instance, opts);
|
101 | if (this.container instanceof ElementRef) {
|
102 | this.container.nativeElement.appendChild(this._componentRef.location.nativeElement);
|
103 | }
|
104 | if (typeof this.container === 'string' && typeof document !== 'undefined') {
|
105 | const selectedElement = document.querySelector(this.container) ||
|
106 | document.querySelector(this.containerDefaultSelector);
|
107 | if (!selectedElement) {
|
108 | return;
|
109 | }
|
110 | selectedElement.appendChild(this._componentRef.location.nativeElement);
|
111 | }
|
112 | if (!this.container &&
|
113 | this._elementRef &&
|
114 | this._elementRef.nativeElement.parentElement) {
|
115 | this._elementRef.nativeElement.parentElement.appendChild(this._componentRef.location.nativeElement);
|
116 | }
|
117 |
|
118 |
|
119 |
|
120 |
|
121 | if (this._contentRef.componentRef) {
|
122 | this._innerComponent = this._contentRef.componentRef.instance;
|
123 | this._contentRef.componentRef.changeDetectorRef.markForCheck();
|
124 | this._contentRef.componentRef.changeDetectorRef.detectChanges();
|
125 | }
|
126 | this._componentRef.changeDetectorRef.markForCheck();
|
127 | this._componentRef.changeDetectorRef.detectChanges();
|
128 | this.onShown.emit(opts.id ? { id: opts.id } : this._componentRef.instance);
|
129 | }
|
130 | this._registerOutsideClick();
|
131 | return this._componentRef;
|
132 | }
|
133 | hide(id) {
|
134 | var _a, _b, _c;
|
135 | if (!this._componentRef) {
|
136 | return this;
|
137 | }
|
138 | this._posService.deletePositionElement(this._componentRef.location);
|
139 | this.onBeforeHide.emit(this._componentRef.instance);
|
140 | const componentEl = this._componentRef.location.nativeElement;
|
141 | componentEl.parentNode.removeChild(componentEl);
|
142 | if ((_a = this._contentRef) === null || _a === void 0 ? void 0 : _a.componentRef) {
|
143 | this._contentRef.componentRef.destroy();
|
144 | }
|
145 | if (this._viewContainerRef && ((_b = this._contentRef) === null || _b === void 0 ? void 0 : _b.viewRef)) {
|
146 | this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._contentRef.viewRef));
|
147 | }
|
148 | if ((_c = this._contentRef) === null || _c === void 0 ? void 0 : _c.viewRef) {
|
149 | this._contentRef.viewRef.destroy();
|
150 | }
|
151 | this._contentRef = void 0;
|
152 | this._componentRef = void 0;
|
153 | this._removeGlobalListener();
|
154 | this.onHidden.emit(id ? { id } : null);
|
155 | return this;
|
156 | }
|
157 | toggle() {
|
158 | if (this.isShown) {
|
159 | this.hide();
|
160 | return;
|
161 | }
|
162 | this.show();
|
163 | }
|
164 | dispose() {
|
165 | if (this.isShown) {
|
166 | this.hide();
|
167 | }
|
168 | this._unsubscribePositioning();
|
169 | if (this._unregisterListenersFn) {
|
170 | this._unregisterListenersFn();
|
171 | }
|
172 | }
|
173 | listen(listenOpts) {
|
174 | var _a;
|
175 | this.triggers = listenOpts.triggers || this.triggers;
|
176 | this._listenOpts.outsideClick = listenOpts.outsideClick;
|
177 | this._listenOpts.outsideEsc = listenOpts.outsideEsc;
|
178 | listenOpts.target = listenOpts.target || ((_a = this._elementRef) === null || _a === void 0 ? void 0 : _a.nativeElement);
|
179 | const hide = (this._listenOpts.hide = () => listenOpts.hide ? listenOpts.hide() : void this.hide());
|
180 | const show = (this._listenOpts.show = (registerHide) => {
|
181 | listenOpts.show ? listenOpts.show(registerHide) : this.show(registerHide);
|
182 | registerHide();
|
183 | });
|
184 |
|
185 | const toggle = (registerHide) => {
|
186 | this.isShown ? hide() : show(registerHide);
|
187 | };
|
188 | if (this._renderer) {
|
189 | this._unregisterListenersFn = listenToTriggersV2(this._renderer, {
|
190 | target: listenOpts.target,
|
191 | triggers: listenOpts.triggers,
|
192 | show,
|
193 | hide,
|
194 | toggle
|
195 | });
|
196 | }
|
197 | return this;
|
198 | }
|
199 | _removeGlobalListener() {
|
200 | if (this._globalListener) {
|
201 | this._globalListener();
|
202 | this._globalListener = Function.prototype;
|
203 | }
|
204 | }
|
205 | attachInline(vRef,
|
206 |
|
207 | template) {
|
208 | if (vRef && template) {
|
209 | this._inlineViewRef = vRef.createEmbeddedView(template);
|
210 | }
|
211 | return this;
|
212 | }
|
213 | _registerOutsideClick() {
|
214 | if (!this._componentRef || !this._componentRef.location) {
|
215 | return;
|
216 | }
|
217 |
|
218 | if (this._listenOpts.outsideClick) {
|
219 | const target = this._componentRef.location.nativeElement;
|
220 | setTimeout(() => {
|
221 | if (this._renderer && this._elementRef) {
|
222 | this._globalListener = registerOutsideClick(this._renderer, {
|
223 | targets: [target, this._elementRef.nativeElement],
|
224 | outsideClick: this._listenOpts.outsideClick,
|
225 | hide: () => this._listenOpts.hide && this._listenOpts.hide()
|
226 | });
|
227 | }
|
228 | });
|
229 | }
|
230 | if (this._listenOpts.outsideEsc && this._renderer && this._elementRef) {
|
231 | const target = this._componentRef.location.nativeElement;
|
232 | this._globalListener = registerEscClick(this._renderer, {
|
233 | targets: [target, this._elementRef.nativeElement],
|
234 | outsideEsc: this._listenOpts.outsideEsc,
|
235 | hide: () => this._listenOpts.hide && this._listenOpts.hide()
|
236 | });
|
237 | }
|
238 | }
|
239 | getInnerComponent() {
|
240 | return this._innerComponent;
|
241 | }
|
242 | _subscribePositioning() {
|
243 | if (this._zoneSubscription || !this.attachment) {
|
244 | return;
|
245 | }
|
246 | this.onShown.subscribe(() => {
|
247 | var _a;
|
248 | this._posService.position({
|
249 | element: (_a = this._componentRef) === null || _a === void 0 ? void 0 : _a.location,
|
250 | target: this._elementRef,
|
251 | attachment: this.attachment,
|
252 | appendToBody: this.container === 'body'
|
253 | });
|
254 | });
|
255 | this._zoneSubscription = this._ngZone.onStable.subscribe(() => {
|
256 | if (!this._componentRef) {
|
257 | return;
|
258 | }
|
259 | this._posService.calcPosition();
|
260 | });
|
261 | }
|
262 | _unsubscribePositioning() {
|
263 | if (!this._zoneSubscription) {
|
264 | return;
|
265 | }
|
266 | this._zoneSubscription.unsubscribe();
|
267 | this._zoneSubscription = void 0;
|
268 | }
|
269 | _getContentRef(
|
270 |
|
271 | content,
|
272 |
|
273 | context,
|
274 |
|
275 | initialState) {
|
276 | if (!content) {
|
277 | return new ContentRef([]);
|
278 | }
|
279 | if (content instanceof TemplateRef) {
|
280 | if (this._viewContainerRef) {
|
281 | const _viewRef = this._viewContainerRef
|
282 | .createEmbeddedView(content, context);
|
283 | _viewRef.markForCheck();
|
284 | return new ContentRef([_viewRef.rootNodes], _viewRef);
|
285 | }
|
286 | const viewRef = content.createEmbeddedView({});
|
287 | this._applicationRef.attachView(viewRef);
|
288 | return new ContentRef([viewRef.rootNodes], viewRef);
|
289 | }
|
290 | if (typeof content === 'function') {
|
291 | const contentCmptFactory = this._componentFactoryResolver.resolveComponentFactory(content);
|
292 | const modalContentInjector = Injector.create({
|
293 | providers: this._providers,
|
294 | parent: this._injector
|
295 | });
|
296 | const componentRef = contentCmptFactory.create(modalContentInjector);
|
297 | Object.assign(componentRef.instance, initialState);
|
298 | this._applicationRef.attachView(componentRef.hostView);
|
299 | return new ContentRef([[componentRef.location.nativeElement]], componentRef.hostView, componentRef);
|
300 | }
|
301 | const nodes = this._renderer
|
302 | ? [this._renderer.createText(`${content}`)]
|
303 | : [];
|
304 | return new ContentRef([nodes]);
|
305 | }
|
306 | }
|
307 |
|
308 | class ComponentLoaderFactory {
|
309 | constructor(_componentFactoryResolver, _ngZone, _injector, _posService, _applicationRef) {
|
310 | this._componentFactoryResolver = _componentFactoryResolver;
|
311 | this._ngZone = _ngZone;
|
312 | this._injector = _injector;
|
313 | this._posService = _posService;
|
314 | this._applicationRef = _applicationRef;
|
315 | }
|
316 | |
317 |
|
318 |
|
319 |
|
320 |
|
321 |
|
322 | createLoader(_elementRef, _viewContainerRef, _renderer) {
|
323 | return new ComponentLoader(_viewContainerRef, _renderer, _elementRef, this._injector, this._componentFactoryResolver, this._ngZone, this._applicationRef, this._posService);
|
324 | }
|
325 | }
|
326 | ComponentLoaderFactory.ɵprov = ɵɵdefineInjectable({ factory: function ComponentLoaderFactory_Factory() { return new ComponentLoaderFactory(ɵɵinject(ComponentFactoryResolver), ɵɵinject(NgZone), ɵɵinject(INJECTOR), ɵɵinject(PositioningService), ɵɵinject(ApplicationRef)); }, token: ComponentLoaderFactory, providedIn: "root" });
|
327 | ComponentLoaderFactory.decorators = [
|
328 | { type: Injectable, args: [{ providedIn: 'root' },] }
|
329 | ];
|
330 | ComponentLoaderFactory.ctorParameters = () => [
|
331 | { type: ComponentFactoryResolver },
|
332 | { type: NgZone },
|
333 | { type: Injector },
|
334 | { type: PositioningService },
|
335 | { type: ApplicationRef }
|
336 | ];
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 | export { BsComponentRef, ComponentLoader, ComponentLoaderFactory, ContentRef };
|
343 |
|