• 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

88.04
/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,
1✔
12
    TemplateRef,
13
    SimpleChanges,
14
    booleanAttribute
15
} from '@angular/core';
16

1✔
17
import { ThyEmptyConfig } from './empty.config';
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 { NgIf, NgClass, NgTemplateOutlet } from '@angular/common';
23

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

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

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

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

2✔
54
/**
55
 * 空页面组件
56
 * @name thy-empty
57
 * @order 10
10✔
58
 */
2✔
59
@Component({
60
    selector: 'thy-empty',
61
    templateUrl: './empty.component.html',
62
    standalone: true,
63
    imports: [NgIf, ThyIcon, NgClass, NgTemplateOutlet]
8✔
64
})
65
export class ThyEmpty implements OnInit, AfterViewInit, OnChanges {
66
    /**
67
     * 显示文本提示信息。同时传入 thyMessage,thyTranslationKey,thyEntityName,thyEntityNameTranslateKey 时优先级最高
33✔
68
     */
33✔
69
    @Input() thyMessage: string;
33✔
70

71
    /**
11!
72
     * 显示文本提示信息多语言 Key。同时传入 thyTranslationKey,thyEntityName,thyEntityNameTranslateKey 时优先级最高
73
     */
11✔
74
    @Input() thyTranslationKey: string;
75

11!
UNCOV
76
    /**
×
77
     * 显示文本提示信息多语言 Key 的 Values。传入 thyTranslationKey 后,传入这个才会生效
78
     */
11✔
79
    @Input() thyTranslationValues: any;
80

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

22!
UNCOV
86
    /**
×
87
     * thyEntityName 的多语言 Key。thyMessage,thyTranslationKey,thyEntityName 均未传入时才会生效
88
     */
89
    @Input() thyEntityNameTranslateKey: string;
22✔
90

91
    /**
92
     * 提示图标名
33!
UNCOV
93
     */
×
94
    @Input() thyIconName: string;
95

96
    /**
97
     * 大小
33✔
98
     * @type sm | md | lg
33✔
99
     * @default md
33✔
100
     */
33✔
101
    @Input()
33✔
102
    set thySize(value: string) {
33✔
103
        this.size = value;
33✔
104
        if (this._initialized) {
33✔
105
            this.updateClass();
106
        }
107
    }
33✔
108

33✔
109
    /**
33✔
110
     * 距上距离
111
     */
112
    @Input() thyMarginTop: number | string;
36✔
113

36!
114
    /**
36✔
115
     * 是否自动根据父容器计算高度,垂直居中
116
     * @default false
117
     */
118
    @Input({ transform: booleanAttribute }) thyTopAuto: boolean;
33✔
119

33✔
120
    /**
33✔
121
     * 自动计算高度垂直居中(即 thyTopAuto 为 true)时,支持传入自定义父容器
122
     */
123
    @Input() thyContainer: ElementRef;
124

125
    /**
42!
UNCOV
126
     * 提示图片链接
×
127
     */
128
    @Input() thyImageUrl: string;
129

130
    @Input() thyImageLoading?: ThyEmptyImageLoading;
33✔
131

33✔
132
    @Input() thyImageFetchPriority?: ThyEmptyImageFetchPriority;
33✔
133

134
    /**
1✔
135
     * 显示文本描述
136
     */
137
    @Input() thyDescription: string;
138

139
    private size: string = 'md';
140

141
    private _initialized = false;
1✔
142

143
    private hostRenderer = useHostRenderer();
144

145
    presetSvg: SafeAny;
146

147
    /**
148
     * 除提示图片,文本外的其他信息传入模板
149
     * @type TemplateRef
150
     */
151
    @ContentChild('extra') extraTemplateRef: TemplateRef<any>;
152

153
    get displayText() {
154
        if (this.thyMessage) {
155
            return this.thyMessage;
156
        } else if (this.thyTranslationKey) {
157
            return this.thyTranslate.instant(this.thyTranslationKey, this.thyTranslationValues);
158
        } else if (this.thyEntityName) {
159
            return this.thyTranslate.instant(this.thyEmptyConfig.noResultWithTargetTranslateKey, {
1✔
160
                target: this.thyEntityName
161
            });
162
        } else if (this.thyEntityNameTranslateKey) {
163
            return this.thyTranslate.instant(this.thyEmptyConfig.noResultWithTargetTranslateKey, {
164
                target: this.thyTranslate.instant(this.thyEntityNameTranslateKey)
165
            });
166
        } else {
167
            return this.thyTranslate.instant(this.thyEmptyConfig.noResultTranslateKey);
168
        }
169
    }
170

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

200
    constructor(
201
        private thyTranslate: ThyTranslate,
202
        private thyEmptyConfig: ThyEmptyConfig,
203
        private elementRef: ElementRef,
204
        private ngZone: NgZone,
205
        private sanitizer: DomSanitizer
206
    ) {}
207

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

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

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

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

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

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