• 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

87.91
/src/empty/empty.component.ts
1
import { ThyTranslate } from 'ngx-tethys/core';
2
import { useHostRenderer } from '@tethys/cdk/dom';
3
import {
4
    AfterViewInit,
5
    Component,
6
    ContentChild,
7
    ElementRef,
8
    OnChanges,
9
    Input,
10
    NgZone,
11
    OnInit,
12
    TemplateRef,
1✔
13
    SimpleChanges,
14
    inject
15
} from '@angular/core';
16

17
import { ThyEmptyConfig } from './empty.config';
1✔
18
import { PRESET_SVG } from './svgs';
19
import { DomSanitizer } from '@angular/platform-browser';
20
import { SafeAny } from 'ngx-tethys/types';
21
import { ThyIcon } from 'ngx-tethys/icon';
22
import { NgClass, NgTemplateOutlet } from '@angular/common';
23
import { coerceBooleanProperty } from 'ngx-tethys/util';
24

25
const sizeClassMap = {
26
    lg: ['thy-empty-state', 'thy-empty-state--lg'],
27
    md: ['thy-empty-state'],
28
    sm: ['thy-empty-state', 'thy-empty-state--sm']
29
};
30

31
const sizeMap = {
32
    lg: {
33
        height: 168, // 空提示的高度
34
        offsetTop: 30, // 空提示图标和大小之间的空白距离,需要除去,否则会不居中
35
        defaultMarginTop: 120 // 不自动计算默认的 top 距离
36
    },
37
    md: {
38
        height: 118,
39
        offsetTop: 20,
1✔
40
        defaultMarginTop: 10
41
    },
33✔
42
    sm: {
33✔
43
        height: 78,
33✔
44
        offsetTop: 10,
33✔
45
        defaultMarginTop: 10
33✔
46
    }
33✔
47
};
33✔
48

33✔
49
/** https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-loading */
50
export type ThyEmptyImageLoading = 'eager' | 'lazy';
51

36✔
52
/** https://wicg.github.io/priority-hints/#idl-index */
36✔
53
export type ThyEmptyImageFetchPriority = 'high' | 'low' | 'auto';
3✔
54

55
/**
56
 * 空页面组件
57
 * @name thy-empty
104✔
58
 * @order 10
90✔
59
 */
60
@Component({
14✔
61
    selector: 'thy-empty',
2✔
62
    templateUrl: './empty.component.html',
63
    standalone: true,
12✔
64
    imports: [ThyIcon, NgClass, NgTemplateOutlet]
2✔
65
})
66
export class ThyEmpty implements OnInit, AfterViewInit, OnChanges {
67
    private thyTranslate = inject(ThyTranslate);
68
    private thyEmptyConfig = inject(ThyEmptyConfig);
10✔
69
    private elementRef = inject(ElementRef);
2✔
70
    private ngZone = inject(NgZone);
71
    private sanitizer = inject(DomSanitizer);
72

73
    /**
74
     * 显示文本提示信息。同时传入 thyMessage,thyTranslationKey,thyEntityName,thyEntityNameTranslateKey 时优先级最高
8✔
75
     */
76
    @Input() thyMessage: string;
77

78
    /**
33✔
79
     * 显示文本提示信息多语言 Key。同时传入 thyTranslationKey,thyEntityName,thyEntityNameTranslateKey 时优先级最高
33✔
80
     */
33✔
81
    @Input() thyTranslationKey: string;
82

11!
83
    /**
84
     * 显示文本提示信息多语言 Key 的 Values。传入 thyTranslationKey 后,传入这个才会生效
11✔
85
     */
86
    @Input() thyTranslationValues: any;
11!
UNCOV
87

×
88
    /**
89
     * 显示默认提示信息,替换默认提示信息的目标对象,比如:没有 {thyEntityName}。同时传入 thyEntityName,thyEntityNameTranslateKey 时优先级较高
11✔
90
     */
91
    @Input() thyEntityName: string;
11!
92

11✔
93
    /**
94
     * thyEntityName 的多语言 Key。thyMessage,thyTranslationKey,thyEntityName 均未传入时才会生效
95
     */
96
    @Input() thyEntityNameTranslateKey: string;
22!
UNCOV
97

×
98
    /**
99
     * 提示图标名
100
     */
22✔
101
    @Input() thyIconName: string;
102

103
    /**
33!
UNCOV
104
     * 大小
×
105
     * @type sm | md | lg
106
     * @default md
107
     */
108
    @Input()
33✔
109
    set thySize(value: string) {
33✔
110
        this.size = value;
33✔
111
        if (this._initialized) {
112
            this.updateClass();
113
        }
36✔
114
    }
36!
115

36✔
116
    /**
117
     * 距上距离
118
     */
119
    @Input() thyMarginTop: number | string;
33✔
120

33✔
121
    /**
33✔
122
     * 是否自动根据父容器计算高度,垂直居中
123
     * @default false
124
     */
125
    @Input({ transform: coerceBooleanProperty }) thyTopAuto: boolean;
126

42!
UNCOV
127
    /**
×
128
     * 自动计算高度垂直居中(即 thyTopAuto 为 true)时,支持传入自定义父容器
129
     */
130
    @Input() thyContainer: ElementRef;
131

33✔
132
    /**
33✔
133
     * 提示图片链接
33✔
134
     */
135
    @Input() thyImageUrl: string;
1✔
136

137
    @Input() thyImageLoading?: ThyEmptyImageLoading;
138

139
    @Input() thyImageFetchPriority?: ThyEmptyImageFetchPriority;
140

141
    /**
142
     * 显示文本描述
143
     */
144
    @Input() thyDescription: string;
145

146
    private size: string = 'md';
147

148
    private _initialized = false;
149

150
    private hostRenderer = useHostRenderer();
151

152
    presetSvg: SafeAny;
153

1✔
154
    /**
155
     * 除提示图片,文本外的其他信息传入模板
156
     * @type TemplateRef
157
     */
158
    @ContentChild('extra') extraTemplateRef: TemplateRef<any>;
159

160
    get displayText() {
161
        if (this.thyMessage) {
162
            return this.thyMessage;
163
        } else if (this.thyTranslationKey) {
164
            return this.thyTranslate.instant(this.thyTranslationKey, this.thyTranslationValues);
165
        } else if (this.thyEntityName) {
166
            return this.thyTranslate.instant(this.thyEmptyConfig.noResultWithTargetTranslateKey, {
167
                target: this.thyEntityName
168
            });
169
        } else if (this.thyEntityNameTranslateKey) {
170
            return this.thyTranslate.instant(this.thyEmptyConfig.noResultWithTargetTranslateKey, {
171
                target: this.thyTranslate.instant(this.thyEntityNameTranslateKey)
172
            });
173
        } else {
174
            return this.thyTranslate.instant(this.thyEmptyConfig.noResultTranslateKey);
175
        }
176
    }
177

178
    private _calculatePosition() {
179
        const sizeOptions = sizeMap[this.thySize || 'md'];
180
        let marginTop = null;
181
        if (this.thyTopAuto) {
182
            // 选择参考父容器居中
183
            const containerElement = this.thyContainer ? this.thyContainer.nativeElement : this.elementRef.nativeElement.parentElement;
184
            // containerElement.height;
185
            let emptyStateHeight = this.elementRef.nativeElement.offsetHeight;
186
            // 高度没有自动计算出来使用默认值
187
            if (emptyStateHeight <= 10) {
188
                emptyStateHeight = sizeOptions.height;
189
            }
190
            marginTop = (containerElement.offsetHeight - emptyStateHeight) / 2 - sizeOptions.offsetTop;
191
            // marginTop = (containerElement.offsetHeight - emptyStateHeight) / 2;
192
            if (marginTop < 0) {
193
                marginTop = 0; // sizeOptions.defaultMarginTop;
194
            }
195
        } else {
196
            if (this.thyMarginTop) {
197
                marginTop = this.thyMarginTop;
198
            } else {
199
                marginTop = 0; // sizeOptions.defaultMarginTop;
200
            }
201
        }
202
        if (marginTop) {
203
            this.hostRenderer.setStyle('marginTop', marginTop + 'px');
204
        }
205
    }
206

207
    ngOnInit() {
208
        this.updateClass();
209
        this._initialized = true;
210
        this.setPresetSvg(this.thyIconName);
211
    }
212

213
    updateClass() {
214
        const classList = sizeClassMap[this.size] || sizeClassMap['md'];
215
        if (classList) {
216
            this.hostRenderer.updateClass(classList);
217
        }
218
    }
219

220
    ngAfterViewInit() {
221
        this.ngZone.runOutsideAngular(() => {
222
            setTimeout(() => {
223
                this._calculatePosition();
224
            }, 50);
225
        });
226
    }
227

228
    ngOnChanges(changes: SimpleChanges): void {
229
        if (changes.thyIconName && changes.thyIconName.currentValue && !changes.thyIconName.firstChange) {
230
            this.setPresetSvg(changes.thyIconName.currentValue);
231
        }
232
    }
233

234
    setPresetSvg(icon: string) {
235
        this.presetSvg = '';
236
        let presetSvg = icon ? PRESET_SVG[icon] : PRESET_SVG.default;
237

238
        this.presetSvg = presetSvg ? this.sanitizer.bypassSecurityTrustHtml(presetSvg) : '';
239
    }
240
}
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