Skip to content

Commit 6dd26c6

Browse files
committed
wip(card-list): workaround longstanding chromium 'immediate dragend' bug
1 parent 64c1421 commit 6dd26c6

File tree

1 file changed

+36
-43
lines changed

1 file changed

+36
-43
lines changed

packages/angular-skyhook-card-list/src/card-renderer.directive.ts

Lines changed: 36 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ export interface CardRendererContext<Data> {
2323
spec: SortableSpec<Data>;
2424
}
2525

26+
const _scheduleMicroTaskPolyfill: (f: () => void) => any = (
27+
requestAnimationFrame || webkitRequestAnimationFrame || ((f: () => void) => setTimeout(f, 0))
28+
)
29+
2630
@Directive({
2731
selector: '[cardRenderer]',
2832
exportAs: 'cardRenderer'
@@ -60,44 +64,18 @@ export class CardRendererDirective<Data> implements OnInit, OnDestroy {
6064
return this.isDragging(item);
6165
},
6266
beginDrag: () => {
63-
let item: DraggedItem<Data> = {
64-
data: this.data,
65-
index: this.index,
66-
size: this.size(),
67-
type: this.type,
68-
isInternal: true,
69-
listId: this.listId,
70-
hover: {
71-
index: this.index,
72-
listId: this.listId
73-
}
74-
};
75-
// if (this.spec && this.spec.copy && this.spec.copy(item)) {
76-
// if (!this.spec.clone) {
77-
// throw new Error("must provide clone function");
78-
// }
79-
// let clone = this.spec.clone(item.data);
80-
// if (clone !== item.data || this.sameIds(item.data, clone)) {
81-
// throw new Error("clone must return a new object with a different id / trackBy result");
82-
// }
83-
// item.data = clone;
84-
// item.hover.index ++;
85-
// item.isCopy = true;
86-
// }
87-
this.spec && this.spec.beginDrag && this.spec.beginDrag(item);
88-
// if (item.isCopy) {
89-
// // Chrome bug means an immediate dragend would fire
90-
// // if you did this synchronously
91-
// let canDrop = true;
92-
// if (this.spec && this.spec.canDrop) {
93-
// canDrop = this.spec.canDrop(item);
94-
// }
95-
// if (canDrop) {
96-
// setTimeout(() => {
97-
// this.spec && this.spec.hover && this.spec.hover(item);
98-
// }, 0);
99-
// }
100-
// }
67+
const item = this.createItem();
68+
69+
// Chromium bug since 2016: if you modify styles or DOM
70+
// synchronously within 'dragstart' handler, Chrome fires
71+
// a 'dragend' immediately.
72+
//
73+
// https://bugs.chromium.org/p/chromium/issues/detail?id=674882
74+
// although recommended Promise.resolve().then() doesn't work.
75+
this.spec && this.spec.beginDrag && _scheduleMicroTaskPolyfill(() => {
76+
this.spec.beginDrag(item);
77+
});
78+
10179
return item;
10280
},
10381
endDrag: monitor => {
@@ -116,11 +94,26 @@ export class CardRendererDirective<Data> implements OnInit, OnDestroy {
11694
) {
11795
}
11896

119-
sameIds = (data: Data, other: DraggedItem<Data>) => {
97+
private createItem(): DraggedItem<Data> {
98+
return {
99+
data: this.data,
100+
index: this.index,
101+
size: this.size(),
102+
type: this.type,
103+
isInternal: true,
104+
listId: this.listId,
105+
hover: {
106+
index: this.index,
107+
listId: this.listId
108+
}
109+
};
110+
}
111+
112+
private sameIds = (data: Data, other: DraggedItem<Data>) => {
120113
return data && other.data && this.spec.trackBy(data) === this.spec.trackBy(other.data);
121114
}
122115

123-
isDragging(item: DraggedItem<Data> | null) {
116+
private isDragging(item: DraggedItem<Data> | null) {
124117
const isD = this.spec && this.spec.isDragging || this.sameIds;
125118
return item && isD(this.data, item) || false;
126119
}
@@ -179,11 +172,11 @@ export class CardRendererDirective<Data> implements OnInit, OnDestroy {
179172
suggestedIndex = topHalf ? this.index : this.index + 1;
180173
}
181174

182-
// happens if you're copying from index=0
175+
// happens if you aren't implementing SortableSpec correctly.
183176
if (suggestedIndex < 0) {
184177
// console.warn('this.listId',this.listId, 'hover.listId', hover.listId)
185178
// suggestedIndex = 0;
186-
throw new Error("angular-skyhook-sortable: tried to move a card to an index < 0");
179+
throw new Error("angular-skyhook-sortable: Cannot move a card to an index < 0.");
187180
}
188181

189182
// move the item if its new position is different
@@ -206,7 +199,7 @@ export class CardRendererDirective<Data> implements OnInit, OnDestroy {
206199
/** @ignore */
207200
rect() {
208201
if (!this.el) {
209-
throw new Error("cardRenderer expected to be attached to a real DOM element");
202+
throw new Error("angular-skyhook-sortable: cardRenderer expected to be attached to a real DOM element");
210203
}
211204
const rect = (this.el.nativeElement as Element).getBoundingClientRect();
212205
return rect;

0 commit comments

Comments
 (0)