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

atinc / ngx-tethys / c0ef8457-a839-451f-8b72-80fd73106231

02 Apr 2024 02:27PM UTC coverage: 90.524% (-0.06%) from 90.585%
c0ef8457-a839-451f-8b72-80fd73106231

Pull #3062

circleci

minlovehua
refactor(all): use the transform attribute of @Input() instead of @InputBoolean() and @InputNumber()
Pull Request #3062: refactor(all): use the transform attribute of @input() instead of @InputBoolean() and @InputNumber()

4987 of 6108 branches covered (81.65%)

Branch coverage included in aggregate %.

217 of 223 new or added lines in 82 files covered. (97.31%)

202 existing lines in 53 files now uncovered.

12246 of 12929 relevant lines covered (94.72%)

1055.59 hits per line

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

93.51
/src/flexible-text/flexible-text.component.ts
1
import { ContentObserver } from '@angular/cdk/observers';
2
import { AfterContentInit, Component, ElementRef, Input, NgZone, OnDestroy, OnInit, TemplateRef, numberAttribute } from '@angular/core';
3
import { ThyPlacement } from 'ngx-tethys/core';
4
import { ThyTooltipDirective } from 'ngx-tethys/tooltip';
5
import { isUndefinedOrNull } from 'ngx-tethys/util';
6
import { useHostRenderer } from '@tethys/cdk/dom';
7
import { from, Observable, Subject, Subscription } from 'rxjs';
8
import { debounceTime, take, takeUntil } from 'rxjs/operators';
9

10
/**
11
 * 文本提示组件,支持组件 thy-flexible-text 和指令 [thyFlexibleText] 两种方式
12
 * @name thy-flexible-text,[thyFlexibleText]
13
 */
14
@Component({
15
    selector: 'thy-flexible-text,[thyFlexibleText]',
1✔
16
    exportAs: 'thyFlexibleText',
1✔
17
    templateUrl: './flexible-text.component.html',
18
    hostDirectives: [ThyTooltipDirective],
12✔
19
    standalone: true
12✔
20
})
21
export class ThyFlexibleText implements OnInit, AfterContentInit, OnDestroy {
UNCOV
22
    isOverflow = false;
×
23

24
    content: string | TemplateRef<HTMLElement>;
25

1,079✔
26
    placement: ThyPlacement;
1,079!
27

1,079✔
28
    containerClass: string;
29

30
    subscription: Subscription | null = null;
31

10✔
32
    offset: number;
10!
33

10✔
34
    /**
35
     * 触发提示方式
36
     * @type hover | focus | click
37
     * @default hover
10✔
38
     */
10!
39
    @Input('thyTooltipTrigger') trigger: 'hover' | 'focus' | 'click';
10✔
40

41
    /**
42
     * 自定义class类,如果不设置默认会包含 `flexible-text-container`
43
     */
1,074✔
44
    @Input('thyContainerClass')
1,074✔
45
    set thyContainerClass(value: string) {
1,074✔
46
        this.containerClass = value;
1,074✔
47
        this.updateContainerClass();
1,074✔
48
    }
1,074✔
49

1,074✔
50
    get thyContainerClass(): string {
1,074✔
51
        return this.containerClass;
52
    }
53

926✔
54
    /**
926✔
55
     * 需要展示的全部内容
56✔
56
     * @type string | TemplateRef<HTMLElement>
57
     */
926✔
58
    @Input('thyTooltipContent') set thyContent(value: string | TemplateRef<HTMLElement>) {
926✔
59
        this.content = value;
926✔
60
        if (this.tooltipDirective) {
61
            this.tooltipDirective.content = this.content;
62
        }
63
    }
64

1,074✔
65
    /**
1,074✔
66
     * tooltip 的提示位置
9✔
67
     * @type top | bottom | left | right
68
     * @default top
1,074✔
69
     */
9✔
70
    @Input('thyTooltipPlacement') set thyPlacement(value: ThyPlacement) {
71
        this.placement = value;
1,074✔
72
        if (this.tooltipDirective) {
9✔
73
            this.tooltipDirective.placement = this.placement;
74
        }
1,074✔
75
    }
1,074✔
76

77
    /**
78
     * tooltip 偏移量
79
     */
80
    @Input({ alias: 'thyTooltipOffset', transform: numberAttribute }) set thyOffset(value: number) {
1,074!
81
        this.offset = value;
82
        if (this.tooltipDirective) {
83
            this.tooltipDirective.tooltipOffset = this.offset;
1,074✔
84
        }
85
    }
1,074✔
86

935✔
87
    private destroy$ = new Subject<void>();
88

89
    private hostRenderer = useHostRenderer();
90

3✔
91
    constructor(
92
        private elementRef: ElementRef,
935✔
93
        private contentObserver: ContentObserver,
94
        private ngZone: NgZone,
95
        public tooltipDirective: ThyTooltipDirective
8✔
96
    ) {}
97

98
    static createResizeObserver(element: HTMLElement) {
99
        return new Observable(observer => {
100
            const resize = new ResizeObserver(entries => {
101
                observer.next(entries);
1,074✔
102
            });
1,074✔
103
            resize.observe(element);
104
            return () => {
105
                resize.disconnect();
11✔
106
            };
11✔
107
        });
4✔
108
    }
109

110
    ngOnInit() {
7✔
111
        this.updateContainerClass();
112
        if (this.placement) {
11✔
113
            this.tooltipDirective.placement = this.placement;
114
        }
115
        if (this.offset) {
1,086✔
116
            this.tooltipDirective.tooltipOffset = this.offset;
1,086✔
117
        }
118
        if (this.trigger) {
119
            this.tooltipDirective.trigger = this.trigger;
120
        }
1,086✔
121
        this.tooltipDirective.content = this.content;
122
        this.tooltipDirective.thyTooltipDisabled = true;
1✔
123
    }
124

125
    ngAfterContentInit() {
126
        // Note: the zone may be nooped through `BootstrapOptions` when bootstrapping the root module. This means
127
        // the `onStable` will never emit any value.
128
        const onStable$ = this.ngZone.isStable ? from(Promise.resolve()) : this.ngZone.onStable.pipe(take(1));
1✔
129
        // Normally this isn't in the zone, but it can cause performance regressions for apps
130
        // using `zone-patch-rxjs` because it'll trigger a change detection when it unsubscribes.
131
        this.ngZone.runOutsideAngular(() => {
132
            // Wait for the next time period to avoid blocking the js thread.
133
            onStable$.pipe(takeUntil(this.destroy$)).subscribe(() => {
134
                this.contentObserver
135
                    .observe(this.elementRef)
136
                    .pipe(debounceTime(100), takeUntil(this.destroy$))
1✔
137
                    .subscribe(() => {
138
                        this.applyOverflow();
139
                    });
140

141
                ThyFlexibleText.createResizeObserver(this.elementRef.nativeElement)
142
                    .pipe(debounceTime(100), takeUntil(this.destroy$))
143
                    .subscribe(() => {
144
                        this.applyOverflow();
145
                    });
146
            });
147
        });
148
    }
149

150
    ngOnDestroy() {
151
        this.destroy$.next();
152
        this.tooltipDirective.hide();
153
    }
154

155
    applyOverflow() {
156
        const nativeElement = this.elementRef.nativeElement;
157
        if (nativeElement.clientWidth < nativeElement.scrollWidth || nativeElement.clientHeight < nativeElement.scrollHeight) {
158
            this.isOverflow = true;
159
        } else {
160
            this.isOverflow = false;
161
        }
162
        this.tooltipDirective.thyTooltipDisabled = !this.isOverflow;
163
    }
164

165
    updateContainerClass() {
166
        const containerClass = isUndefinedOrNull(this.containerClass) ? 'flexible-text-container' : this.containerClass;
167
        const flexibleTextClass = {
168
            'text-truncate': true,
169
            [containerClass]: containerClass !== ''
170
        };
171
        this.hostRenderer.updateClassByMap(flexibleTextClass);
172
    }
173
}
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