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

atinc / ngx-tethys / edbc1d43-1648-411a-a6bc-f24c9aa3f654

27 Mar 2025 06:13AM UTC coverage: 90.236% (+0.06%) from 90.179%
edbc1d43-1648-411a-a6bc-f24c9aa3f654

push

circleci

web-flow
Merge pull request #3282 from atinc/v19.0.0-next

5598 of 6865 branches covered (81.54%)

Branch coverage included in aggregate %.

8 of 8 new or added lines in 7 files covered. (100.0%)

157 existing lines in 46 files now uncovered.

13357 of 14141 relevant lines covered (94.46%)

992.51 hits per line

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

86.17
/src/transfer/transfer.component.ts
1
import { Component, ContentChild, EventEmitter, HostBinding, Input, OnInit, Output, TemplateRef, ViewEncapsulation } from '@angular/core';
2

3
import {
4
    Direction,
5
    InnerTransferDragEvent,
6
    ThyTransferChangeEvent,
7
    ThyTransferDragEvent,
8
    ThyTransferItem,
9
    ThyTransferSelectEvent,
10
    TransferDirection
11
} from './transfer.interface';
12
import { ThyFlexibleText } from 'ngx-tethys/flexible-text';
13
import { ThyIcon } from 'ngx-tethys/icon';
14
import { NgClass, NgTemplateOutlet } from '@angular/common';
1✔
15
import { ThyTransferList } from './transfer-list.component';
16

19✔
17
/**
19✔
18
 * 穿梭框组件
19✔
19
 * @name thy-transfer
19✔
20
 * @order 10
19✔
21
 */
19✔
22
@Component({
19✔
23
    selector: 'thy-transfer',
19✔
24
    templateUrl: './transfer.component.html',
25
    encapsulation: ViewEncapsulation.None,
26
    imports: [ThyTransferList, ThyIcon, NgClass, NgTemplateOutlet, ThyFlexibleText]
19!
27
})
19✔
28
export class ThyTransfer implements OnInit {
29
    @HostBinding('class') hostClass = 'thy-transfer';
30

31
    public leftDataSource: ThyTransferItem[] = [];
19!
32

19!
33
    public rightDataSource: ThyTransferItem[] = [];
34

UNCOV
35
    public allDataSource: ThyTransferItem[] = [];
×
36

37
    public leftTitle: string;
38

×
39
    public rightTitle: string;
19✔
40

19✔
41
    public rightDraggable = false;
19✔
42

19✔
43
    private _autoMove = true;
171✔
44

171✔
45
    /**
76✔
46
     * 数据源
47
     * @type ThyTransferItem[]
171✔
48
     */
95✔
49
    @Input()
50
    set thyData(value: ThyTransferItem[]) {
51
        if (value) {
52
            this.initializeTransferData(value);
53
        }
13!
UNCOV
54
    }
×
55

56
    @Input() thyrenderLeftTemplateRef: TemplateRef<any>;
13✔
57

2✔
58
    @Input() thyrenderRightTemplateRef: TemplateRef<any>;
59

11✔
60
    /**
11✔
61
     * title集合,title[0]为左标题,title[1]为右标题
11!
62
     * @type string[]
11✔
63
     */
64
    @Input()
65
    set thyTitles(value: string[]) {
66
        this.leftTitle = value[0] || '';
1✔
67
        this.rightTitle = value[1] || '';
68
    }
69

2✔
70
    /**
71
     * 右侧列表是否可以锁定
×
72
     * @default false
26✔
73
     */
26✔
74
    @Input() thyRightCanLock: boolean;
115✔
75

11✔
76
    /**
77
     * 右侧锁定最大数量
78
     */
104✔
79
    @Input() thyRightLockMax: number;
80

81
    /**
26✔
82
     * 右侧选择最大数量
83
     */
84
    @Input() thyRightMax: number;
11✔
85

11✔
86
    /**
51✔
87
     * 设置是否自动移动
11✔
88
     * @description.en-us Currently not implemented, in order to support the selections move
11✔
89
     * @default true
90
     */
91
    @Input()
92
    set thyAutoMove(value: boolean) {
11✔
93
        this._autoMove = value;
11✔
94
    }
11✔
95

11✔
96
    /**
11✔
97
     * 左侧列表是否拖动
11✔
98
     * @default false
99
     */
11✔
100
    @Input() thyLeftDraggable: boolean;
101

102
    /**
103
     * 右侧列表是否拖动
104
     * @default false
105
     */
106
    @Input() thyRightDraggable: boolean;
4!
107

4✔
108
    /**
4✔
109
     * @type EventEmitter<ThyTransferDragEvent>
110
     */
4!
111
    @Output() thyDraggableUpdate: EventEmitter<ThyTransferDragEvent> = new EventEmitter<ThyTransferDragEvent>();
4!
112

113
    /**
4✔
114
     * Transfer变化的回调事件
4!
115
     * @type EventEmitter<ThyTransferChangeEvent>
116
     */
117
    @Output() thyChange: EventEmitter<ThyTransferChangeEvent> = new EventEmitter<ThyTransferChangeEvent>();
118

1✔
119
    /**
120
     * 设置自定义Item渲染数据模板
121
     * @type TemplateRef
122
     */
123
    @ContentChild('renderTemplate') templateRef: TemplateRef<any>;
124

125
    /**
126
     * 设置自定义左侧内容模板
127
     * @type TemplateRef
128
     */
129
    @ContentChild('renderLeftTemplate') leftContentRef: TemplateRef<any>;
130

131
    /**
132
     * 设置自定义右侧内容模板
133
     * @type TemplateRef
134
     */
135
    @ContentChild('renderRightTemplate') rightContentRef: TemplateRef<any>;
136

137
    ngOnInit() {}
1✔
138

139
    initializeTransferData(data: ThyTransferItem[] = []) {
140
        this.allDataSource = [];
141
        this.leftDataSource = [];
142
        this.rightDataSource = [];
143
        data.forEach(item => {
144
            this.allDataSource.push(item);
145
            if (item.direction === TransferDirection.left) {
146
                this.leftDataSource.push(item);
147
            }
148
            if (item.direction === TransferDirection.right) {
149
                this.rightDataSource.push(item);
150
            }
151
        });
152
    }
153

154
    onSelect(from: Direction, event: ThyTransferSelectEvent) {
155
        if (event.item.isFixed) {
156
            return;
157
        }
158
        if (this.thyRightMax <= this.rightDataSource.length && from === TransferDirection.left) {
159
            return;
160
        }
161
        const to = from === TransferDirection.left ? TransferDirection.right : TransferDirection.left;
162
        event.item.checked = !event.item.checked;
163
        if (this._autoMove) {
164
            this.onMove(to);
165
        }
166
    }
167

168
    selectItem(event: ThyTransferSelectEvent) {
169
        this.onSelect(TransferDirection.left, event);
170
    }
171

172
    unselectItem(event: ThyTransferSelectEvent) {
173
        this.onSelect(TransferDirection.right, event);
174
    }
175

176
    private groupListByIsLock(list: ThyTransferItem[] = []) {
177
        const lock: ThyTransferItem[] = [],
178
            unlock: ThyTransferItem[] = [];
179
        list.forEach(item => {
180
            if (item.isLock) {
181
                lock.push(item);
182
            } else {
183
                unlock.push(item);
184
            }
185
        });
186
        return { lock: lock, unlock: unlock };
187
    }
188

189
    onMove(to: Direction) {
190
        const fromDataSource = to === TransferDirection.right ? this.leftDataSource : this.rightDataSource;
191
        const toDataSource = to === TransferDirection.right ? this.rightDataSource : this.leftDataSource;
192
        const selections = fromDataSource.filter(item => item.checked);
193
        const changeEvent: ThyTransferChangeEvent = {
194
            from: to === TransferDirection.right ? TransferDirection.left : TransferDirection.right,
195
            to: to,
196
            items: [...selections]
197
        };
198
        selections.forEach(item => {
199
            const index = fromDataSource.indexOf(item);
200
            const removed = fromDataSource.splice(index, 1)[0];
201
            removed.checked = !removed.checked;
202
            removed.direction = to;
203
            toDataSource.push(removed);
204
        });
205
        this.thyChange.emit({
206
            ...changeEvent,
207
            left: this.groupListByIsLock(this.leftDataSource),
208
            right: this.groupListByIsLock(this.rightDataSource)
209
        });
210
    }
211

212
    onDragUpdate(direction: Direction, event: InnerTransferDragEvent) {
213
        const otherDirectionData = direction === TransferDirection.left ? this.rightDataSource : this.leftDataSource;
214
        const otherListData = this.groupListByIsLock(otherDirectionData);
215
        this.thyDraggableUpdate.emit({
216
            ...event.dragEvent,
217
            left: direction === TransferDirection.left ? event.listData : otherListData,
218
            right: direction === TransferDirection.right ? event.listData : otherListData
219
        });
220

221
        this.rightDataSource =
222
            direction === TransferDirection.right
223
                ? [...event.listData.lock, ...event.listData.unlock]
224
                : [...otherListData.lock, ...otherListData.unlock];
225
    }
226
}
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

© 2026 Coveralls, Inc