• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atinc / ngx-tethys / 85b806b8-794f-4793-b127-9b12bd4fc630

21 Nov 2024 08:14AM UTC coverage: 90.325% (-0.02%) from 90.343%
85b806b8-794f-4793-b127-9b12bd4fc630

Pull #3264

circleci

web-flow
Merge branch 'master' into xl/#TINFR-602
Pull Request #3264: feat(dialog): support overlay toTop with dialogRef(#TINFR-602)

5531 of 6774 branches covered (81.65%)

Branch coverage included in aggregate %.

6 of 6 new or added lines in 4 files covered. (100.0%)

4 existing lines in 3 files now uncovered.

13243 of 14011 relevant lines covered (94.52%)

993.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.02
/src/dialog/dialog.service.ts
1
import { ThyAbstractOverlayRef, ThyAbstractOverlayService, ThyClickPositioner } from 'ngx-tethys/core';
2
import { of } from 'rxjs';
3

4
import { Directionality } from '@angular/cdk/bidi';
5
import { Overlay, OverlayConfig, OverlayContainer, OverlayKeyboardDispatcher, OverlayRef } from '@angular/cdk/overlay';
6
import { ComponentPortal, ComponentType } from '@angular/cdk/portal';
7
import { Injectable, Injector, OnDestroy, StaticProvider, TemplateRef, inject } from '@angular/core';
8

9
import { isString } from 'ngx-tethys/util';
10
import { ThyConfirmConfig } from './confirm.config';
11
import { THY_CONFIRM_COMPONENT_TOKEN, ThyConfirmAbstractComponent } from './confirm/token';
12
import { ThyDialogContainer } from './dialog-container.component';
13
import { ThyAbstractDialog, ThyDialogRef, ThyInternalDialogRef } from './dialog-ref';
14
import { THY_DIALOG_DEFAULT_OPTIONS, ThyDialogConfig, ThyDialogSizes } from './dialog.config';
15
import { dialogAbstractOverlayOptions } from './dialog.options';
16

17
/**
18
 * @public
1✔
19
 * @order 10
20
 */
111✔
21
@Injectable()
111✔
22
export class ThyDialog extends ThyAbstractOverlayService<ThyDialogConfig, ThyDialogContainer> implements OnDestroy {
111✔
23
    private confirmComponentType = inject<ComponentType<ThyConfirmAbstractComponent>>(THY_CONFIRM_COMPONENT_TOKEN);
111✔
24

111✔
25
    private overlayKeyboardDispatcher = inject(OverlayKeyboardDispatcher);
26

27
    private overlayContainer = inject(OverlayContainer);
111✔
28

111✔
29
    private abstractDialog: ThyAbstractDialog = {
195✔
30
        toTop: (id: string) => this.toTop(id)
31
    };
32

111✔
33
    protected buildOverlayConfig(config: ThyDialogConfig<any>): OverlayConfig {
111✔
34
        const size = config.size || ThyDialogSizes.md;
111✔
35
        const overlayConfig = this.buildBaseOverlayConfig(config, [`dialog-${size}`]);
36
        overlayConfig.positionStrategy = this.overlay.position().global();
37
        overlayConfig.scrollStrategy = config.scrollStrategy || this.overlay.scrollStrategies.block();
111✔
38
        return overlayConfig;
39
    }
40

110✔
41
    protected attachOverlayContainer(overlay: OverlayRef, config: ThyDialogConfig<any>): ThyDialogContainer {
110✔
42
        const userInjector = config && config.viewContainerRef && config.viewContainerRef.injector;
43
        const injector = Injector.create({
44
            parent: userInjector || this.injector,
45
            providers: [{ provide: ThyDialogConfig, useValue: config }]
46
        });
47
        const containerPortal = new ComponentPortal(ThyDialogContainer, config.viewContainerRef, injector);
48
        const containerRef = overlay.attach<ThyDialogContainer>(containerPortal);
110!
49

2✔
50
        return containerRef.instance;
51
    }
52

53
    protected createAbstractOverlayRef<T, TResult>(
54
        overlayRef: OverlayRef,
55
        containerInstance: ThyDialogContainer,
56
        config: ThyDialogConfig<any>
57
    ): ThyAbstractOverlayRef<T, ThyDialogContainer, TResult> {
110✔
58
        return new ThyInternalDialogRef(overlayRef, containerInstance, config, this.abstractDialog);
59
    }
60

112✔
61
    protected createInjector<T>(config: ThyDialogConfig, dialogRef: ThyDialogRef<T>, dialogContainer: ThyDialogContainer): Injector {
112✔
62
        const userInjector = config && config.viewContainerRef && config.viewContainerRef.injector;
112✔
63

112✔
64
        const injectionTokens: StaticProvider[] = [
112✔
65
            { provide: ThyDialogContainer, useValue: dialogContainer },
112✔
66
            {
112✔
67
                provide: ThyDialogRef,
112✔
68
                useValue: dialogRef
112✔
UNCOV
69
            }
×
70
        ];
71

112✔
72
        if (config.direction && (!userInjector || !userInjector.get<Directionality | null>(Directionality, null))) {
73
            injectionTokens.push({
74
                provide: Directionality,
75
                useValue: {
76
                    value: config.direction,
77
                    change: of()
112✔
78
                }
111✔
79
            });
111✔
80
        }
111✔
81

82
        return Injector.create({ parent: userInjector || this.injector, providers: injectionTokens });
83
    }
84

85
    constructor() {
86
        const overlay = inject(Overlay);
10✔
87
        const injector = inject(Injector);
88
        const defaultConfig = inject(THY_DIALOG_DEFAULT_OPTIONS, { optional: true })!;
89
        const clickPositioner = inject(ThyClickPositioner);
90

91
        super(dialogAbstractOverlayOptions, overlay, injector, defaultConfig);
92
        clickPositioner.initialize();
93
    }
94

95
    /**
96
     * 打开 Dialog
2✔
97
     */
98
    open<T, TData = unknown, TResult = unknown>(
99
        componentOrTemplateRef: ComponentType<T> | TemplateRef<T>,
100
        config?: ThyDialogConfig<TData>
101
    ): ThyDialogRef<T, TResult> {
102
        const dialogRef = this.openOverlay(componentOrTemplateRef, config);
1✔
103
        const dialogRefInternal = dialogRef as ThyInternalDialogRef<T, TResult>;
104
        dialogRefInternal.updateSizeAndPosition(
105
            dialogRef.containerInstance.config.width,
106
            dialogRef.containerInstance.config.height,
107
            dialogRef.containerInstance.config.position
108
        );
109
        return dialogRef as ThyDialogRef<T, TResult>;
7✔
110
    }
7✔
111

18✔
112
    /**
113
     * 打开 Confirm
7✔
114
     */
1✔
115
    confirm(options: ThyConfirmConfig) {
116
        return this.open(this.confirmComponentType, {
6✔
117
            initialState: {
118
                options: options
119
            }
120
        });
121
    }
122

123
    /**
1!
124
     * 根据 id 获取 Dialog
1✔
125
     */
126
    getDialogById(id: string): ThyDialogRef<any> | undefined {
UNCOV
127
        return this.getAbstractOverlayById(id) as ThyDialogRef<any> | undefined;
×
128
    }
129

1!
130
    /**
1✔
131
     * 获取所有打开的 Dialog
1✔
132
     */
1✔
133
    getOpenedDialogs(): ThyDialogRef<any>[] {
1✔
134
        return this.getAbstractOverlays();
1✔
135
    }
1✔
136

2!
137
    /**
138
     * @description.en-us Finds the closest ThyDialogRef to an element by looking at the DOM.
139
     * @description 获取与指定元素最接近的 ThyDialogRef
140
     */
114✔
141
    getClosestDialog(element: HTMLElement): ThyDialogRef<any> | undefined {
142
        let parent: HTMLElement | null = element.parentElement;
1✔
143

144
        while (parent && !parent.classList.contains('thy-dialog-container')) {
1✔
145
            parent = parent.parentElement;
146
        }
147
        if (parent && parent.id) {
148
            return this.getDialogById(parent.id);
149
        }
150
        return null;
151
    }
152

153
    /**
154
     * Update dialog to top
155
     */
156
    toTop(idOrOverlayRef: string | ThyDialogRef<unknown, ThyDialogContainer>) {
157
        let dialogRef: ThyAbstractOverlayRef<unknown, ThyDialogContainer>;
158
        if (isString(idOrOverlayRef)) {
159
            dialogRef = this.openedOverlays.find(item => item.id === idOrOverlayRef);
160
        } else {
161
            dialogRef = idOrOverlayRef;
162
        }
163
        if (dialogRef) {
164
            const overlayRef = dialogRef.getOverlayRef();
165
            const containerElement = this.overlayContainer.getContainerElement();
166
            containerElement.appendChild(overlayRef.backdropElement);
167
            containerElement.appendChild(overlayRef.hostElement);
168
            this.overlayKeyboardDispatcher.remove(overlayRef);
169
            this.overlayKeyboardDispatcher.add(overlayRef);
170
            this.openedOverlays = [...(this.openedOverlays || []).filter(item => item.id !== dialogRef?.id), dialogRef];
171
        }
172
    }
173

174
    ngOnDestroy() {
175
        this.dispose();
176
    }
177
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc