• 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

0.63
/src/drag-drop/drag-ref.ts
1
import { NgZone, ElementRef, Renderer2 } from '@angular/core';
2
import { coerceElement } from '@angular/cdk/coercion';
3
import { Subject, fromEvent } from 'rxjs';
4
import { auditTime, takeUntil } from 'rxjs/operators';
5
import { ThyDragDropService } from './drag-drop.service';
6
import { ThyDragStartEvent, ThyDragEndEvent, ThyDragOverEvent, ThyDragDropEvent, ThyDropPosition } from './drag-drop.class';
1✔
7
import { IThyDragDirective, IThyDragHandleDirective, IThyDropContainerDirective } from './drag-drop.token';
8
import { coerceArray, isEmpty, isString } from 'ngx-tethys/util';
9

10
const dropPositionClass = {
11
    [ThyDropPosition.in]: 'thy-drop-position-in',
12
    [ThyDropPosition.before]: 'thy-drop-position-before',
UNCOV
13
    [ThyDropPosition.after]: 'thy-drop-position-after'
×
14
};
15

UNCOV
16
export class DragRef<T = any> {
×
17
    private rootElement: HTMLElement;
18

UNCOV
19
    private contentElement: HTMLElement;
×
UNCOV
20

×
UNCOV
21
    private target: HTMLElement;
×
UNCOV
22

×
UNCOV
23
    private handles: IThyDragHandleDirective[];
×
UNCOV
24

×
UNCOV
25
    private ngUnsubscribe$ = new Subject();
×
UNCOV
26

×
UNCOV
27
    started = new Subject<ThyDragStartEvent>();
×
UNCOV
28

×
UNCOV
29
    ended = new Subject<ThyDragEndEvent>();
×
UNCOV
30

×
UNCOV
31
    overed = new Subject<ThyDragOverEvent>();
×
UNCOV
32

×
UNCOV
33
    dropped = new Subject<ThyDragDropEvent>();
×
UNCOV
34

×
UNCOV
35
    entered = new Subject<DragEvent>();
×
36

37
    leaved = new Subject<DragEvent>();
UNCOV
38

×
UNCOV
39
    private _disabled = false;
×
UNCOV
40

×
UNCOV
41
    get disabled(): boolean {
×
42
        return (this.container && this.container.disabled) || this._disabled;
43
    }
44
    set disabled(value: boolean) {
UNCOV
45
        this._disabled = value;
×
UNCOV
46
    }
×
UNCOV
47

×
UNCOV
48
    private addPositionClass$ = new Subject<{ element: HTMLElement; class: string }>();
×
49

50
    constructor(
UNCOV
51
        element: ElementRef<HTMLElement> | HTMLElement,
×
UNCOV
52
        private drag: IThyDragDirective,
×
53
        private container: IThyDropContainerDirective<T>,
54
        private dragDropService: ThyDragDropService<T>,
UNCOV
55
        private document: any,
×
UNCOV
56
        private ngZone: NgZone,
×
57
        private renderer: Renderer2
58
    ) {
UNCOV
59
        this.withRootElement(element);
×
60
        this.subAddPositionClass();
61
    }
62

63
    subAddPositionClass() {
64
        this.addPositionClass$.pipe(auditTime(30), takeUntil(this.ngUnsubscribe$)).subscribe(data => {
65
            this.removeExistClassByMap(this.dragDropService.classMap);
UNCOV
66
            this.dragDropService.classMap.set(data.element, data.class);
×
67
            this.renderer.addClass(data.element, data.class);
68
        });
UNCOV
69
    }
×
70

71
    withRootElement(rootElement: ElementRef<HTMLElement> | HTMLElement): this {
UNCOV
72
        const element = coerceElement(rootElement);
×
UNCOV
73
        this.rootElement = element;
×
UNCOV
74
        this.registerDragDropEvents();
×
UNCOV
75
        return this;
×
76
    }
77

78
    withContentElement(contentElement: ElementRef<HTMLElement> | HTMLElement): this {
79
        this.contentElement = coerceElement(contentElement);
80
        return this;
UNCOV
81
    }
×
UNCOV
82

×
83
    withHandles(handleOrHandles: IThyDragHandleDirective | IThyDragHandleDirective[]): this {
84
        this.handles = coerceArray(handleOrHandles);
85
        return this;
86
    }
87

UNCOV
88
    private registerDragDropEvents() {
×
UNCOV
89
        const events = {
×
UNCOV
90
            dragstart: this.dragStart,
×
91
            dragover: this.dragOver,
UNCOV
92
            dragend: this.dragEnd,
×
UNCOV
93
            drop: this.dragDrop,
×
UNCOV
94
            dragleave: this.dragLeave,
×
95
            dragenter: (event: DragEvent) => {
96
                this.entered.next(event);
97
            },
UNCOV
98
            mouseover: (event: MouseEvent) => {
×
99
                this.target = event.target as HTMLElement;
×
100
            }
×
101
        };
102
        this.ngZone.runOutsideAngular(() => {
×
103
            for (const name in events) {
104
                if (events.hasOwnProperty(name)) {
UNCOV
105
                    fromEvent(this.rootElement, name).pipe(takeUntil(this.ngUnsubscribe$)).subscribe(events[name].bind(this));
×
106
                }
107
            }
108
        });
UNCOV
109
    }
×
UNCOV
110

×
UNCOV
111
    private dragStart(event: DragEvent) {
×
112
        event.stopPropagation();
113
        const dragStartEvent: ThyDragStartEvent = {
114
            event: event,
×
115
            item: this.drag.data,
116
            containerItems: this.container.data,
117
            currentIndex: this.container.data.indexOf(this.drag.data)
UNCOV
118
        };
×
119
        if (this.disabled || !this.isTriggerHandle() || (this.container.beforeStart && !this.container.beforeStart(dragStartEvent))) {
×
120
            event.preventDefault();
UNCOV
121
            return false;
×
UNCOV
122
        }
×
123
        this.dragDropService.previousDrag = this.drag;
124
        this.ngZone.run(() => {
×
125
            this.started.next(dragStartEvent);
126
        });
UNCOV
127
    }
×
UNCOV
128

×
UNCOV
129
    private isTriggerHandle() {
×
UNCOV
130
        if (this.handles && this.handles.length > 0) {
×
UNCOV
131
            const targetHandle = this.handles.find(handle => {
×
UNCOV
132
                return (
×
133
                    !handle.disabled && (handle.element.nativeElement === this.target || handle.element.nativeElement.contains(this.target))
UNCOV
134
                );
×
135
            });
136
            return !!targetHandle;
137
        } else {
138
            return true;
139
        }
140
    }
141

UNCOV
142
    private getPreviousEventData() {
×
UNCOV
143
        const previousItem = this.dragDropService.previousDrag?.data;
×
UNCOV
144
        const previousContainerItems = this.dragDropService.previousDrag?.container?.data;
×
145
        return {
146
            previousItem: previousItem,
147
            previousContainerItems,
UNCOV
148
            previousIndex: isEmpty(previousContainerItems) ? -1 : previousContainerItems.indexOf(previousItem)
×
UNCOV
149
        };
×
UNCOV
150
    }
×
151

152
    private isContinueDragOver(event: ThyDragOverEvent, container: IThyDropContainerDirective<T>) {
UNCOV
153
        if (event.item === event.previousItem && event.position === ThyDropPosition.in) {
×
UNCOV
154
            return false;
×
UNCOV
155
        }
×
UNCOV
156
        if (container && container.beforeOver) {
×
UNCOV
157
            return container.beforeOver(event);
×
158
        }
UNCOV
159
        return true;
×
160
    }
161

162
    private dragOver(event: DragEvent) {
163
        event.stopPropagation();
164
        event.preventDefault();
165

166
        const dropPosition = this.calcDropPosition(event);
UNCOV
167
        const previousEventData = this.getPreviousEventData();
×
168
        if (previousEventData.previousIndex < 0) {
×
169
            return;
×
170
        }
UNCOV
171
        const dragOverEvent: ThyDragOverEvent<T> = {
×
UNCOV
172
            event: event,
×
173
            item: this.drag.data,
174
            containerItems: this.drag.container.data,
175
            currentIndex: this.container.data.indexOf(this.drag.data),
UNCOV
176
            position: dropPosition,
×
UNCOV
177
            ...previousEventData
×
UNCOV
178
        };
×
179

180
        if (this.isContinueDragOver(dragOverEvent, this.container)) {
181
            this.dragOverHandler(dropPosition);
182
            this.overed.next(dragOverEvent);
183
        }
UNCOV
184
    }
×
185

186
    private dragOverHandler(position: ThyDropPosition) {
UNCOV
187
        const element = this.contentElement || this.rootElement;
×
UNCOV
188
        this.addPositionClass$.next({ element, class: dropPositionClass[position] });
×
UNCOV
189
        this.dragDropService.dropPosition = position;
×
190
    }
191

UNCOV
192
    private dragDrop(event: DragEvent) {
×
UNCOV
193
        event.stopPropagation();
×
UNCOV
194
        this.clearDragPositionClass();
×
UNCOV
195
        const previousEventData = this.getPreviousEventData();
×
196
        if (previousEventData.previousIndex < 0) {
197
            return;
198
        }
UNCOV
199
        const dragDropEvent: ThyDragDropEvent<T> = {
×
UNCOV
200
            event: event,
×
UNCOV
201
            item: this.drag.data,
×
202
            containerItems: this.drag.container.data,
203
            currentIndex: this.container.data.indexOf(this.drag.data),
204
            position: this.calcDropPosition(event),
205
            ...previousEventData
UNCOV
206
        };
×
UNCOV
207
        if (this.dragDropService.previousDrag === this.drag || (this.container.beforeDrop && !this.container.beforeDrop(dragDropEvent))) {
×
UNCOV
208
            event.preventDefault();
×
UNCOV
209
            return;
×
210
        }
211
        this.ngZone.run(() => {
UNCOV
212
            this.dropped.next(dragDropEvent);
×
UNCOV
213
        });
×
UNCOV
214
    }
×
215

216
    private dragEnd(event: DragEvent) {
×
217
        this.clearDragPositionClass();
×
218
        this.ngZone.run(() => {
219
            this.ended.next({
×
220
                event: event,
221
                item: this.drag.data,
UNCOV
222
                containerItems: this.container.data
×
223
            });
224
        });
225
        this.dragDropService.previousDrag = undefined;
226
    }
227

228
    private dragLeave(event: DragEvent) {
229
        event.stopPropagation();
230
        this.clearDragPositionClass();
231
        this.leaved.next(event);
232
    }
233

234
    private clearDragPositionClass() {
235
        setTimeout(() => {
236
            const classMap = this.dragDropService.classMap;
237
            this.removeExistClassByMap(classMap);
238
            classMap.clear();
239
        }, 30);
240
    }
241

242
    private removeExistClassByMap(classMap: Map<Element, string>) {
243
        classMap.forEach((value, key) => {
244
            if (isString(value) && key) {
245
                this.renderer.removeClass(key, value);
246
            }
247
        });
248
    }
249

250
    private calcDropPosition(event: DragEvent): ThyDropPosition {
251
        const sideRange = 0.25;
252
        const minGap = 2;
253
        const { clientY } = event;
254
        const { top, bottom, height } = event.srcElement
255
            ? (event.srcElement as Element).getBoundingClientRect()
256
            : (event.target as Element).getBoundingClientRect();
257
        const des = Math.max(height * sideRange, minGap);
258
        if (clientY <= top + des) {
259
            return ThyDropPosition.before;
260
        } else if (clientY >= bottom - des) {
261
            return ThyDropPosition.after;
262
        }
263
        return ThyDropPosition.in;
264
    }
265

266
    dispose() {
267
        this.ngUnsubscribe$.complete();
268
    }
269
}
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