diff --git a/src/core/ReactDOMComponent.js b/src/core/ReactDOMComponent.js index 08de4eb2d8d..a59b04c0226 100644 --- a/src/core/ReactDOMComponent.js +++ b/src/core/ReactDOMComponent.js @@ -22,6 +22,7 @@ var CSSPropertyOperations = require('CSSPropertyOperations'); var DOMProperty = require('DOMProperty'); var DOMPropertyOperations = require('DOMPropertyOperations'); +var ExecutionEnvironment = require('ExecutionEnvironment'); var ReactComponent = require('ReactComponent'); var ReactEventEmitter = require('ReactEventEmitter'); var ReactMount = require('ReactMount'); @@ -64,11 +65,43 @@ function assertValidProps(props) { ); } + +/* + * The owning document is the Node to which we should attach event handlers. + * Under normal circumstances, this would be the document contained + * in the window. + * + * However, when rendering into a shadow root, we need to bind the handlers + * to the shadow root. That is because events are stopped at shadow boundaries. + * + * This means we have to manually walk up the parents until we find a suitable + * node. + * + * Futher complicated by the fact that this module is tested to run in web + * workers, where 'window' is not defined. So the whole function is only + * defined if it can actually run. + */ +var owningDocument = (function() { + if (ExecutionEnvironment.canUseDOM) { + var ShadowRoot = window.ShadowRoot; + return function(node) { + if (node.parentNode == null) { + return node; + } else if (ShadowRoot && node instanceof ShadowRoot) { + return node; + } else { + return owningDocument(node.parentNode); + } + } + } +})(); + + function putListener(id, registrationName, listener) { var container = ReactMount.findReactContainerForID(id); if (container) { var doc = container.nodeType === ELEMENT_NODE_TYPE ? - container.ownerDocument : + owningDocument(container) : container; listenTo(registrationName, doc); }