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

atinc / ngx-tethys / d9ae709b-3c27-4b69-b125-b8b80b54f90b

pending completion
d9ae709b-3c27-4b69-b125-b8b80b54f90b

Pull #2757

circleci

mengshuicmq
fix: fix code review
Pull Request #2757: feat(color-picker): color-picker support disabled (#INFR-8645)

98 of 6315 branches covered (1.55%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

2392 of 13661 relevant lines covered (17.51%)

83.12 hits per line

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

7.81
/src/back-top/back-top.component.ts
1
import {
2
    Component,
3
    OnInit,
4
    ChangeDetectionStrategy,
5
    ViewEncapsulation,
6
    Input,
7
    TemplateRef,
8
    EventEmitter,
9
    Output,
10
    HostBinding,
11
    NgZone,
12
    ChangeDetectorRef,
13
    OnDestroy,
14
    OnChanges,
1✔
15
    Inject,
16
    ViewChild,
×
17
    ElementRef
18
} from '@angular/core';
19
import { Subject, fromEvent, BehaviorSubject, EMPTY, Observable } from 'rxjs';
×
20
import { Platform } from '@angular/cdk/platform';
×
21
import { throttleTime, takeUntil, switchMap } from 'rxjs/operators';
×
22
import { DOCUMENT, NgIf, NgTemplateOutlet } from '@angular/common';
×
23
import { fadeMotion, InputNumber, ThyScrollService } from 'ngx-tethys/core';
×
24
import { ThyIconComponent } from 'ngx-tethys/icon';
×
25

×
26
/**
×
27
 * 回到顶部组件
×
28
 * @name thy-back-top
×
29
 */
30
@Component({
31
    selector: 'thy-back-top,[thyBackTop]',
32
    templateUrl: './back-top.component.html',
33
    changeDetection: ChangeDetectionStrategy.OnPush,
34
    encapsulation: ViewEncapsulation.None,
35
    animations: [fadeMotion],
×
36
    standalone: true,
×
37
    imports: [NgIf, ThyIconComponent, NgTemplateOutlet]
×
38
})
×
39
export class ThyBackTopComponent implements OnInit, OnDestroy, OnChanges {
×
40
    @HostBinding('class.thy-back-top-container') classNames = true;
×
41

×
42
    /**
43
     * 自定义按钮显示模板
44
     */
×
45
    @Input() thyTemplate?: TemplateRef<void>;
×
46

×
47
    /**
48
     * 指定对哪个 DOM 元素返回顶部
49
     * @type string | HTMLElement
50
     * @default window
51
     */
×
52
    @Input() thyContainer?: string | HTMLElement;
53

54
    /**
×
55
     * 滚动高度达到此参数值才出现 thy-back-top
56
     * @type number
57
     */
×
58
    @Input() @InputNumber() thyVisibilityHeight = 400;
×
59

60
    /**
×
61
     * 点击按钮的回调函数
×
62
     */
×
63
    @Output() readonly thyClick: EventEmitter<boolean> = new EventEmitter();
×
64

×
65
    /**
66
     * 监听按钮显示状态的回调函数
67
     */
68
    @Output() public visibleChange: EventEmitter<boolean> = new EventEmitter();
69

×
70
    /** The native `<div class="thy-back-top"></div>` element. */
×
71
    @ViewChild('backTop', { static: false })
72
    set backTop(backTop: ElementRef<HTMLElement> | undefined) {
×
73
        this.backTop$.next(backTop);
×
74
    }
×
75

×
76
    public visible = false;
77

×
78
    /**
79
     * The subject used to store the native `<div class="thy-back-top"></div>` since
80
     * it's located within the `ngIf` directive. It might be set asynchronously whenever the condition
81
     * is met. Having subject makes the code reactive and cancellable (e.g. event listeners will be
×
82
     * automatically removed and re-added through the `switchMap` below).
×
83
     */
84
    private backTop$ = new BehaviorSubject<ElementRef<HTMLElement> | undefined>(undefined);
85

×
86
    private destroy$ = new Subject<void>();
×
87
    private scrollListenerDestroy$ = new Subject<void>();
×
88

×
89
    private target: HTMLElement | null = null;
90

91
    constructor(
1✔
92
        @Inject(DOCUMENT) private doc: any,
93
        private thyScrollService: ThyScrollService,
94
        private platform: Platform,
95
        private cdr: ChangeDetectorRef,
96
        private zone: NgZone
97
    ) {
98
        this.backTop$
1✔
99
            .pipe(
100
                switchMap(backTop =>
101
                    backTop
102
                        ? new Observable(subscriber =>
103
                              zone.runOutsideAngular(() => fromEvent(backTop.nativeElement, 'click').subscribe(subscriber))
104
                          )
105
                        : EMPTY
106
                ),
107
                takeUntil(this.destroy$)
108
            )
1✔
109
            .subscribe(() => {
110
                this.thyScrollService.scrollTo(this.getTarget(), 0);
111
                if (this.thyClick.observers.length) {
112
                    zone.run(() => this.thyClick.emit(true));
1✔
113
                }
114
            });
115
    }
116

117
    ngOnInit(): void {
118
        this.registerScrollEvent();
119
    }
120

121
    private getTarget(): HTMLElement | Window {
122
        return this.target || window;
123
    }
124

125
    private handleScroll(): void {
126
        if (this.visible === this.thyScrollService.getScroll(this.getTarget()) > this.thyVisibilityHeight) {
127
            return;
128
        }
129
        this.visible = !this.visible;
130
        this.cdr.detectChanges();
131
        if (this.visibleChange.observers.length > 0) {
132
            this.zone.run(() => {
133
                this.visibleChange.emit(this.visible);
134
            });
135
        }
136
    }
137

138
    private registerScrollEvent(): void {
139
        if (!this.platform.isBrowser) {
140
            return;
141
        }
142
        this.scrollListenerDestroy$.next();
143
        this.handleScroll();
144
        this.zone.runOutsideAngular(() => {
145
            fromEvent(this.getTarget(), 'scroll', { passive: true })
146
                .pipe(throttleTime(50), takeUntil(this.scrollListenerDestroy$))
147
                .subscribe(() => this.handleScroll());
148
        });
149
    }
150

151
    ngOnDestroy(): void {
152
        this.destroy$.next();
153
        this.scrollListenerDestroy$.next();
154
    }
155

156
    ngOnChanges(changes: any): void {
157
        const { thyContainer } = changes;
158
        if (thyContainer) {
159
            this.target = typeof this.thyContainer === 'string' ? this.doc.querySelector(this.thyContainer) : this.thyContainer;
160
            this.registerScrollEvent();
161
        }
162
    }
163
}
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