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

atinc / ngx-tethys / 68ef226c-f83e-44c1-b8ed-e420a83c5d84

28 May 2025 10:31AM UTC coverage: 10.352% (-80.0%) from 90.316%
68ef226c-f83e-44c1-b8ed-e420a83c5d84

Pull #3460

circleci

pubuzhixing8
chore: xxx
Pull Request #3460: refactor(icon): migrate signal input #TINFR-1476

132 of 6823 branches covered (1.93%)

Branch coverage included in aggregate %.

10 of 14 new or added lines in 1 file covered. (71.43%)

11648 existing lines in 344 files now uncovered.

2078 of 14525 relevant lines covered (14.31%)

6.69 hits per line

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

0.86
/src/fullscreen/fullscreen-ref.ts
1
import { coerceElement } from '@angular/cdk/coercion';
2
import { ESCAPE } from '@angular/cdk/keycodes';
3
import { DOCUMENT } from '@angular/common';
4
import { ElementRef, Inject, NgZone } from '@angular/core';
5
import { fromEvent, merge, Observable, Subject } from 'rxjs';
6
import { takeUntil } from 'rxjs/operators';
7
import { ThyFullscreenConfig, ThyFullscreenMode } from './fullscreen.config';
8

9
export class ThyFullscreenRef<TResult = unknown> {
UNCOV
10
    fullscreenConfig: ThyFullscreenConfig;
×
UNCOV
11

×
UNCOV
12
    private isFullscreen = false;
×
UNCOV
13

×
UNCOV
14
    private ngUnsubscribe$ = new Subject<void>();
×
UNCOV
15

×
UNCOV
16
    private readonly _afterLaunched = new Subject<TResult>();
×
UNCOV
17

×
UNCOV
18
    private readonly _afterExited = new Subject<TResult>();
×
UNCOV
19

×
20
    constructor(
21
        @Inject(DOCUMENT) protected document: Document,
22
        private ngZone: NgZone
23
    ) {}
24

UNCOV
25
    private onFullscreenChange() {
×
UNCOV
26
        const isFullScreen = this.isImmersiveFullscreen();
×
27
        if (isFullScreen) {
×
28
            this.launchNormalFullscreen();
29
        } else {
UNCOV
30
            this.exitNormalFullscreen();
×
31
        }
32
    }
33

UNCOV
34
    private resetElement(element: string | Element | ElementRef) {
×
UNCOV
35
        const targetType = typeof element;
×
36
        if (targetType === 'string') {
×
37
            return this.document.querySelector(`.${element}`);
38
        } else {
UNCOV
39
            return coerceElement(element);
×
40
        }
41
    }
42

UNCOV
43
    private isImmersiveFullscreen() {
×
UNCOV
44
        const doc = this.document;
×
45
        return !!(doc['fullscreenElement'] || doc['mozFullScreenElement'] || doc['webkitFullscreenElement'] || doc['msFullscreenElement']);
46
    }
UNCOV
47

×
UNCOV
48
    private handleKeyDown = (event: KeyboardEvent): void => {
×
UNCOV
49
        if (event.keyCode === ESCAPE) {
×
UNCOV
50
            if (this.isFullscreen && this.fullscreenConfig.mode === ThyFullscreenMode.emulated) {
×
UNCOV
51
                this.ngZone.run(() => this.exitNormalFullscreen());
×
UNCOV
52
            }
×
UNCOV
53
        }
×
UNCOV
54
    };
×
UNCOV
55

×
UNCOV
56
    private launchNormalFullscreen() {
×
UNCOV
57
        const targetElement = this.resetElement(this.fullscreenConfig.target);
×
UNCOV
58
        const classes = this.fullscreenConfig.targetLaunchedClass;
×
59
        const container = this.fullscreenConfig.emulatedContainer;
60
        if (container) {
UNCOV
61
            const containerElement = this.resetElement(container);
×
62
            const containerClientRect = containerElement.getBoundingClientRect();
UNCOV
63
            const targetClientRect = targetElement.getBoundingClientRect();
×
UNCOV
64
            const distanceX = containerClientRect.left - targetClientRect.left;
×
UNCOV
65
            const distanceY = containerClientRect.top - targetClientRect.top;
×
66
            targetElement.style.transform = `translate(${distanceX}px, ${distanceY}px)`;
UNCOV
67
            targetElement.style.width = `${containerClientRect.width}px`;
×
UNCOV
68
            targetElement.style.height = `${containerClientRect.height}px`;
×
69
        } else {
70
            targetElement.classList.add('thy-fullscreen');
UNCOV
71
        }
×
UNCOV
72
        targetElement.classList.add('thy-fullscreen-active');
×
UNCOV
73
        if (classes && classes.length) {
×
UNCOV
74
            targetElement.classList.add(classes);
×
UNCOV
75
        }
×
UNCOV
76
        this.isFullscreen = true;
×
UNCOV
77
        this._afterLaunched.next(undefined);
×
78
    }
79

UNCOV
80
    private exitNormalFullscreen() {
×
81
        const targetElement = this.resetElement(this.fullscreenConfig.target);
UNCOV
82
        const classes = this.fullscreenConfig.targetLaunchedClass;
×
UNCOV
83
        const container = this.fullscreenConfig.emulatedContainer;
×
UNCOV
84
        if (container) {
×
85
            targetElement.style.transform = ``;
UNCOV
86
            targetElement.style.width = ``;
×
UNCOV
87
            targetElement.style.height = ``;
×
UNCOV
88
        } else {
×
UNCOV
89
            targetElement.classList.remove('thy-fullscreen');
×
UNCOV
90
        }
×
91
        targetElement.classList.remove('thy-fullscreen-active');
92
        if (classes && classes.length) {
UNCOV
93
            targetElement.classList.remove(classes);
×
UNCOV
94
        }
×
95

96
        this.isFullscreen = false;
97
        this._afterExited.next(undefined);
UNCOV
98
        this._afterExited.complete();
×
99

100
        this.ngUnsubscribe$.next();
101
        this.ngUnsubscribe$.complete();
102
    }
103

104
    protected launchImmersiveFullscreen() {
UNCOV
105
        const { documentElement } = this.document;
×
106

107
        const requestFullscreen: HTMLElement['requestFullscreen'] | undefined =
108
            documentElement.requestFullscreen ||
109
            documentElement['mozRequestFullScreen'] ||
×
110
            documentElement['webkitRequestFullscreen'] ||
×
111
            documentElement['msRequestFullscreen'];
×
112

×
113
        if (typeof requestFullscreen === 'function') {
114
            // Note: the `requestFullscreen` returns a promise that resolves when the full screen is initiated.
115
            // The promise may reject with a `fullscreen error`. The browser warns into the console before rejecting:
UNCOV
116
            // `Failed to execute ‘requestFullScreen’ on ‘Element’: API can only be initiated by a user gesture.`.
×
UNCOV
117
            // We explicitly call `catch` and redirect the rejection to `console.error`.
×
118
            // Otherwise, this fill fail in unit tests with the following error:
119
            // `An error was thrown in afterAll. Unhandled promise rejection: TypeError: fullscreen error`.
UNCOV
120
            requestFullscreen.call(documentElement)?.catch(console.error);
×
121
        }
UNCOV
122
    }
×
123

124
    protected exitImmersiveFullscreen() {
UNCOV
125
        const { document } = this;
×
UNCOV
126

×
127
        const exitFullscreen: Document['exitFullscreen'] | undefined =
128
            document.exitFullscreen || document['mozCancelFullScreen'] || document['webkitExitFullscreen'] || document['msExitFullscreen'];
129

UNCOV
130
        if (typeof exitFullscreen === 'function') {
×
131
            exitFullscreen.call(document)?.catch(console.error);
×
132
        }
133
    }
UNCOV
134

×
135
    launch() {
136
        if (this.fullscreenConfig.mode === ThyFullscreenMode.immersive) {
137
            merge(
138
                fromEvent(this.document, 'fullscreenchange'),
×
139
                fromEvent(this.document, 'MSFullscreenChange'),
140
                fromEvent(this.document, 'webkitfullscreenchange')
UNCOV
141
            )
×
142
                .pipe(takeUntil(this.ngUnsubscribe$))
143
                .subscribe(() => {
1✔
144
                    this.onFullscreenChange();
145
                });
146
            this.launchImmersiveFullscreen();
147
        } else {
148
            this.ngZone.runOutsideAngular(() =>
149
                fromEvent<KeyboardEvent>(this.document, 'keydown').pipe(takeUntil(this.ngUnsubscribe$)).subscribe(this.handleKeyDown)
150
            );
151

152
            this.launchNormalFullscreen();
153
        }
154
    }
155

156
    exit() {
157
        if (this.fullscreenConfig.mode === ThyFullscreenMode.immersive) {
158
            this.exitImmersiveFullscreen();
159
        } else {
160
            this.exitNormalFullscreen();
161
        }
162
    }
163

164
    afterLaunched(): Observable<TResult> {
165
        return this._afterLaunched.asObservable();
166
    }
167

168
    afterExited(): Observable<TResult> {
169
        return this._afterExited.asObservable();
170
    }
171
}
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