Skip to content

Commit

Permalink
patch/unpatch methods
Browse files Browse the repository at this point in the history
  • Loading branch information
valdrinkoshi committed Nov 23, 2016
1 parent a7b3159 commit 1c53778
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 38 deletions.
75 changes: 71 additions & 4 deletions dist/inert.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons

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

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

// Watch for:
// - any additions in the shadowRoot subtree: make them unfocusable too
// - any removals from the shadowRoot subtree: remove them from this inert root's managed nodes
var rootObserver = new MutationObserver(this._onMutation);
this._rootObserver = rootObserver;
patchShadowRootCreation(this._rootElement, function (shadowRoot) {
rootObserver.observe(shadowRoot, { childList: true, subtree: true });
});
}

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

if (this._rootElement) this._rootElement.removeAttribute('aria-hidden');
this._rootObserver.disconnect();
this._rootObserver = null;

this._rootElement.removeAttribute('aria-hidden');
unpatchShadowRootCreation(this._rootElement);
this._rootElement = null;

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

/**
* Invokes the callback after the element attaches the shadow root. If `element`
* has already a shadowRoot, the `callback` is invoked immediately.
* Need to patch `attachShadow` and `createShadowRoot` methods as there is
* no way to observe shadow root attachment (yet), see w3c/webcomponents#204
* @param {!Element} element
* @param {!Function(DocumentFragment)} callback
*/
function patchShadowRootCreation(element, callback) {
var shadowRoot = element.shadowRoot || element.webkitShadowRoot;
if (shadowRoot) {
callback(shadowRoot);
} else {
(function () {
// ShadowDOM v1 support.
var attachShadowFn = element.attachShadow;
if (attachShadowFn) {
element.attachShadow = function patchedAttachShadow() {
var shadowRoot = attachShadowFn.apply(this, arguments);
callback(shadowRoot);
return shadowRoot;
};
element.attachShadow._originalFn = attachShadowFn;
}
// ShadowDOM v0 support.
var createShadowRootFn = element.createShadowRoot;
if (createShadowRootFn) {
element.createShadowRoot = function patchedCreateShadowRoot() {
var shadowRoot = createShadowRootFn.apply(this, arguments);
callback(shadowRoot);
return shadowRoot;
};
element.createShadowRoot._originalFn = createShadowRootFn;
}
})();
}
}

/**
* Restores the original `attachShadow` and `createShadowRoot` methods of `element`.
* @param {!Element} element
*/
function unpatchShadowRootCreation(element) {
// ShadowDOM v1 support.
if (element.attachShadow && element.attachShadow._originalFn) {
element.attachShadow = element.attachShadow._originalFn;
}
// ShadowDOM v0 support.
if (element.createShadowRoot && element.createShadowRoot._originalFn) {
element.createShadowRoot = element.createShadowRoot._originalFn;
}
}

var inertManager = new InertManager(document);

Object.defineProperty(Element.prototype, 'inert', {
Expand Down
Loading

0 comments on commit 1c53778

Please sign in to comment.