From 9c89b27c7c3d102feec14112312d13be999e1fce Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Tue, 1 Dec 2015 13:03:07 -0800 Subject: [PATCH 1/5] Adds support for Document/ShadowRoot activeElement. --- src/ShadowDOM/wrappers/Document.js | 26 ++ src/ShadowDOM/wrappers/ShadowRoot.js | 25 ++ tests/ShadowDOM/html/activeElement.html | 344 ++++++++++++++++++++++++ tests/ShadowDOM/runner.html | 1 + 4 files changed, 396 insertions(+) create mode 100644 tests/ShadowDOM/html/activeElement.html diff --git a/src/ShadowDOM/wrappers/Document.js b/src/ShadowDOM/wrappers/Document.js index 561d9a1cb..fd9eb9c28 100644 --- a/src/ShadowDOM/wrappers/Document.js +++ b/src/ShadowDOM/wrappers/Document.js @@ -20,6 +20,7 @@ var ShadowRoot = scope.wrappers.ShadowRoot; var TreeScope = scope.TreeScope; var cloneNode = scope.cloneNode; + var defineGetter = scope.defineGetter; var defineWrapGetter = scope.defineWrapGetter; var elementFromPoint = scope.elementFromPoint; var forwardMethodsToWrapper = scope.forwardMethodsToWrapper; @@ -50,6 +51,31 @@ defineWrapGetter(Document, 'body'); defineWrapGetter(Document, 'head'); + defineGetter(Document, 'activeElement', function() { + var activeElement = wrap(unwrap(this).activeElement); + + // Loop while activeElement is not a shallow child of this document. + while (!this.contains(activeElement)) { + var lastHost = activeElement; + // Iterate until we hit activeElement's containing ShadowRoot (which + // isn't this one) or document. + while (activeElement.parentNode) { + activeElement = activeElement.parentNode; + } + + // If we've reached a ShadowRoot, move to its host. + if (activeElement.host) { + activeElement = activeElement.host; + // Otherwise, we've reached a different document - this document is + // not an ancestor of the active element. + } else { + return null; + } + } + + return activeElement; + }); + // document cannot be overridden so we override a bunch of its methods // directly on the instance. diff --git a/src/ShadowDOM/wrappers/ShadowRoot.js b/src/ShadowDOM/wrappers/ShadowRoot.js index dad9dcb40..3a5f36c04 100644 --- a/src/ShadowDOM/wrappers/ShadowRoot.js +++ b/src/ShadowDOM/wrappers/ShadowRoot.js @@ -21,6 +21,7 @@ var setInnerHTML = scope.setInnerHTML; var unsafeUnwrap = scope.unsafeUnwrap; var unwrap = scope.unwrap; + var wrap = scope.wrap; var shadowHostTable = new WeakMap(); var nextOlderShadowTreeTable = new WeakMap(); @@ -71,6 +72,30 @@ getSelection: function() { return document.getSelection(); + }, + + get activeElement() { + var activeElement = wrap(unwrap(this).ownerDocument.activeElement); + + // Loop while activeElement is not a shallow child of this ShadowRoot. + while (!this.contains(activeElement)) { + // Iterate until we hit activeElement's containing ShadowRoot (which + // isn't this one) or document. + while (activeElement.parentNode) { + activeElement = activeElement.parentNode; + } + + // If we've reached a ShadowRoot, move to its host. + if (activeElement.host) { + activeElement = activeElement.host; + // Otherwise, we've reached a document - this ShadowRoot is not an + // ancestor of the active element. + } else { + return null; + } + } + + return activeElement; } }); diff --git a/tests/ShadowDOM/html/activeElement.html b/tests/ShadowDOM/html/activeElement.html new file mode 100644 index 000000000..3254dd1d9 --- /dev/null +++ b/tests/ShadowDOM/html/activeElement.html @@ -0,0 +1,344 @@ + + +document.activeElement + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/ShadowDOM/runner.html b/tests/ShadowDOM/runner.html index 843b3f333..b9401fbfb 100644 --- a/tests/ShadowDOM/runner.html +++ b/tests/ShadowDOM/runner.html @@ -21,6 +21,7 @@ 'html/full-suite.html', 'html/document-body-inner-html.html', 'html/document-body-shadow-root.html', + 'html/activeElement.html', //'html/on-load-test.html', //'html/on-unload-test.html', ]); From a67cf373900ecd735382b2a916e65bdcf9fca664 Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Wed, 2 Dec 2015 15:29:22 -0800 Subject: [PATCH 2/5] Removes an irrelevant test; moves test tree removal behind post-test hook assertions. --- tests/ShadowDOM/html/activeElement.html | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/tests/ShadowDOM/html/activeElement.html b/tests/ShadowDOM/html/activeElement.html index 3254dd1d9..f8139a146 100644 --- a/tests/ShadowDOM/html/activeElement.html +++ b/tests/ShadowDOM/html/activeElement.html @@ -97,12 +97,12 @@ }); teardown(function() { - document.body.removeChild(r); - assert.equal(r_0_0.shadowRoot.activeElement, null); assert.equal(r_0_1.shadowRoot.activeElement, null); assert.equal(r_1_0.shadowRoot.activeElement, null); assert.equal(r_1_1.shadowRoot.activeElement, null); + + document.body.removeChild(r); }); @@ -242,26 +242,6 @@ assert.equal(r_0.shadowRoot.activeElement, null); assert.equal(r_1.shadowRoot.activeElement, r_1_1_l); }); - - test('focused element in different document', function() { - var docType = doc.implementation.createDocumentType( - 'html', '-//W3C//DTD XHTML 1.0 Transitional//EN', - 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'); - var otherDocument = doc.implementation.createDocument( - 'http://www.w3.org/1999/xhtml', 'html', docType); - otherDocument.documentElement.appendChild( - otherDocument.createElement('body')); - - var elt = otherDocument.createElement('div'); - otherDocument.body.appendChild(elt); - - ShadowDOMPolyfill.renderAllPending(); - - elt.focus(); - - var activeElement = doc.activeElement; - assert.isTrue(activeElement === null || activeElement === doc.body); - }); }); From 484f2dd6fc21fe05589de7f04edc51eae03e98b2 Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Wed, 2 Dec 2015 18:29:00 -0800 Subject: [PATCH 3/5] Fix for IE11 bug where document.activeElement sometimes returns a null-prototyped object. --- src/ShadowDOM/wrappers/Document.js | 5 ++++- src/ShadowDOM/wrappers/ShadowRoot.js | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/ShadowDOM/wrappers/Document.js b/src/ShadowDOM/wrappers/Document.js index fd9eb9c28..5ebe24537 100644 --- a/src/ShadowDOM/wrappers/Document.js +++ b/src/ShadowDOM/wrappers/Document.js @@ -52,7 +52,10 @@ defineWrapGetter(Document, 'head'); defineGetter(Document, 'activeElement', function() { - var activeElement = wrap(unwrap(this).activeElement); + var unwrappedActiveElement = unwrap(this).activeElement; + if (!unwrappedActiveElement || !unwrappedActiveElement.nodeType) return null; + + var activeElement = wrap(unwrappedActiveElement); // Loop while activeElement is not a shallow child of this document. while (!this.contains(activeElement)) { diff --git a/src/ShadowDOM/wrappers/ShadowRoot.js b/src/ShadowDOM/wrappers/ShadowRoot.js index 3a5f36c04..915462ef4 100644 --- a/src/ShadowDOM/wrappers/ShadowRoot.js +++ b/src/ShadowDOM/wrappers/ShadowRoot.js @@ -75,7 +75,10 @@ }, get activeElement() { - var activeElement = wrap(unwrap(this).ownerDocument.activeElement); + var unwrappedActiveElement = unwrap(this).ownerDocument.activeElement; + if (!unwrappedActiveElement || !unwrappedActiveElement.nodeType) return null; + + var activeElement = wrap(unwrappedActiveElement); // Loop while activeElement is not a shallow child of this ShadowRoot. while (!this.contains(activeElement)) { From 4d3dd37cfcd080395f356da0a54c43180b442065 Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Fri, 4 Dec 2015 11:54:05 -0800 Subject: [PATCH 4/5] Force render before focus. --- src/ShadowDOM/wrappers/HTMLElement.js | 1 + tests/ShadowDOM/html/activeElement.html | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ShadowDOM/wrappers/HTMLElement.js b/src/ShadowDOM/wrappers/HTMLElement.js index fbc2c40a7..8c3a64d36 100644 --- a/src/ShadowDOM/wrappers/HTMLElement.js +++ b/src/ShadowDOM/wrappers/HTMLElement.js @@ -333,6 +333,7 @@ } [ + 'focus', 'getBoundingClientRect', 'getClientRects', 'scrollIntoView' diff --git a/tests/ShadowDOM/html/activeElement.html b/tests/ShadowDOM/html/activeElement.html index f8139a146..6ec9aa0d1 100644 --- a/tests/ShadowDOM/html/activeElement.html +++ b/tests/ShadowDOM/html/activeElement.html @@ -91,9 +91,6 @@ r_1_1_l = r_1_1.querySelector('[shadow-template-id=x-shadow-host-root-1-1-light]'); document.body.appendChild(r); - - // Nodes need to be in the document to be focusable. - ShadowDOMPolyfill.renderAllPending(); }); teardown(function() { From 396430f7a0b6c6576fd89c0cb4d452e5de751acc Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Fri, 4 Dec 2015 16:21:52 -0800 Subject: [PATCH 5/5] prepare for release v0.7.19 --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index d2543c291..bdef97a57 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "webcomponentsjs", "main": "webcomponents.js", - "version": "0.7.18", + "version": "0.7.19", "homepage": "http://webcomponents.org", "authors": [ "The Polymer Authors" diff --git a/package.json b/package.json index c97981e2c..e62ee5af9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "webcomponents.js", - "version": "0.7.18", + "version": "0.7.19", "description": "webcomponents.js", "main": "webcomponents.js", "directories": {