Skip to content

Commit

Permalink
fix: allow Component to handle all event listeners without binding ex…
Browse files Browse the repository at this point in the history
…ternal (#60)

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 authored Feb 17, 2020
1 parent 5ccf95e commit 73a1c73
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 targetListener = targetElementOrCornerstone[addOrRemoveEventListener];
const boundMethod = this._handleExternalEventListeners.bind(this);
for (let i = 0; i < events.length; i++) {
targetListener(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 73a1c73

Please sign in to comment.