Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Drawing threads now destroy their event handlers properly #317

Merged
merged 2 commits into from Dec 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/AnnotationThread.js
Expand Up @@ -102,10 +102,9 @@ class AnnotationThread extends EventEmitter {
destroy() {
this.threadID = null;
this.unmountPopover();
this.unbindDOMListeners();

if (this.element) {
this.unbindDOMListeners();

if (this.element.parentNode) {
this.element.parentNode.removeChild(this.element);
}
Expand Down
2 changes: 0 additions & 2 deletions src/controllers/DrawingModeController.js
Expand Up @@ -166,8 +166,6 @@ class DrawingModeController extends AnnotationModeController {
this.pushElementHandler(this.redoButtonEl, 'click', this.redoDrawing);

// Mobile & Desktop listeners are bound for touch-enabled laptop edge cases
// $FlowFixMe
this.drawingStartHandler = this.drawingStartHandler.bind(this);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicated code, as this.drawingStartHandler is already bound on line 160.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

this.pushElementHandler(this.annotatedElement, ['mousedown', 'touchstart'], this.drawingStartHandler, true);
}

Expand Down
9 changes: 9 additions & 0 deletions src/doc/DocDrawingThread.js
Expand Up @@ -147,6 +147,15 @@ class DocDrawingThread extends DrawingThread {
return !!(location && !!this.location && !!this.location.page && this.location.page !== location.page);
}

/** @inheritdoc */
destroy() {
if (this.drawingContext && this.drawingContext.canvas && this.drawingContext.canvas.parentNode) {
this.drawingContext.canvas.parentNode.removeChild(this.drawingContext.canvas);
}

super.destroy();
}

/**
* Display the document drawing thread. Will set the drawing context if the scale has changed since the last show.
*
Expand Down
22 changes: 22 additions & 0 deletions src/doc/__tests__/DocDrawingThread-test.js
Expand Up @@ -320,6 +320,7 @@ describe('doc/DocDrawingThread', () => {

it('should return the pending drawing context when the state is pending', () => {
thread.state = STATES.pending;
thread.destroy = jest.fn();
thread.drawingContext = {
clearRect: jest.fn(),
canvas: {
Expand Down Expand Up @@ -381,4 +382,25 @@ describe('doc/DocDrawingThread', () => {
expect(value).toStrictEqual([5, 5, 45, 40]);
});
});

describe('destroy()', () => {
it('should remove the drawing canvas from the DOM if present', () => {
const removeFn = jest.fn();

thread.drawingContext = {
clearRect: jest.fn(),
canvas: {
height: 100,
parentNode: {
removeChild: removeFn
},
width: 100
}
};

thread.destroy();

expect(removeFn).toHaveBeenCalled();
});
});
});
52 changes: 25 additions & 27 deletions src/drawing/DrawingThread.js
Expand Up @@ -15,6 +15,12 @@ class DrawingThread extends AnnotationThread {
/** @property {number} - Drawing state */
drawingFlag = DRAW_STATES.idle;

/** @property {Function} Handler for drawing start events */
userMoveHandler;

/** @property {Function} Handler for drawing stop events */
userStopHandler;

/** @property {DrawingContainer} - The path container supporting undo and redo */
pathContainer = new DrawingContainer();

Expand Down Expand Up @@ -96,7 +102,6 @@ class DrawingThread extends AnnotationThread {
window.cancelAnimationFrame(this.lastAnimationRequestId);
}

this.unmountPopover();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already done as part of super.destroy().

this.reset();
super.destroy();

Expand Down Expand Up @@ -124,43 +129,36 @@ class DrawingThread extends AnnotationThread {
* @return {void}
*/
bindDrawingListeners(locationFunction) {
this.userMoveHandler = eventToLocationHandler(locationFunction, this.handleMove);
this.userStopHandler = eventToLocationHandler(locationFunction, this.handleStop);

if (this.hasTouch) {
this.annotatedElement.addEventListener(
'touchmove',
eventToLocationHandler(locationFunction, this.handleMove)
);
this.annotatedElement.addEventListener(
'touchcancel',
eventToLocationHandler(locationFunction, this.handleStop)
);
this.annotatedElement.addEventListener(
'touchend',
eventToLocationHandler(locationFunction, this.handleStop)
);
this.annotatedElement.addEventListener('touchmove', this.userMoveHandler);
this.annotatedElement.addEventListener('touchcancel', this.userStopHandler);
this.annotatedElement.addEventListener('touchend', this.userStopHandler);
} else {
this.annotatedElement.addEventListener(
'mousemove',
eventToLocationHandler(locationFunction, this.handleMove)
);
this.annotatedElement.addEventListener(
'mouseup',
eventToLocationHandler(locationFunction, this.handleStop)
);
this.annotatedElement.addEventListener('mousemove', this.userMoveHandler);
this.annotatedElement.addEventListener('mouseup', this.userStopHandler);
}
}

/** @inheritdoc */
unbindDOMListeners() {
this.unbindDrawingListeners();
super.unbindDOMListeners();
}

/**
* Unbinds DOM event listeners for drawing new threads.
*
* @return {void}
*/
unbindDrawingListeners() {
this.annotatedElement.removeEventListener('mousemove', eventToLocationHandler);
this.annotatedElement.removeEventListener('mouseup', eventToLocationHandler);

this.annotatedElement.removeEventListener('touchmove', eventToLocationHandler);
this.annotatedElement.removeEventListener('touchcancel', eventToLocationHandler);
this.annotatedElement.removeEventListener('touchend', eventToLocationHandler);
this.annotatedElement.removeEventListener('mousemove', this.userMoveHandler);
this.annotatedElement.removeEventListener('mouseup', this.userStopHandler);
this.annotatedElement.removeEventListener('touchmove', this.userMoveHandler);
this.annotatedElement.removeEventListener('touchcancel', this.userStopHandler);
this.annotatedElement.removeEventListener('touchend', this.userStopHandler);
}

/**
Expand Down
12 changes: 7 additions & 5 deletions src/drawing/__tests__/DrawingThread-test.js
Expand Up @@ -119,15 +119,17 @@ describe('drawing/DrawingThread', () => {
thread.annotatedElement = {
removeEventListener: jest.fn()
};
thread.userMoveHandler = jest.fn();
thread.userStopHandler = jest.fn();
});

it('should add only mouse listeners for desktop devices', () => {
thread.unbindDrawingListeners();
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('mousemove', expect.any(Function));
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('mouseup', expect.any(Function));
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('touchmove', expect.any(Function));
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('touchcancel', expect.any(Function));
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('touchend', expect.any(Function));
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('mousemove', thread.userMoveHandler);
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('mouseup', thread.userStopHandler);
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('touchmove', thread.userMoveHandler);
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('touchcancel', thread.userStopHandler);
expect(thread.annotatedElement.removeEventListener).toBeCalledWith('touchend', thread.userStopHandler);
});
});

Expand Down