From f09916f921e78420b5ca168ca82aa81379f0f9f3 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sat, 20 Jun 2020 16:13:40 +0200 Subject: [PATCH] fix(drag-drop): error when cloning 0x0 canvas We have some logic to clone the `canvas` elements inside the drag preview, but the process that transfers the content can throw if the canvas is invisible. These changes add a try/catch to prevent the entire process from breaking down. --- src/cdk/drag-drop/directives/drag.spec.ts | 37 +++++++++++++++++++++++ src/cdk/drag-drop/drag-ref.ts | 6 +++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/cdk/drag-drop/directives/drag.spec.ts b/src/cdk/drag-drop/directives/drag.spec.ts index 97077253ebe3..6534c56828b1 100644 --- a/src/cdk/drag-drop/directives/drag.spec.ts +++ b/src/cdk/drag-drop/directives/drag.spec.ts @@ -2151,6 +2151,19 @@ describe('CdkDrag', () => { 'Expected cloned canvas to have the same content as the source.'); })); + it('should not throw when cloning an invalid canvas', fakeAsync(() => { + const fixture = createComponent(DraggableWithInvalidCanvasInDropZone); + fixture.detectChanges(); + const item = fixture.componentInstance.dragItems.toArray()[1].element.nativeElement; + + expect(() => { + startDraggingViaMouse(fixture, item); + tick(); + }).not.toThrow(); + + expect(document.querySelector('.cdk-drag-preview canvas')).toBeTruthy(); + })); + it('should clear the ids from descendants of the preview', fakeAsync(() => { const fixture = createComponent(DraggableInDropZone); fixture.detectChanges(); @@ -5949,6 +5962,30 @@ class DraggableWithCanvasInDropZone extends DraggableInDropZone implements After } } +@Component({ + template: ` +
+
+ {{item.value}} + +
+
+ ` +}) +class DraggableWithInvalidCanvasInDropZone extends DraggableInDropZone {} + /** * Component that passes through whatever content is projected into it. * Used to test having drag elements being projected into a component. diff --git a/src/cdk/drag-drop/drag-ref.ts b/src/cdk/drag-drop/drag-ref.ts index c1aa23e0850f..699e4660f290 100644 --- a/src/cdk/drag-drop/drag-ref.ts +++ b/src/cdk/drag-drop/drag-ref.ts @@ -1292,7 +1292,11 @@ function deepCloneNode(node: HTMLElement): HTMLElement { const correspondingCloneContext = cloneCanvases[i].getContext('2d'); if (correspondingCloneContext) { - correspondingCloneContext.drawImage(descendantCanvases[i], 0, 0); + // In some cases `drawImage` can throw (e.g. if the canvas size is 0x0). + // We can't do much about it so just ignore the error. + try { + correspondingCloneContext.drawImage(descendantCanvases[i], 0, 0); + } catch {} } } }