Skip to content

Commit 23ac4f3

Browse files
committed
patch/unpatch methods
1 parent c600fc2 commit 23ac4f3

File tree

1 file changed

+58
-33
lines changed

1 file changed

+58
-33
lines changed

inert.js

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -69,47 +69,23 @@ class InertRoot {
6969
// Make all focusable elements in the subtree unfocusable and add them to _managedNodes
7070
this._makeSubtreeUnfocusable(this._rootElement);
7171

72-
const boundOnMutation = this._onMutation.bind(this);
72+
this._onMutation = this._onMutation.bind(this);
7373
// Watch for:
7474
// - any additions in the subtree: make them unfocusable too
7575
// - any removals from the subtree: remove them from this inert root's managed nodes
7676
// - attribute changes: if `tabindex` is added, or removed from an intrinsically focusable element,
7777
// make that node a managed node.
78-
this._observer = new MutationObserver(boundOnMutation);
78+
this._observer = new MutationObserver(this._onMutation);
7979
this._observer.observe(this._rootElement, { attributes: true, childList: true, subtree: true });
8080

8181
// Watch for:
8282
// - any additions in the shadowRoot subtree: make them unfocusable too
8383
// - any removals from the shadowRoot subtree: remove them from this inert root's managed nodes
84-
const rootObserver = new MutationObserver(boundOnMutation);
85-
const shadowRoot = this._rootElement.shadowRoot || this._rootElement.webkitShadowRoot;
86-
if (shadowRoot) {
87-
rootObserver.observe(shadowRoot, { childList: true, subtree: true });
88-
} else {
89-
// ShadowDOM v1 support.
90-
// NOTE(valdrin) There is no way to observe shadow root attachment (yet),
91-
// patching might be slow https://github.com/w3c/webcomponents/issues/204
92-
const attachShadowFn = this._rootElement.attachShadow;
93-
if (attachShadowFn) {
94-
this._rootElement.attachShadow = function patchedAttachShadow() {
95-
const shadowRoot = attachShadowFn.apply(this, arguments);
96-
rootObserver.observe(shadowRoot, { childList: true, subtree: true });
97-
return shadowRoot;
98-
};
99-
}
100-
// ShadowDOM v0 support.
101-
// NOTE(valdrin) There is no way to observe shadow root attachment (yet),
102-
// patching might be slow https://github.com/w3c/webcomponents/issues/204
103-
const createShadowRootFn = this._rootElement.createShadowRoot;
104-
if (createShadowRootFn) {
105-
this._rootElement.createShadowRoot = function patchedCreateShadowRoot() {
106-
const shadowRoot = createShadowRootFn.apply(this, arguments);
107-
rootObserver.observe(shadowRoot, { childList: true, subtree: true });
108-
return shadowRoot;
109-
};
110-
}
111-
}
84+
const rootObserver = new MutationObserver(this._onMutation);
11285
this._rootObserver = rootObserver;
86+
patchShadowRootCreation(this._rootElement, function(shadowRoot) {
87+
rootObserver.observe(shadowRoot, { childList: true, subtree: true });
88+
});
11389
}
11490

11591
/**
@@ -124,9 +100,7 @@ class InertRoot {
124100
this._rootObserver = null;
125101

126102
this._rootElement.removeAttribute('aria-hidden');
127-
// Restore original attachShadow and createShadowRoot.
128-
delete this._rootElement.attachShadow;
129-
delete this._rootElement.createShadowRoot;
103+
unpatchShadowRootCreation(this._rootElement);
130104
this._rootElement = null;
131105

132106
for (let inertNode of this._managedNodes)
@@ -676,6 +650,57 @@ function addInertStyle(node) {
676650
node.appendChild(style);
677651
}
678652

653+
/**
654+
* Invokes the callback after the element attaches the shadow root. If `element`
655+
* has already a shadowRoot, the `callback` is invoked immediately.
656+
* Need to patch `attachShadow` and `createShadowRoot` methods as there is
657+
* no way to observe shadow root attachment (yet), see w3c/webcomponents#204
658+
* @param {!Element} element
659+
* @param {!Function(DocumentFragment)} callback
660+
*/
661+
function patchShadowRootCreation(element, callback) {
662+
const shadowRoot = element.shadowRoot || element.webkitShadowRoot;
663+
if (shadowRoot) {
664+
callback(shadowRoot);
665+
} else {
666+
// ShadowDOM v1 support.
667+
const attachShadowFn = element.attachShadow;
668+
if (attachShadowFn) {
669+
element.attachShadow = function patchedAttachShadow() {
670+
const shadowRoot = attachShadowFn.apply(this, arguments);
671+
callback(shadowRoot);
672+
return shadowRoot;
673+
};
674+
element.attachShadow._originalFn = attachShadowFn;
675+
}
676+
// ShadowDOM v0 support.
677+
const createShadowRootFn = this._rootElement.createShadowRoot;
678+
if (createShadowRootFn) {
679+
element.createShadowRoot = function patchedCreateShadowRoot() {
680+
const shadowRoot = createShadowRootFn.apply(this, arguments);
681+
callback(shadowRoot);
682+
return shadowRoot;
683+
};
684+
element.createShadowRoot._originalFn = createShadowRootFn;
685+
}
686+
}
687+
}
688+
689+
/**
690+
* Restores the original `attachShadow` and `createShadowRoot` methods of `element`.
691+
* @param {!Element} element
692+
*/
693+
function unpatchShadowRootCreation(element) {
694+
// ShadowDOM v1 support.
695+
if (element.attachShadow && element.attachShadow._originalFn) {
696+
element.attachShadow = element.attachShadow._originalFn;
697+
}
698+
// ShadowDOM v0 support.
699+
if (element.createShadowRoot && element.createShadowRoot._originalFn) {
700+
element.createShadowRoot = element.createShadowRoot._originalFn;
701+
}
702+
}
703+
679704
const inertManager = new InertManager(document);
680705

681706
Object.defineProperty(Element.prototype, 'inert', {

0 commit comments

Comments
 (0)