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

atinc / ngx-tethys / cd64db52-e563-41a3-85f3-a0adb87ce135

30 Oct 2024 08:03AM UTC coverage: 90.402% (-0.04%) from 90.438%
cd64db52-e563-41a3-85f3-a0adb87ce135

push

circleci

web-flow
refactor: refactor constructor to the inject function (#3222)

5503 of 6730 branches covered (81.77%)

Branch coverage included in aggregate %.

422 of 429 new or added lines in 170 files covered. (98.37%)

344 existing lines in 81 files now uncovered.

13184 of 13941 relevant lines covered (94.57%)

997.19 hits per line

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

81.67
/src/input/input-group.component.ts
1
import {
2
    Component,
3
    HostBinding,
4
    Input,
5
    ContentChild,
6
    TemplateRef,
7
    ViewEncapsulation,
8
    ChangeDetectionStrategy,
9
    AfterContentChecked,
10
    OnInit,
11
    OnDestroy,
1✔
12
    ChangeDetectorRef,
13
    NgZone,
14
    inject,
15
    DestroyRef
16
} from '@angular/core';
17
import { ThyTranslate, useHostFocusControl } from 'ngx-tethys/core';
18
import { useHostRenderer } from '@tethys/cdk/dom';
19
import { ThyInputDirective } from './input.directive';
20
import { NgTemplateOutlet } from '@angular/common';
21
import { throttleTime } from 'rxjs/operators';
1✔
22
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
23
import { Observable, of } from 'rxjs';
40✔
24
import { FocusOrigin } from '@angular/cdk/a11y';
40✔
25

40✔
26
export type InputGroupSize = 'sm' | 'lg' | 'md' | '';
40✔
27

40✔
28
const inputGroupSizeMap = {
40✔
29
    sm: ['input-group-sm'],
40✔
30
    lg: ['input-group-lg'],
31
    md: ['input-group-md']
32
};
8✔
33

34
/**
35
 * 输入框分组
8!
36
 * @name thy-input-group
8✔
37
 * @order 20
38
 */
39
@Component({
40
    selector: 'thy-input-group',
8✔
41
    templateUrl: './input-group.component.html',
42
    changeDetection: ChangeDetectionStrategy.OnPush,
43
    encapsulation: ViewEncapsulation.None,
8!
44
    host: {
8✔
45
        class: 'thy-input-group',
46
        '[class.form-control]': 'prefixTemplate || suffixTemplate',
47
        '[class.thy-input-group-with-prefix]': 'prefixTemplate',
48
        '[class.thy-input-group-with-suffix]': 'suffixTemplate',
18✔
49
        '[class.thy-input-group-with-textarea-suffix]': 'isTextareaSuffix',
3✔
50
        '[class.thy-input-group-with-scroll-bar]': 'isTextareaSuffix && hasScrollbar'
51
    },
52
    standalone: true,
15✔
53
    imports: [NgTemplateOutlet]
54
})
55
export class ThyInputGroup implements OnInit, AfterContentChecked, OnDestroy {
56
    private thyTranslate = inject(ThyTranslate);
40✔
57
    private ngZone = inject(NgZone);
4✔
58
    private cdr = inject(ChangeDetectorRef);
2✔
59

60
    private hostRenderer = useHostRenderer();
61

2✔
62
    private hostFocusControl = useHostFocusControl();
63

64
    private readonly destroyRef = inject(DestroyRef);
65

66
    public appendText: string;
80✔
67

80✔
68
    public prependText: string;
80✔
69

2✔
70
    public isTextareaSuffix: boolean;
71

72
    public hasScrollbar: boolean;
73

2✔
74
    @HostBinding('class.disabled') disabled = false;
2✔
75

76
    /**
UNCOV
77
     * 输入框上添加的后置文本
×
UNCOV
78
     */
×
UNCOV
79
    @Input()
×
UNCOV
80
    set thyAppendText(value: string) {
×
81
        this.appendText = value;
×
82
    }
83

84
    /**
85
     * 输入框上添加的后置文本多语言 Key
86
     */
87
    @Input()
88
    set thyAppendTextTranslateKey(value: string) {
2!
89
        if (value) {
90
            this.appendText = this.thyTranslate.instant(value);
91
        }
2✔
UNCOV
92
    }
×
93

94
    /**
2✔
95
     * 输入框上添加的前置文本
2✔
96
     */
2✔
97
    @Input()
98
    set thyPrependText(value: string) {
99
        this.prependText = value;
100
    }
101

40✔
102
    /**
103
     * 输入框上添加的前置文本多语言 Key
1✔
104
     */
105
    @Input()
106
    set thyPrependTextTranslateKey(value: string) {
107
        if (value) {
108
            this.prependText = this.thyTranslate.instant(value);
109
        }
110
    }
111

112
    /**
113
     * 输入框分组大小
114
     * @type 'sm' | 'lg' | 'md' | ''
115
     * @default ''
116
     */
117
    @Input()
1✔
118
    set thySize(size: InputGroupSize) {
119
        if (size && inputGroupSizeMap[size]) {
120
            this.hostRenderer.updateClass(inputGroupSizeMap[size]);
121
        } else {
122
            this.hostRenderer.updateClass([]);
123
        }
124
    }
125

126
    /**
127
     * 后置模板
128
     */
129
    @ContentChild('append') appendTemplate: TemplateRef<unknown>;
130

131
    /**
132
     * 前置模板
133
     */
134
    @ContentChild('prepend') prependTemplate: TemplateRef<unknown>;
135

136
    /**
137
     * 前缀
138
     */
139
    @ContentChild('prefix') prefixTemplate: TemplateRef<unknown>;
140

141
    /**
142
     * 后缀
143
     */
144
    @ContentChild('suffix') suffixTemplate: TemplateRef<unknown>;
145

146
    /**
147
     * @private
148
     */
149
    @ContentChild(ThyInputDirective) inputDirective: ThyInputDirective;
150

151
    ngOnInit() {
152
        this.hostFocusControl.focusChanged = (origin: FocusOrigin) => {
153
            if (origin) {
154
                this.hostRenderer.addClass('form-control-active');
155
            } else {
156
                this.hostRenderer.removeClass('form-control-active');
157
            }
158
        };
159
    }
160

161
    ngAfterContentChecked(): void {
162
        this.disabled = !!this.inputDirective?.nativeElement?.hasAttribute('disabled');
163

164
        this.isTextareaSuffix = this.inputDirective?.nativeElement?.tagName === 'TEXTAREA';
165
        if (this.isTextareaSuffix) {
166
            this.determineHasScrollbar();
167
        }
168
    }
169

170
    private determineHasScrollbar() {
171
        this.ngZone.runOutsideAngular(() => {
172
            this.resizeObserver(this.inputDirective.nativeElement)
173
                .pipe(throttleTime(100), takeUntilDestroyed(this.destroyRef))
174
                .subscribe(() => {
175
                    const hasScrollbar = this.inputDirective.nativeElement.scrollHeight > this.inputDirective.nativeElement.clientHeight;
176
                    if (this.hasScrollbar !== hasScrollbar) {
177
                        this.ngZone.run(() => {
178
                            this.hasScrollbar = hasScrollbar;
179
                            this.cdr.detectChanges();
180
                        });
181
                    }
182
                });
183
        });
184
    }
185

186
    private resizeObserver(element: HTMLElement): Observable<ResizeObserverEntry[]> {
187
        return typeof ResizeObserver === 'undefined' || !ResizeObserver
188
            ? of(null)
189
            : new Observable(observer => {
190
                  const resize = new ResizeObserver((entries: ResizeObserverEntry[]) => {
191
                      observer.next(entries);
192
                  });
193
                  resize.observe(element);
194
                  return () => {
195
                      resize.disconnect();
196
                  };
197
              });
198
    }
199

200
    ngOnDestroy() {
201
        this.hostFocusControl.destroy();
202
    }
203
}
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

© 2026 Coveralls, Inc