• 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

6.21
/src/rate/rate.component.ts
1
import { InputBoolean, InputNumber } from 'ngx-tethys/core';
2
import { helpers } from 'ngx-tethys/util';
3

4
import { NgClass, NgFor } from '@angular/common';
5
import {
6
    ChangeDetectionStrategy,
7
    ChangeDetectorRef,
8
    Component,
9
    EventEmitter,
10
    forwardRef,
11
    HostBinding,
12
    Input,
1✔
13
    OnChanges,
14
    OnInit,
15
    Output,
16
    SimpleChanges,
17
    TemplateRef
18
} from '@angular/core';
1✔
19
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
20
import { ThyStopPropagationDirective } from 'ngx-tethys/shared';
×
21
import { ThyTooltipDirective } from 'ngx-tethys/tooltip';
×
22
import { ThyRateItemComponent } from './rate-item.component';
×
23

×
24
const noop = () => {};
25

26
/**
×
27
 * 评分组件
28
 * @name thy-rate
29
 * @order 10
30
 */
×
31
@Component({
×
32
    selector: 'thy-rate',
×
33
    templateUrl: './rate.component.html',
×
34
    providers: [
×
35
        {
×
36
            provide: NG_VALUE_ACCESSOR,
×
37
            useExisting: forwardRef(() => ThyRateComponent),
×
38
            multi: true
×
39
        }
×
40
    ],
×
41
    changeDetection: ChangeDetectionStrategy.OnPush,
×
42
    standalone: true,
×
43
    imports: [NgFor, ThyStopPropagationDirective, ThyRateItemComponent, NgClass, ThyTooltipDirective]
×
44
})
×
45
export class ThyRateComponent implements ControlValueAccessor, OnInit, OnChanges {
×
46
    private _value = 0;
×
47

×
48
    private currentValue = 0;
49

50
    private hasHalf = false;
×
51

52
    public rateArray: number[] = [];
53

×
54
    public rateStyleArray: Record<string, boolean>[] = [];
×
55

56
    private icons: string | TemplateRef<any> | string[] | TemplateRef<any>[] = null;
×
57

×
58
    public iconValue: string = null;
×
59

60
    public iconTemplate: TemplateRef<any> = null;
61

×
62
    private onTouchedCallback: () => void = noop;
×
63

×
64
    private onChangeCallback: (_: any) => void = noop;
65

66
    /**
67
     * 自定义评分的总数
×
68
     */
×
69
    @Input() @InputNumber() thyCount = 5;
×
70

71
    /**
×
72
     * 是否只读
×
73
     * @default false
74
     */
×
75
    @Input() @InputBoolean() thyDisabled = false;
76

77
    /**
×
78
     * 是否允许半选
×
79
     * @default false
80
     */
×
81
    @Input() @InputBoolean() thyAllowHalf = false;
×
82

×
83
    /**
×
84
     * 是否允许再次点击后清除
×
85
     */
86
    @Input() @InputBoolean() thyAllowClear = true;
87

×
88
    /**
×
89
     * 自定义每项的提示信息
90
     * @type string[]
×
91
     */
×
92
    @Input() thyTooltips: string[] = [];
×
93

×
94
    /**
×
95
     * 自定义模板,目前支持传单个模板或图标名称、数组(模板 | 图标名称)
×
96
     * @type string | TemplateRef<any> | string[] | TemplateRef<any>[]
×
97
     */
98
    @Input('thyIconTemplate')
99
    set thyIconTemplate(value: string | TemplateRef<any> | string[] | TemplateRef<any>[]) {
100
        this.icons = value;
×
101
        if (!this.icons) {
×
102
            this.iconValue = null;
×
103
            this.iconTemplate = null;
104
        } else {
×
105
            this.setIconTemplate();
106
        }
107
    }
×
108

×
109
    /**
×
110
     * 当前值hover时的回调
×
111
     */
112
    @Output() readonly thyItemHoverChange = new EventEmitter<number>();
113

×
114
    @HostBinding('class.thy-rate') className = true;
115

116
    constructor(private cdr: ChangeDetectorRef) {}
×
117

118
    get thyValue(): number {
×
119
        return this._value;
120
    }
121

×
122
    set thyValue(value: number) {
×
123
        if (this._value === value) {
×
124
            return;
×
125
        }
×
126
        this._value = value;
×
127
        this.hasHalf = !Number.isInteger(value);
×
128
        this.currentValue = Math.ceil(value);
×
129
    }
130

131
    writeValue(value: number): void {
132
        this.thyValue = value || 0;
133
        this.updateRateArray();
134
        this.cdr.markForCheck();
×
135
    }
×
136

×
137
    ngOnInit() {}
138

139
    ngOnChanges(changes: SimpleChanges): void {
×
140
        const { thyCount, thyValue } = changes;
141
        if (thyCount) {
142
            this.updateRateArray();
143
        }
×
144

×
145
        if (thyValue) {
×
146
            this.updateItemStyle();
×
147
        }
148
        this.cdr.detectChanges();
149
    }
×
150

151
    itemHover(isHalf: boolean, index: number): void {
152
        if (this.thyDisabled || (this.currentValue === index + 1 && this.hasHalf === isHalf)) {
×
153
            return;
×
154
        }
×
155
        this.currentValue = index + 1;
156
        this.hasHalf = isHalf;
157
        const _value = isHalf ? Number(this.currentValue - 0.5) : this.currentValue;
×
158
        this.thyItemHoverChange.emit(_value);
159
        this.updateItemStyle();
160
    }
161

162
    itemClick(isHalf: boolean, index: number) {
×
163
        if (this.thyDisabled) {
164
            return;
165
        }
×
166
        this.currentValue = index + 1;
167
        const _value = isHalf ? index + 1 - 0.5 : index + 1;
168
        if (this.thyValue === _value) {
×
169
            if (this.thyAllowClear) {
170
                this.thyValue = 0;
1✔
171
                this.onChangeCallback(this.thyValue);
172
                this.onTouchedCallback();
173
            }
1✔
174
        } else {
175
            this.thyValue = _value;
176
            this.onChangeCallback(this.thyValue);
177
            this.onTouchedCallback();
178
        }
179
        this.updateItemStyle();
180
    }
181

182
    onRateLeave(event: Event): void {
183
        event.stopPropagation();
184
        this.hasHalf = !Number.isInteger(this.thyValue);
1✔
185
        this.currentValue = Math.ceil(this.thyValue);
186
        this.updateItemStyle();
187
    }
188

1✔
189
    updateRateArray(): void {
190
        this.rateArray = Array(this.thyCount)
191
            .fill(0)
192
            .map((_, i) => {
1✔
193
                return i;
194
            });
195
        this.updateItemStyle();
196
    }
1✔
197

198
    updateItemStyle(): void {
199
        this.updateIcon();
200
        const rateStyle = 'thy-rate-star';
1✔
201
        this.rateStyleArray = this.rateArray.map(i => {
202
            const value = i + 1;
203
            return {
204
                [`${rateStyle}--full`]: value < this.currentValue || (value === this.currentValue && !this.hasHalf),
205
                [`${rateStyle}--half`]: this.hasHalf && value === this.currentValue,
206
                [`${rateStyle}--active`]: this.hasHalf && value === this.currentValue,
207
                [`${rateStyle}--zero`]: value > this.currentValue
×
208
            };
209
        });
210
    }
211

212
    updateIcon(): void {
213
        if (!this.icons) {
214
            this.iconValue = null;
215
            this.iconTemplate = null;
216
        } else {
217
            this.setIconTemplate();
218
        }
219
    }
220

221
    setIconTemplate(): void {
222
        if (helpers.isArray(this.icons) && this.icons.length > 0) {
223
            const currentIcon = (this.currentValue && this.currentValue - 1) || 0;
224
            if (this.icons[currentIcon] instanceof TemplateRef) {
225
                this.iconTemplate = this.icons[currentIcon] as TemplateRef<any>;
226
            } else {
227
                this.iconValue = this.icons[currentIcon] as string;
228
            }
229
        } else if (!helpers.isArray(this.icons)) {
230
            if (this.icons instanceof TemplateRef) {
231
                this.iconTemplate = this.icons;
232
            } else {
233
                this.iconValue = this.icons;
234
            }
235
        }
236
    }
237

238
    registerOnChange(fn: any): void {
239
        this.onChangeCallback = fn;
240
    }
241

242
    registerOnTouched(fn: any): void {
243
        this.onTouchedCallback = fn;
244
    }
245

246
    trackByFn(index: number, item: any) {
247
        return item || index;
248
    }
249
}
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