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

atinc / ngx-tethys / 0bbb2cec-209e-4d8a-b1b3-6bc54e05daa6

04 Sep 2023 08:40AM UTC coverage: 15.616% (-74.6%) from 90.2%
0bbb2cec-209e-4d8a-b1b3-6bc54e05daa6

Pull #2829

circleci

cmm-va
fix: add test
Pull Request #2829: fix: add tabIndex

300 of 6386 branches covered (0.0%)

Branch coverage included in aggregate %.

78 of 78 new or added lines in 26 files covered. (100.0%)

2849 of 13779 relevant lines covered (20.68%)

83.41 hits per line

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

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

×
23
import { THY_TREE_ABSTRACT_TOKEN, ThyTreeAbstractComponent } from './tree-abstract';
24
import { ThyTreeNode } from './tree-node.class';
25
import { ThyTreeEmitEvent, ThyTreeNodeCheckState, ThyClickBehavior } from './tree.class';
×
26
import { ThyTreeService } from './tree.service';
27
import { InputBoolean, InputNumber } from 'ngx-tethys/core';
28
import { ThyLoadingComponent } from 'ngx-tethys/loading';
×
29
import { ThyIconComponent } from 'ngx-tethys/icon';
×
30
import { NgIf, NgClass, NgStyle, NgTemplateOutlet } from '@angular/common';
×
31

×
32
const passiveEventListenerOptions = <AddEventListenerOptions>normalizePassiveListenerOptions({ passive: true });
×
33

×
34
/**
×
35
 * 树形控件的节点组件
×
36
 * @private
×
37
 * @name thy-tree-node
×
38
 */
×
39
@Component({
×
40
    selector: 'thy-tree-node',
×
41
    templateUrl: './tree-node.component.html',
×
42
    encapsulation: ViewEncapsulation.None,
×
43
    standalone: true,
44
    imports: [NgIf, ThyIconComponent, NgClass, NgStyle, NgTemplateOutlet, ThyLoadingComponent]
45
})
×
46
export class ThyTreeNodeComponent implements OnDestroy, OnInit, OnChanges {
×
47
    /**
48
     * node 节点展现所需的数据
49
     */
×
50
    @Input() node: ThyTreeNode;
×
51

52
    /**
53
     * 设置 TreeNode 是否支持异步加载
×
54
     */
×
55
    @Input() @InputBoolean() thyAsync = false;
56

57
    /**
×
58
     * 设置 TreeNode 是否支持多选节点
59
     */
60
    @Input() @InputBoolean() thyMultiple = false;
61

×
62
    /**
63
     * 设置 TreeNode 是否支持拖拽排序
64
     */
65
    @Input() @InputBoolean() thyDraggable = false;
66

67
    /**
68
     * 设置 TreeNode 是否支持 Checkbox 选择
×
69
     */
70
    @Input() @InputBoolean() thyCheckable = false;
71

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

×
78
    /**
79
     * 设置节点名称是否支持超出截取
×
80
     * @default false
×
81
     */
82
    @Input() @InputBoolean() thyTitleTruncate: boolean;
×
83

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

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

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

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

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

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

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

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

122
    @HostBinding('class.thy-tree-node') thyTreeNodeClass = true;
123

124
    @HostBinding('class') itemClass: string;
×
125

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

131
    /**
1✔
132
     * 设置节点缩进距离,缩进距离 = thyIndent * node.level
133
     */
134
    @Input() @InputNumber() thyIndent = 25;
135

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

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

144
    private destroy$ = new Subject<void>();
145

146
    checkState = ThyTreeNodeCheckState;
147

148
    constructor(@Inject(THY_TREE_ABSTRACT_TOKEN) public root: ThyTreeAbstractComponent, public thyTreeService: ThyTreeService) {}
149

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

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

179
    public clickNodeCheck(event: Event) {
180
        event.stopPropagation();
181
        if (this.node.isChecked === ThyTreeNodeCheckState.unchecked) {
1✔
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