Skip to content

Commit 568bbfe

Browse files
committed
patch/unpatch methods
1 parent a7b3159 commit 568bbfe

File tree

3 files changed

+130
-38
lines changed

3 files changed

+130
-38
lines changed

dist/inert.js

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
4545

4646
var InertRoot = function () {
4747
/**
48-
* @param {Element} rootElement The Element at the root of the inert subtree.
49-
* @param {InertManager} inertManager The global singleton InertManager object.
48+
* @param {!Element} rootElement The Element at the root of the inert subtree.
49+
* @param {!InertManager} inertManager The global singleton InertManager object.
5050
*/
5151
function InertRoot(rootElement, inertManager) {
5252
_classCallCheck(this, InertRoot);
@@ -69,13 +69,23 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
6969
// Make all focusable elements in the subtree unfocusable and add them to _managedNodes
7070
this._makeSubtreeUnfocusable(this._rootElement);
7171

72+
this._onMutation = this._onMutation.bind(this);
7273
// Watch for:
7374
// - any additions in the subtree: make them unfocusable too
7475
// - any removals from the subtree: remove them from this inert root's managed nodes
7576
// - attribute changes: if `tabindex` is added, or removed from an intrinsically focusable element,
7677
// make that node a managed node.
77-
this._observer = new MutationObserver(this._onMutation.bind(this));
78+
this._observer = new MutationObserver(this._onMutation);
7879
this._observer.observe(this._rootElement, { attributes: true, childList: true, subtree: true });
80+
81+
// Watch for:
82+
// - any additions in the shadowRoot subtree: make them unfocusable too
83+
// - any removals from the shadowRoot subtree: remove them from this inert root's managed nodes
84+
var rootObserver = new MutationObserver(this._onMutation);
85+
this._rootObserver = rootObserver;
86+
patchShadowRootCreation(this._rootElement, function (shadowRoot) {
87+
rootObserver.observe(shadowRoot, { childList: true, subtree: true });
88+
});
7989
}
8090

8191
/**
@@ -90,7 +100,11 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
90100
this._observer.disconnect();
91101
this._observer = null;
92102

93-
if (this._rootElement) this._rootElement.removeAttribute('aria-hidden');
103+
this._rootObserver.disconnect();
104+
this._rootObserver = null;
105+
106+
this._rootElement.removeAttribute('aria-hidden');
107+
unpatchShadowRootCreation(this._rootElement);
94108
this._rootElement = null;
95109

96110
var _iteratorNormalCompletion = true;
@@ -915,6 +929,59 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons
915929
node.appendChild(style);
916930
}
917931

932+
/**
933+
* Invokes the callback after the element attaches the shadow root. If `element`
934+
* has already a shadowRoot, the `callback` is invoked immediately.
935+
* Need to patch `attachShadow` and `createShadowRoot` methods as there is
936+
* no way to observe shadow root attachment (yet), see w3c/webcomponents#204
937+
* @param {!Element} element
938+
* @param {!Function(DocumentFragment)} callback
939+
*/
940+
function patchShadowRootCreation(element, callback) {
941+
var shadowRoot = element.shadowRoot || element.webkitShadowRoot;
942+
if (shadowRoot) {
943+
callback(shadowRoot);
944+
} else {
945+
(function () {
946+
// ShadowDOM v1 support.
947+
var attachShadowFn = element.attachShadow;
948+
if (attachShadowFn) {
949+
element.attachShadow = function patchedAttachShadow() {
950+
var shadowRoot = attachShadowFn.apply(this, arguments);
951+
callback(shadowRoot);
952+
return shadowRoot;
953+
};
954+
element.attachShadow._originalFn = attachShadowFn;
955+
}
956+
// ShadowDOM v0 support.
957+
var createShadowRootFn = element.createShadowRoot;
958+
if (createShadowRootFn) {
959+
element.createShadowRoot = function patchedCreateShadowRoot() {
960+
var shadowRoot = createShadowRootFn.apply(this, arguments);
961+
callback(shadowRoot);
962+
return shadowRoot;
963+
};
964+
element.createShadowRoot._originalFn = createShadowRootFn;
965+
}
966+
})();
967+
}
968+
}
969+
970+
/**
971+
* Restores the original `attachShadow` and `createShadowRoot` methods of `element`.
972+
* @param {!Element} element
973+
*/
974+
function unpatchShadowRootCreation(element) {
975+
// ShadowDOM v1 support.
976+
if (element.attachShadow && element.attachShadow._originalFn) {
977+
element.attachShadow = element.attachShadow._originalFn;
978+
}
979+
// ShadowDOM v0 support.
980+
if (element.createShadowRoot && element.createShadowRoot._originalFn) {
981+
element.createShadowRoot = element.createShadowRoot._originalFn;
982+
}
983+
}
984+
918985
var inertManager = new InertManager(document);
919986

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

0 commit comments

Comments
 (0)