• 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

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

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

657✔
31
const passiveEventListenerOptions = <AddEventListenerOptions>normalizePassiveListenerOptions({ passive: true });
657✔
32

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

49
    /**
5✔
50
     * node 节点展现所需的数据
2✔
51
     */
52
    @Input() node: ThyTreeNode;
53

3✔
54
    /**
1✔
55
     * 设置 TreeNode 是否支持异步加载
56
     */
57
    @Input({ transform: coerceBooleanProperty }) thyAsync = false;
2✔
58

59
    /**
60
     * 设置 TreeNode 是否支持多选节点
61
     */
7✔
62
    @Input({ transform: coerceBooleanProperty }) thyMultiple = false;
63

64
    /**
65
     * 设置 TreeNode 是否支持拖拽排序
66
     */
67
    @Input({ transform: coerceBooleanProperty }) thyDraggable = false;
68

1✔
69
    /**
70
     * 设置 TreeNode 是否支持 Checkbox 选择
71
     */
72
    @Input({ transform: coerceBooleanProperty }) thyCheckable = false;
73

74
    /**
75
     * 点击节点的行为,`default` 为选中当前节点,`selectCheckbox` 为选中节点的 Checkbox, `thyCheckable` 为 true 时生效。
9✔
76
     * @default default
9✔
77
     */
5✔
78
    @Input() thyClickBehavior: ThyClickBehavior;
79

4✔
80
    /**
1✔
81
     * 设置节点名称是否支持超出截取
82
     * @default false
3!
83
     */
3!
84
    @Input({ transform: coerceBooleanProperty }) thyTitleTruncate: boolean;
16✔
85

5✔
86
    /**
3✔
87
     * 设置 TreeNode 的渲染模板
88
     */
UNCOV
89
    @Input() templateRef: TemplateRef<any>;
×
90

91
    /**
92
     * 设置子的空数据渲染模板
9✔
93
     */
94
    @Input() emptyChildrenTemplateRef: TemplateRef<any>;
95

96
    /**
97
     * 设置 node 点击事件
98
     */
99
    @Output() thyOnClick: EventEmitter<ThyTreeEmitEvent> = new EventEmitter<ThyTreeEmitEvent>();
6✔
100

6✔
101
    /**
6!
102
     * 双击 node 事件
6✔
103
     */
104
    @Output() thyDblClick: EventEmitter<ThyTreeEmitEvent> = new EventEmitter<ThyTreeEmitEvent>();
105

106
    /**
107
     * 点击展开触发事件
6✔
108
     */
1✔
109
    @Output() thyOnExpandChange: EventEmitter<ThyTreeEmitEvent> = new EventEmitter<ThyTreeEmitEvent>();
110

111
    /**
112
     * 设置 check 选择事件
113
     */
1,110✔
114
    @Output() thyOnCheckboxChange: EventEmitter<ThyTreeEmitEvent> = new EventEmitter<ThyTreeEmitEvent>();
115

116
    /**
657✔
117
     * 设置 childrenTree 的渲染模板
118
     */
119
    @ContentChild('childrenTree') childrenTreeTemplateRef: TemplateRef<any>;
740✔
120

59✔
121
    /** The native `<div class="thy-tree-node-wrapper thy-sortable-item"></div>` element. */
122
    @ViewChild('treeNodeWrapper', { static: true }) treeNodeWrapper: ElementRef<HTMLElement>;
123

124
    @HostBinding('class.thy-tree-node') thyTreeNodeClass = true;
657✔
125

657✔
126
    @HostBinding('class') itemClass: string;
127

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

133
    /**
134
     * 设置节点缩进距离,缩进距离 = thyIndent * node.level
135
     */
136
    @Input({ transform: numberAttribute }) thyIndent = 25;
137

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

142
    public get nodeIconStyle() {
143
        return this.node.origin.iconStyle;
144
    }
145

146
    private destroy$ = new Subject<void>();
147

148
    checkState = ThyTreeNodeCheckState;
149

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

171
    public dbClickNode(event: Event) {
172
        this.thyDblClick.emit({
173
            eventName: 'dbclick',
174
            event: event,
175
            node: this.node
176
        });
177
    }
178

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

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

216
    public isShowExpand(node: ThyTreeNode) {
217
        return this.root.isShowExpand(node);
218
    }
219

220
    ngOnInit(): void {
221
        this.itemClass = this.node?.itemClass?.join(' ');
222
    }
223

224
    ngOnChanges(changes: SimpleChanges): void {
225
        if (changes.node && !changes.node.isFirstChange()) {
226
            this.itemClass = changes?.node?.currentValue.itemClass?.join(' ');
227
        }
228
    }
229

230
    ngOnDestroy(): void {
231
        this.destroy$.next();
232
        this.destroy$.complete();
233
    }
234
}
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