UNPKG

8.3 kBPlain TextView Raw
1import {
2 DragAndDropService, DraggingEvent, DragSourceType, DropTarget,
3 VDirection
4} from "../dragAndDrop/dragAndDropService";
5import {Autowired, Optional, PostConstruct} from "../context/context";
6import {ClientSideRowModel} from "../rowModels/clientSide/clientSideRowModel";
7import {FocusedCellController} from "../focusedCellController";
8import {IRangeController} from "../interfaces/iRangeController";
9import {GridPanel} from "./gridPanel";
10import {GridOptionsWrapper} from "../gridOptionsWrapper";
11import {EventService} from "../eventService";
12import {RowDragEvent} from "../events";
13import {Events} from "../eventKeys";
14import {IRowModel} from "../interfaces/iRowModel";
15
16export class RowDragFeature implements DropTarget {
17
18 @Autowired('dragAndDropService') private dragAndDropService: DragAndDropService;
19 // this feature is only created when row model is ClientSide, so we can type it as ClientSide
20 @Autowired('rowModel') private rowModel: IRowModel;
21 @Autowired('focusedCellController') private focusedCellController: FocusedCellController;
22 @Autowired('gridOptionsWrapper') private gridOptionsWrapper: GridOptionsWrapper;
23 @Optional('rangeController') private rangeController: IRangeController;
24 @Autowired('eventService') private eventService: EventService;
25
26 private gridPanel: GridPanel;
27
28 private clientSideRowModel: ClientSideRowModel;
29
30 private eContainer: HTMLElement;
31
32 private needToMoveUp: boolean;
33 private needToMoveDown: boolean;
34
35 private movingIntervalId: number;
36 private intervalCount: number;
37
38 private lastDraggingEvent: DraggingEvent;
39
40 constructor(eContainer: HTMLElement, gridPanel: GridPanel) {
41 this.eContainer = eContainer;
42 this.gridPanel = gridPanel;
43 }
44
45 @PostConstruct
46 private postConstruct(): void {
47 if (this.gridOptionsWrapper.isRowModelDefault()) {
48 this.clientSideRowModel = <ClientSideRowModel> this.rowModel;
49 }
50 }
51
52 public getContainer(): HTMLElement {
53 return this.eContainer;
54 }
55
56 public isInterestedIn(type: DragSourceType): boolean {
57 return type===DragSourceType.RowDrag;
58 }
59
60 public getIconName(): string {
61 return DragAndDropService.ICON_MOVE;
62 }
63
64 public onDragEnter(draggingEvent: DraggingEvent): void {
65 // when entering, we fire the enter event, then in onEnterOrDragging,
66 // we also fire the move event. so we get both events when entering.
67 this.dispatchEvent(Events.EVENT_ROW_DRAG_ENTER, draggingEvent);
68 this.dragAndDropService.setGhostIcon(DragAndDropService.ICON_MOVE);
69 draggingEvent.dragItem.rowNode.setDragging(true);
70 this.onEnterOrDragging(draggingEvent);
71 }
72
73 public onDragging(draggingEvent: DraggingEvent): void {
74 this.onEnterOrDragging(draggingEvent);
75 }
76
77 private onEnterOrDragging(draggingEvent: DraggingEvent): void {
78 // this event is fired for enter and move
79 this.dispatchEvent(Events.EVENT_ROW_DRAG_MOVE, draggingEvent);
80
81 this.lastDraggingEvent = draggingEvent;
82 let pixel = this.normaliseForScroll(draggingEvent.y);
83
84 let managedDrag = this.gridOptionsWrapper.isRowDragManaged();
85 if (managedDrag) {
86 this.doManagedDrag(draggingEvent, pixel);
87 }
88
89 this.checkCenterForScrolling(pixel);
90 }
91
92 private doManagedDrag(draggingEvent: DraggingEvent, pixel: number): void {
93 let rowNode = draggingEvent.dragItem.rowNode;
94 let rowWasMoved = this.clientSideRowModel.ensureRowAtPixel(rowNode, pixel);
95
96 if (rowWasMoved) {
97 this.focusedCellController.clearFocusedCell();
98 if (this.rangeController) {
99 this.rangeController.clearSelection();
100 }
101 }
102 }
103
104 private normaliseForScroll(pixel: number): number {
105 let gridPanelHasScrolls = !this.gridOptionsWrapper.isGridAutoHeight();
106 if (gridPanelHasScrolls) {
107 let pixelRange = this.gridPanel.getVScrollPosition();
108 return pixel + pixelRange.top;
109 } else {
110 return pixel;
111 }
112 }
113
114 private checkCenterForScrolling(pixel: number): void {
115
116 // scroll if the mouse is within 50px of the grid edge
117 let pixelRange = this.gridPanel.getVScrollPosition();
118
119 // console.log(`pixelRange = (${pixelRange.top}, ${pixelRange.bottom})`);
120
121 this.needToMoveUp = pixel < (pixelRange.top + 50);
122 this.needToMoveDown = pixel > (pixelRange.bottom - 50);
123
124 // console.log(`needToMoveUp = ${this.needToMoveUp} = pixel < (pixelRange.top + 50) = ${pixel} < (${pixelRange.top} + 50)`);
125 // console.log(`needToMoveDown = ${this.needToMoveDown} = pixel < (pixelRange.top + 50) = ${pixel} < (${pixelRange.top} + 50)`);
126
127 if (this.needToMoveUp || this.needToMoveDown) {
128 this.ensureIntervalStarted();
129 } else {
130 this.ensureIntervalCleared();
131 }
132 }
133
134 private ensureIntervalStarted(): void {
135 if (!this.movingIntervalId) {
136 this.intervalCount = 0;
137 this.movingIntervalId = setInterval(this.moveInterval.bind(this), 100);
138 }
139 }
140
141 private ensureIntervalCleared(): void {
142 if (this.moveInterval) {
143 clearInterval(this.movingIntervalId);
144 this.movingIntervalId = null;
145 }
146 }
147
148 private moveInterval(): void {
149 // the amounts we move get bigger at each interval, so the speed accelerates, starting a bit slow
150 // and getting faster. this is to give smoother user experience. we max at 100px to limit the speed.
151 let pixelsToMove: number;
152 this.intervalCount++;
153 pixelsToMove = 10 + (this.intervalCount * 5);
154 if (pixelsToMove > 100) {
155 pixelsToMove = 100;
156 }
157
158 let pixelsMoved: number;
159 if (this.needToMoveDown) {
160 pixelsMoved = this.gridPanel.scrollVertically(pixelsToMove);
161 } else if (this.needToMoveUp) {
162 pixelsMoved = this.gridPanel.scrollVertically(-pixelsToMove);
163 }
164
165 if (pixelsMoved !== 0) {
166 this.onDragging(this.lastDraggingEvent);
167 }
168 }
169
170 // i tried using generics here with this:
171 // public createEvent<T extends RowDragEvent>(type: string, clazz: {new(): T; }, draggingEvent: DraggingEvent) {
172 // but it didn't work - i think it's because it only works with classes, and not interfaces, (the events are interfaces)
173 public dispatchEvent(type: string, draggingEvent: DraggingEvent): void {
174
175 let yNormalised = this.normaliseForScroll(draggingEvent.y);
176
177 let overIndex = -1;
178 let overNode = null;
179 let mouseIsPastLastRow = yNormalised > this.rowModel.getCurrentPageHeight();
180
181 if (!mouseIsPastLastRow) {
182 overIndex = this.rowModel.getRowIndexAtPixel(yNormalised);
183 overNode = this.rowModel.getRow(overIndex);
184 }
185
186 let vDirectionString: string;
187 switch (draggingEvent.vDirection) {
188 case VDirection.Down:
189 vDirectionString = 'down';
190 break;
191 case VDirection.Up:
192 vDirectionString = 'up';
193 break;
194 default:
195 vDirectionString = null;
196 break;
197 }
198
199 let event: RowDragEvent = {
200 type: type,
201 api: this.gridOptionsWrapper.getApi(),
202 columnApi: this.gridOptionsWrapper.getColumnApi(),
203 event: draggingEvent.event,
204 node: draggingEvent.dragItem.rowNode,
205 overIndex: overIndex,
206 overNode: overNode,
207 y: yNormalised,
208 vDirection: vDirectionString
209 };
210
211 this.eventService.dispatchEvent(event);
212 }
213
214 public onDragLeave(draggingEvent: DraggingEvent): void {
215 this.dispatchEvent(Events.EVENT_ROW_DRAG_LEAVE, draggingEvent);
216 this.stopDragging(draggingEvent);
217 }
218
219 public onDragStop(draggingEvent: DraggingEvent): void {
220 this.dispatchEvent(Events.EVENT_ROW_DRAG_END, draggingEvent);
221 this.stopDragging(draggingEvent);
222 }
223
224 private stopDragging(draggingEvent: DraggingEvent): void {
225 this.ensureIntervalCleared();
226 draggingEvent.dragItem.rowNode.setDragging(false);
227 }
228}
\No newline at end of file