Skip to content

Commit

Permalink
Allow Component to handle all event listeners without binding external
Browse files Browse the repository at this point in the history
Wrap all events in a single handler which will delegate out the events to the
provided functions. This means that if the external function changes we do not
need to rebind the function, fixing issues with functional react components.
  • Loading branch information
Todd Dembrey committed Feb 17, 2020
1 parent 5ccf95e commit 8e4f71b
Showing 1 changed file with 46 additions and 15 deletions.
61 changes: 46 additions & 15 deletions src/CornerstoneViewport/CornerstoneViewport.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,10 @@ class CornerstoneViewport extends Component {
isFlippedHorizontally: undefined,
};

this._validateExternalEventsListeners();

// TODO: Deep Copy? How does that work w/ handlers?
// Save a copy. Props could change before `willUnmount`
this.eventListeners = this.props.eventListeners;
this.startLoadHandler = this.props.startLoadHandler;
this.endLoadHandler = this.props.endLoadHandler;
this.loadHandlerTimeout = undefined; // "Loading..." timer
Expand Down Expand Up @@ -286,6 +287,8 @@ class CornerstoneViewport extends Component {
if (Object.keys(updatedState).length > 0) {
this.setState(updatedState);
}

this._validateExternalEventsListeners();
}

/**
Expand Down Expand Up @@ -470,29 +473,40 @@ class CornerstoneViewport extends Component {
}

/**
* Listens out for all events and then defers handling to a single listener to act on them
*
* @param {string} target - "cornerstone" || "element"
* @param {boolean} [clear=false] - True to clear event listeners
* @returns {undefined}
*/
_bindExternalEventListeners(target, clear = false) {
if (!this.eventListeners) {
return;
}
_bindExternalEventListeners(targetType, clear=false) {
const addOrRemoveEventListener = clear
? 'removeEventListener'
: 'addEventListener';

const cornerstoneEvents = Object.values(cornerstone.EVENTS);
const cornerstoneToolsEvents = Object.values(cornerstoneTools.EVENTS);
const addOrRemoveEventListener = clear
? 'removeEventListener'
: 'addEventListener';

for (let i = 0; i < this.eventListeners.length; i++) {
const { target: targetType, eventName, handler } = this.eventListeners[i];
if (targetType !== target) { continue; }
const events = cornerstoneEvents.concat(cornerstoneToolsEvents);
const targetElementOrCornerstone =
targetType === 'element' ? this.element : cornerstone.events;
const boundMethod = this._handleExternalEventListeners.bind(this);
for (let i = 0; i < events.length; i++) {
const targetHandler = targetElementOrCornerstone[addOrRemoveEventListener];
targetHandler(events[i], boundMethod);
}
}

const targetElementOrCornerstone =
targetType === 'element' ? this.element : cornerstone.events;
/**
* Called to validate that events passed into the event listeners prop are valid
*
* @returns {undefined}
*/
_validateExternalEventsListeners() {
const cornerstoneEvents = Object.values(cornerstone.EVENTS);
const cornerstoneToolsEvents = Object.values(cornerstoneTools.EVENTS);

for (let i = 0; i < this.props.eventListeners.length; i++) {
const { target: targetType, eventName, handler } = this.props.eventListeners[i];
if (
!cornerstoneEvents.includes(eventName) &&
!cornerstoneToolsEvents.includes(eventName)
Expand All @@ -502,8 +516,25 @@ class CornerstoneViewport extends Component {
);
continue;
}
}
}
/**
* Handles delegating of events from cornerstone back to the defined
* external events handlers
*
* @param {event}
* @returns {undefined}
*/
_handleExternalEventListeners(event){
if (!this.props.eventListeners) {
return;
}
for (let i = 0; i < this.props.eventListeners.length; i++) {
const { eventName, handler } = this.props.eventListeners[i];

targetElementOrCornerstone[addOrRemoveEventListener](eventName, handler);
if (event.type === eventName) {
handler(event);
}
}
}

Expand Down

0 comments on commit 8e4f71b

Please sign in to comment.