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

atinc / ngx-tethys / 68ef226c-f83e-44c1-b8ed-e420a83c5d84

28 May 2025 10:31AM UTC coverage: 10.352% (-80.0%) from 90.316%
68ef226c-f83e-44c1-b8ed-e420a83c5d84

Pull #3460

circleci

pubuzhixing8
chore: xxx
Pull Request #3460: refactor(icon): migrate signal input #TINFR-1476

132 of 6823 branches covered (1.93%)

Branch coverage included in aggregate %.

10 of 14 new or added lines in 1 file covered. (71.43%)

11648 existing lines in 344 files now uncovered.

2078 of 14525 relevant lines covered (14.31%)

6.69 hits per line

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

3.8
/src/tree/tree-node.component.ts
1
import { Subject } from 'rxjs';
2
import {
3
    Component,
4
    ContentChild,
5
    ElementRef,
6
    EventEmitter,
7
    HostBinding,
8
    Input,
9
    OnChanges,
10
    OnDestroy,
11
    OnInit,
12
    Output,
13
    SimpleChanges,
14
    TemplateRef,
15
    ViewChild,
16
    ViewEncapsulation,
17
    numberAttribute,
18
    inject
1✔
19
} from '@angular/core';
UNCOV
20

×
UNCOV
21
import { THY_TREE_ABSTRACT_TOKEN } from './tree-abstract';
×
UNCOV
22
import { ThyTreeNode } from './tree.class';
×
UNCOV
23
import { ThyTreeEmitEvent, ThyTreeNodeCheckState, ThyClickBehavior } from './tree.class';
×
UNCOV
24
import { ThyTreeService } from './tree.service';
×
UNCOV
25
import { ThyLoading } from 'ngx-tethys/loading';
×
UNCOV
26
import { ThyIcon } from 'ngx-tethys/icon';
×
UNCOV
27
import { NgClass, NgStyle, NgTemplateOutlet } from '@angular/common';
×
UNCOV
28
import { coerceBooleanProperty } from 'ngx-tethys/util';
×
UNCOV
29

×
UNCOV
30
/**
×
UNCOV
31
 * 树形控件的节点组件
×
UNCOV
32
 * @private
×
UNCOV
33
 * @name thy-tree-node
×
UNCOV
34
 */
×
35
@Component({
36
    selector: 'thy-tree-node',
UNCOV
37
    templateUrl: './tree-node.component.html',
×
38
    encapsulation: ViewEncapsulation.None,
39
    imports: [ThyIcon, NgClass, NgStyle, NgTemplateOutlet, ThyLoading]
40
})
×
41
export class ThyTreeNodeComponent implements OnDestroy, OnInit, OnChanges {
42
    root = inject(THY_TREE_ABSTRACT_TOKEN);
UNCOV
43
    thyTreeService = inject(ThyTreeService);
×
UNCOV
44

×
45
    /**
46
     * node 节点展现所需的数据
UNCOV
47
     */
×
UNCOV
48
    @Input() node: ThyTreeNode;
×
49

50
    /**
UNCOV
51
     * 设置 TreeNode 是否支持异步加载
×
UNCOV
52
     */
×
53
    @Input({ transform: coerceBooleanProperty }) thyAsync = false;
54

UNCOV
55
    /**
×
56
     * 设置 TreeNode 是否支持多选节点
57
     */
58
    @Input({ transform: coerceBooleanProperty }) thyMultiple = false;
UNCOV
59

×
60
    /**
61
     * 设置 TreeNode 是否支持拖拽排序
62
     */
63
    @Input({ transform: coerceBooleanProperty }) thyDraggable = false;
64

65
    /**
UNCOV
66
     * 设置 TreeNode 是否支持 Checkbox 选择
×
67
     */
68
    @Input({ transform: coerceBooleanProperty }) thyCheckable = false;
69

70
    /**
71
     * 点击节点的行为,`default` 为选中当前节点,`selectCheckbox` 为选中节点的 Checkbox, `thyCheckable` 为 true 时生效。
72
     * @default default
UNCOV
73
     */
×
UNCOV
74
    @Input() thyClickBehavior: ThyClickBehavior;
×
UNCOV
75

×
76
    /**
UNCOV
77
     * 设置节点名称是否支持超出截取
×
UNCOV
78
     * @default false
×
79
     */
UNCOV
80
    @Input({ transform: coerceBooleanProperty }) thyTitleTruncate: boolean;
×
UNCOV
81

×
UNCOV
82
    /**
×
UNCOV
83
     * 设置 TreeNode 的渲染模板
×
UNCOV
84
     */
×
85
    @Input() templateRef: TemplateRef<any>;
86

87
    /**
×
88
     * 设置子的空数据渲染模板
89
     */
UNCOV
90
    @Input() emptyChildrenTemplateRef: TemplateRef<any>;
×
91

92
    /**
93
     * 设置 node 点击事件
94
     */
95
    @Output() thyOnClick: EventEmitter<ThyTreeEmitEvent> = new EventEmitter<ThyTreeEmitEvent>();
96

UNCOV
97
    /**
×
UNCOV
98
     * 双击 node 事件
×
UNCOV
99
     */
×
UNCOV
100
    @Output() thyDblClick: EventEmitter<ThyTreeEmitEvent> = new EventEmitter<ThyTreeEmitEvent>();
×
101

102
    /**
103
     * 点击展开触发事件
104
     */
UNCOV
105
    @Output() thyOnExpandChange: EventEmitter<ThyTreeEmitEvent> = new EventEmitter<ThyTreeEmitEvent>();
×
UNCOV
106

×
107
    /**
108
     * 设置 check 选择事件
109
     */
110
    @Output() thyOnCheckboxChange: EventEmitter<ThyTreeEmitEvent> = new EventEmitter<ThyTreeEmitEvent>();
UNCOV
111

×
112
    /**
113
     * 设置 childrenTree 的渲染模板
UNCOV
114
     */
×
115
    @ContentChild('childrenTree') childrenTreeTemplateRef: TemplateRef<any>;
116

UNCOV
117
    /** The native `<div class="thy-tree-node-wrapper thy-sortable-item"></div>` element. */
×
UNCOV
118
    @ViewChild('treeNodeWrapper', { static: true }) treeNodeWrapper: ElementRef<HTMLElement>;
×
119

120
    @HostBinding('class.thy-tree-node') thyTreeNodeClass = true;
121

UNCOV
122
    @HostBinding('class') itemClass: string;
×
UNCOV
123

×
124
    /**
125
     * 开启虚拟滚动时,单行节点的高度,当`thySize`为`default`时,该参数才生效
1✔
126
     */
127
    @Input({ transform: numberAttribute }) thyItemSize = 44;
128

129
    /**
130
     * 设置节点缩进距离,缩进距离 = thyIndent * node.level
131
     */
132
    @Input({ transform: numberAttribute }) thyIndent = 25;
133

134
    public get nodeIcon() {
135
        return this.node.origin.icon;
136
    }
137

138
    public get nodeIconStyle() {
139
        return this.node.origin.iconStyle;
140
    }
141

142
    private destroy$ = new Subject<void>();
143

144
    checkState = ThyTreeNodeCheckState;
145

146
    public clickNode(event: Event) {
147
        if (this.node.isDisabled) {
1✔
148
            this.expandNode(event);
149
        } else {
150
            if (this.thyCheckable && this.thyClickBehavior === 'selectCheckbox') {
151
                this.clickNodeCheck(event);
152
            } else {
153
                if (this.root.thyMultiple) {
154
                    this.root.toggleTreeNode(this.node);
155
                } else {
156
                    this.root.selectTreeNode(this.node);
157
                }
158
            }
159
        }
160
        this.thyOnClick.emit({
161
            eventName: 'click',
162
            event: event,
163
            node: this.node
164
        });
165
    }
166

167
    public dbClickNode(event: Event) {
168
        this.thyDblClick.emit({
169
            eventName: 'dbclick',
170
            event: event,
171
            node: this.node
172
        });
173
    }
174

175
    public clickNodeCheck(event: Event) {
176
        event.stopPropagation();
177
        if (this.node.isChecked === ThyTreeNodeCheckState.unchecked) {
178
            this.node.setChecked(true);
179
        } else if (this.node.isChecked === ThyTreeNodeCheckState.checked) {
180
            this.node.setChecked(false);
181
        } else if (this.node.isChecked === ThyTreeNodeCheckState.indeterminate) {
182
            if (this.node.children?.length) {
183
                const activeChildren = this.node.children.filter(item => !item.isDisabled);
184
                const isAllActiveChildrenChecked = activeChildren.every(item => item.isChecked);
185
                this.node.setChecked(!isAllActiveChildrenChecked);
186
            } else {
187
                this.node.setChecked(true);
188
            }
189
        }
190
        this.thyOnCheckboxChange.emit({
191
            eventName: 'checkboxChange',
192
            event: event,
193
            node: this.node
194
        });
195
    }
196

197
    public expandNode(event: Event) {
198
        event.stopPropagation();
199
        this.node.setExpanded(!this.node.isExpanded);
200
        if (this.root.thyShowExpand) {
201
            this.thyOnExpandChange.emit({
202
                eventName: 'expand',
203
                event: event,
204
                node: this.node
205
            });
206
            if (this.thyAsync && this.node.children.length === 0) {
207
                this.node.setLoading(true);
208
            }
209
        }
210
    }
211

212
    public isShowExpand(node: ThyTreeNode) {
213
        return this.root.isShowExpand(node);
214
    }
215

216
    ngOnInit(): void {
217
        this.itemClass = this.node?.itemClass?.join(' ');
218
    }
219

220
    ngOnChanges(changes: SimpleChanges): void {
221
        if (changes.node && !changes.node.isFirstChange()) {
222
            this.itemClass = changes?.node?.currentValue.itemClass?.join(' ');
223
        }
224
    }
225

226
    ngOnDestroy(): void {
227
        this.destroy$.next();
228
        this.destroy$.complete();
229
    }
230
}
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