From 298457610b957199088468ac0a58572e967bb7b4 Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Tue, 15 Dec 2015 17:47:15 -0800 Subject: [PATCH 1/3] DOM API implementation of `activeElement`. --- bower.json | 2 +- src/lib/dom-api-shadow.html | 7 + src/lib/dom-api-shady.html | 43 ++++- test/unit/polymer-dom-elements.html | 242 +++++++++++++++++++++++ test/unit/polymer-dom-shadow.html | 4 + test/unit/polymer-dom.html | 4 + test/unit/polymer-dom.js | 288 ++++++++++++++++++++++++++++ 7 files changed, 588 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index b6655cda..a13c6ad7 100644 --- a/bower.json +++ b/bower.json @@ -20,7 +20,7 @@ "url": "https://github.com/Polymer/polymer.git" }, "dependencies": { - "webcomponentsjs": "^0.7.18" + "webcomponentsjs": "^0.7.20" }, "devDependencies": { "web-component-tester": "*" diff --git a/src/lib/dom-api-shadow.html b/src/lib/dom-api-shadow.html index cc73842b..3cdb7ea8 100644 --- a/src/lib/dom-api-shadow.html +++ b/src/lib/dom-api-shadow.html @@ -58,6 +58,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Object.defineProperties(DomApi.prototype, { + activeElement: { + get: function() { + return Polymer.DomApi.wrap(this.node).activeElement; + }, + configurable: true + }, + childNodes: { get: function() { return TreeApi.arrayCopyChildNodes(this.node); diff --git a/src/lib/dom-api-shady.html b/src/lib/dom-api-shady.html index 64e41c1c..9d00661e 100644 --- a/src/lib/dom-api-shady.html +++ b/src/lib/dom-api-shady.html @@ -422,6 +422,47 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN Object.defineProperties(DomApi.prototype, { + activeElement: { + get: function() { + var active = document.activeElement; + if (!active) { + return null; + } + var isShadyRoot = !!this.node._isShadyRoot; + if (this.node !== document) { + // If this node isn't a document or shady root, then it doesn't + // have an active element. + if (!isShadyRoot) { + return null; + } + // If this shady root's host is the active element or the active + // element is not a descendant of the host, then it doesn't have + // an active element. + if (this.node.host === active || + !this.node.host.contains(active)) { + return null; + } + // If the active element is a light descendant of the shady root's + // host, return the active element. + if (this.node.host !== active && + this._contains(this.node.host, active)) { + return active; + } + } + // This node is either the document or a shady root of which the + // active element is a descendant of its host; iterate upwards to + // find the active element's most shallow host. + var activeRoot = Polymer.dom(active).getOwnerRoot(); + while (activeRoot && activeRoot !== this.node && + !(isShadyRoot && this._contains(this.node.host, active))) { + active = activeRoot.host; + activeRoot = Polymer.dom(active).getOwnerRoot(); + } + return active; + }, + configurable: true + }, + childNodes: { get: function() { var c$ = TreeApi.Logical.getChildNodes(this.node); @@ -569,4 +610,4 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN }; })(); - \ No newline at end of file + diff --git a/test/unit/polymer-dom-elements.html b/test/unit/polymer-dom-elements.html index c0b28546..a4c39fd7 100644 --- a/test/unit/polymer-dom-elements.html +++ b/test/unit/polymer-dom-elements.html @@ -357,3 +357,245 @@ }); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/unit/polymer-dom-shadow.html b/test/unit/polymer-dom-shadow.html index f1f52678..cc2a5c2c 100644 --- a/test/unit/polymer-dom-shadow.html +++ b/test/unit/polymer-dom-shadow.html @@ -57,6 +57,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN + + + + diff --git a/test/unit/polymer-dom.html b/test/unit/polymer-dom.html index 7899b1c2..7f0e15c5 100644 --- a/test/unit/polymer-dom.html +++ b/test/unit/polymer-dom.html @@ -57,6 +57,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN + + + + diff --git a/test/unit/polymer-dom.js b/test/unit/polymer-dom.js index c11a6e8d..f6e06747 100644 --- a/test/unit/polymer-dom.js +++ b/test/unit/polymer-dom.js @@ -802,6 +802,294 @@ suite('Polymer.dom accessors', function() { assert.equal(testElement.children.length, 3); }); + suite('Polymer.dom activeElement', function() { + var r; + // light + var r_l + // shadow + var r_0; + // light + var r_0_l; + // shadow + var r_0_0; + // light + var r_0_0_l; + // shadow + var r_0_0_l_0; + var r_0_1; + // light + var r_0_1_l; + var r_1; + // light + var r_1_l; + // shadow + var r_1_l_0; + // shadow + var r_1_0; + // light + var r_1_0_l; + var r_1_1; + // light + var r_1_1_l; + + suiteSetup(function() { + r = Polymer.dom(document).querySelector('x-shadow-host-root'); + r_l = Polymer.dom(r).querySelector('x-shadow-host-root-light'); + r_0 = Polymer.dom(r.root).querySelector('x-shadow-host-root-0'); + r_0_l = Polymer.dom(r_0).querySelector('x-shadow-host-root-0-light'); + r_0_0 = Polymer.dom(r_0.root).querySelector('x-shadow-host-root-0-0'); + r_0_0_l = Polymer.dom(r_0_0).querySelector('x-shadow-host-root-0-0-light'); + r_0_0_l_0 = Polymer.dom(r_0_0_l.root).querySelector('x-shadow-host-root-0-0-light-0'); + r_0_1 = Polymer.dom(r_0.root).querySelector('x-shadow-host-root-0-1'); + r_0_1_l = Polymer.dom(r_0_1).querySelector('x-shadow-host-root-0-1-light'); + r_1 = Polymer.dom(r.root).querySelector('x-shadow-host-root-1'); + r_1_l = Polymer.dom(r_1).querySelector('x-shadow-host-root-1-light'); + r_1_l_0 = Polymer.dom(r_1_l.root).querySelector('x-shadow-host-root-1-light-0'); + r_1_0 = Polymer.dom(r_1.root).querySelector('x-shadow-host-root-1-0'); + r_1_0_l = Polymer.dom(r_1_0).querySelector('x-shadow-host-root-1-0-light'); + r_1_1 = Polymer.dom(r_1.root).querySelector('x-shadow-host-root-1-1'); + r_1_1_l = Polymer.dom(r_1_1).querySelector('x-shadow-host-root-1-1-light'); + }); + + test('r.focus()', function() { + r.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, null, 'r.root.activeElement === null'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_l.focus()', function() { + r_l.focus(); + + assert.equal(Polymer.dom(document).activeElement, r_l, 'document.activeElement === r_l'); + assert.equal(Polymer.dom(r.root).activeElement, r_l, 'r.root.activeElement === r_l'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_0.focus()', function() { + r_0.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_0, 'r.root.activeElement === r_0'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_0_l.focus()', function() { + r_0_l.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_0_l, 'r.root.activeElement === r_0_l'); + assert.equal(Polymer.dom(r_0.root).activeElement, r_0_l, 'r_0.root.activeElement === r_0_l'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_0_0.focus()', function() { + r_0_0.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_0, 'r.root.activeElement === r_0'); + assert.equal(Polymer.dom(r_0.root).activeElement, r_0_0, 'r_0.root.activeElement === r_0_0'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_0_0_l.focus()', function() { + r_0_0_l.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_0, 'r.root.activeElement === r_0'); + assert.equal(Polymer.dom(r_0.root).activeElement, r_0_0_l, 'r_0.root.activeElement === r_0_0_l'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, r_0_0_l, 'r_0_0.root.activeElement === r_0_0_l'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_0_0_l_0.focus()', function() { + r_0_0_l_0.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_0, 'r.root.activeElement === r_0'); + assert.equal(Polymer.dom(r_0.root).activeElement, r_0_0_l, 'r_0.root.activeElement === r_0_0_l'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, r_0_0_l, 'r_0_0.root.activeElement === r_0_0_l'); + assert.equal(Polymer.dom(r_0_0_l.root).activeElement, r_0_0_l_0, 'r_0_0_l.root.activeElement === r_0_0_l_0'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_0_1.focus()', function() { + r_0_1.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_0, 'r.root.activeElement === r_0'); + assert.equal(Polymer.dom(r_0.root).activeElement, r_0_1, 'r_0.root.activeElement === r_0_1'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_0_1_l.focus()', function() { + r_0_1_l.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_0, 'r.root.activeElement === r_0'); + assert.equal(Polymer.dom(r_0.root).activeElement, r_0_1_l, 'r_0.root.activeElement === r_0_1_l'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, r_0_1_l, 'r_0_1.root.activeElement === r_0_1_l'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_1.focus()', function() { + r_1.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_1, 'r.root.activeElement === r_1'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_1_l.focus()', function() { + r_1_l.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_1_l, 'r.root.activeElement === r_1_l'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, r_1_l, 'r_1.root.activeElement === r_1_l'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_1_l_0.focus()', function() { + r_1_l_0.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_1_l, 'r.root.activeElement === r_1_l'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, r_1_l, 'r_1.root.activeElement === r_1_l'); + assert.equal(Polymer.dom(r_1_l.root).activeElement, r_1_l_0, 'r_1.root.activeElement === r_1_l_0'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_1_0.focus()', function() { + r_1_0.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_1, 'r.root.activeElement === r_1'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, r_1_0, 'r_1.root.activeElement === r_1_0'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_1_0_l.focus()', function() { + r_1_0_l.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_1, 'r.root.activeElement === r_1'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, r_1_0_l, 'r_1.root.activeElement === r_1_0_l'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, r_1_0_l, 'r_1_0.root.activeElement === r_1_0_l'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_1_1.focus()', function() { + r_1_1.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_1, 'r.root.activeElement === r_1'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, r_1_1, 'r_1.root.activeElement === r_1_1'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('r_1_1_l.focus()', function() { + r_1_1_l.focus(); + + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_1, 'r.root.activeElement === r_1'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, r_1_1_l, 'r_1.root.activeElement === r_1_1_l'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, r_1_1_l, 'r_1_1.root.activeElement === r_1_1_l'); + }); + + test('setting activeElement on document has no effect', function() { + r_1_1.focus(); + + Polymer.dom(document).activeElement = "abc"; + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_1, 'r.root.activeElement === r_1'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, r_1_1, 'r_1.root.activeElement === r_1_1'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + + test('setting activeElement on a shadow root has no effect', function() { + r_1_1.focus(); + + Polymer.dom(r_1.root).activeElement = "abc"; + assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); + assert.equal(Polymer.dom(r.root).activeElement, r_1, 'r.root.activeElement === r_1'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); + assert.equal(Polymer.dom(r_1.root).activeElement, r_1_1, 'r_1.root.activeElement === r_1_1'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); + }); + }); }); suite('Polymer.dom non-distributed elements', function() { From e848af896463714a8f33e7131dc699f60d77d3be Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Wed, 6 Jan 2016 11:45:21 -0800 Subject: [PATCH 2/3] Removes the case where activeElement could be in the light DOM of a ShadowRoot. --- src/lib/dom-api-shadow.html | 6 ++++-- src/lib/dom-api-shady.html | 32 ++++++++++++++++---------------- test/unit/polymer-dom.js | 18 +++++++++--------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/lib/dom-api-shadow.html b/src/lib/dom-api-shadow.html index 3cdb7ea8..daf15df8 100644 --- a/src/lib/dom-api-shadow.html +++ b/src/lib/dom-api-shadow.html @@ -60,11 +60,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN activeElement: { get: function() { - return Polymer.DomApi.wrap(this.node).activeElement; + var node = Polymer.DomApi.wrap(this.node); + var activeElement = node.activeElement; + return node.contains(activeElement) ? activeElement : null; }, configurable: true }, - + childNodes: { get: function() { return TreeApi.arrayCopyChildNodes(this.node); diff --git a/src/lib/dom-api-shady.html b/src/lib/dom-api-shady.html index 9d00661e..ccb93354 100644 --- a/src/lib/dom-api-shady.html +++ b/src/lib/dom-api-shady.html @@ -430,35 +430,35 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN } var isShadyRoot = !!this.node._isShadyRoot; if (this.node !== document) { - // If this node isn't a document or shady root, then it doesn't - // have an active element. + // If this node isn't a document or shady root, then it doesn't have + // an active element. if (!isShadyRoot) { return null; } // If this shady root's host is the active element or the active - // element is not a descendant of the host, then it doesn't have - // an active element. + // element is not a descendant of the host (in the composed tree), + // then it doesn't have an active element. if (this.node.host === active || !this.node.host.contains(active)) { return null; } - // If the active element is a light descendant of the shady root's - // host, return the active element. - if (this.node.host !== active && - this._contains(this.node.host, active)) { - return active; - } } - // This node is either the document or a shady root of which the - // active element is a descendant of its host; iterate upwards to - // find the active element's most shallow host. + // This node is either the document or a shady root of which the active + // element is a (composed) descendant of its host; iterate upwards to + // find the active element's most shallow host within it. var activeRoot = Polymer.dom(active).getOwnerRoot(); - while (activeRoot && activeRoot !== this.node && - !(isShadyRoot && this._contains(this.node.host, active))) { + while (activeRoot && activeRoot !== this.node) { active = activeRoot.host; activeRoot = Polymer.dom(active).getOwnerRoot(); } - return active; + if (this.node === document) { + // This node is the document, so activeRoot should be null. + return activeRoot ? null : active; + } else { + // This node is a non-document shady root, and it should be + // activeRoot. + return activeRoot === this.node ? active : null; + } }, configurable: true }, diff --git a/test/unit/polymer-dom.js b/test/unit/polymer-dom.js index f6e06747..ab9f735d 100644 --- a/test/unit/polymer-dom.js +++ b/test/unit/polymer-dom.js @@ -868,7 +868,7 @@ suite('Polymer.dom accessors', function() { r_l.focus(); assert.equal(Polymer.dom(document).activeElement, r_l, 'document.activeElement === r_l'); - assert.equal(Polymer.dom(r.root).activeElement, r_l, 'r.root.activeElement === r_l'); + assert.equal(Polymer.dom(r.root).activeElement, null, 'r.root.activeElement === null'); assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); @@ -895,7 +895,7 @@ suite('Polymer.dom accessors', function() { assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); assert.equal(Polymer.dom(r.root).activeElement, r_0_l, 'r.root.activeElement === r_0_l'); - assert.equal(Polymer.dom(r_0.root).activeElement, r_0_l, 'r_0.root.activeElement === r_0_l'); + assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); @@ -923,7 +923,7 @@ suite('Polymer.dom accessors', function() { assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); assert.equal(Polymer.dom(r.root).activeElement, r_0, 'r.root.activeElement === r_0'); assert.equal(Polymer.dom(r_0.root).activeElement, r_0_0_l, 'r_0.root.activeElement === r_0_0_l'); - assert.equal(Polymer.dom(r_0_0.root).activeElement, r_0_0_l, 'r_0_0.root.activeElement === r_0_0_l'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); @@ -936,7 +936,7 @@ suite('Polymer.dom accessors', function() { assert.equal(Polymer.dom(document).activeElement, r, 'document.activeElement === r'); assert.equal(Polymer.dom(r.root).activeElement, r_0, 'r.root.activeElement === r_0'); assert.equal(Polymer.dom(r_0.root).activeElement, r_0_0_l, 'r_0.root.activeElement === r_0_0_l'); - assert.equal(Polymer.dom(r_0_0.root).activeElement, r_0_0_l, 'r_0_0.root.activeElement === r_0_0_l'); + assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); assert.equal(Polymer.dom(r_0_0_l.root).activeElement, r_0_0_l_0, 'r_0_0_l.root.activeElement === r_0_0_l_0'); assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); @@ -964,7 +964,7 @@ suite('Polymer.dom accessors', function() { assert.equal(Polymer.dom(r.root).activeElement, r_0, 'r.root.activeElement === r_0'); assert.equal(Polymer.dom(r_0.root).activeElement, r_0_1_l, 'r_0.root.activeElement === r_0_1_l'); assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); - assert.equal(Polymer.dom(r_0_1.root).activeElement, r_0_1_l, 'r_0_1.root.activeElement === r_0_1_l'); + assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); @@ -991,7 +991,7 @@ suite('Polymer.dom accessors', function() { assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); - assert.equal(Polymer.dom(r_1.root).activeElement, r_1_l, 'r_1.root.activeElement === r_1_l'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); }); @@ -1004,7 +1004,7 @@ suite('Polymer.dom accessors', function() { assert.equal(Polymer.dom(r_0.root).activeElement, null, 'r_0.root.activeElement === null'); assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); - assert.equal(Polymer.dom(r_1.root).activeElement, r_1_l, 'r_1.root.activeElement === r_1_l'); + assert.equal(Polymer.dom(r_1.root).activeElement, null, 'r_1.root.activeElement === null'); assert.equal(Polymer.dom(r_1_l.root).activeElement, r_1_l_0, 'r_1.root.activeElement === r_1_l_0'); assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); @@ -1032,7 +1032,7 @@ suite('Polymer.dom accessors', function() { assert.equal(Polymer.dom(r_0_0.root).activeElement, null, 'r_0_0.root.activeElement === null'); assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); assert.equal(Polymer.dom(r_1.root).activeElement, r_1_0_l, 'r_1.root.activeElement === r_1_0_l'); - assert.equal(Polymer.dom(r_1_0.root).activeElement, r_1_0_l, 'r_1_0.root.activeElement === r_1_0_l'); + assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); }); @@ -1059,7 +1059,7 @@ suite('Polymer.dom accessors', function() { assert.equal(Polymer.dom(r_0_1.root).activeElement, null, 'r_0_1.root.activeElement === null'); assert.equal(Polymer.dom(r_1.root).activeElement, r_1_1_l, 'r_1.root.activeElement === r_1_1_l'); assert.equal(Polymer.dom(r_1_0.root).activeElement, null, 'r_1_0.root.activeElement === null'); - assert.equal(Polymer.dom(r_1_1.root).activeElement, r_1_1_l, 'r_1_1.root.activeElement === r_1_1_l'); + assert.equal(Polymer.dom(r_1_1.root).activeElement, null, 'r_1_1.root.activeElement === null'); }); test('setting activeElement on document has no effect', function() { From 47ee2ca912ae3799e28774f2c833f6c35b29f3f8 Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Fri, 8 Jan 2016 14:11:25 -0800 Subject: [PATCH 3/3] Use local references to wrapper functions; add test element tree to native shadow tests; reorder test elements. --- src/lib/dom-api-shadow.html | 5 +- src/lib/dom-api-shady.html | 4 +- test/unit/polymer-dom-elements.html | 274 +++++++++++------------ test/unit/polymer-dom-native-shadow.html | 4 + 4 files changed, 147 insertions(+), 140 deletions(-) diff --git a/src/lib/dom-api-shadow.html b/src/lib/dom-api-shadow.html index daf15df8..e442b761 100644 --- a/src/lib/dom-api-shadow.html +++ b/src/lib/dom-api-shadow.html @@ -60,8 +60,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN activeElement: { get: function() { - var node = Polymer.DomApi.wrap(this.node); + var node = DomApi.wrap(this.node); var activeElement = node.activeElement; + // Prevents `activeElement` from returning elements outside of the + // ShadowRoot, even if they would become descendants of the ShadowRoot + // in the composed tree. See w3c/webcomponents#358. return node.contains(activeElement) ? activeElement : null; }, configurable: true diff --git a/src/lib/dom-api-shady.html b/src/lib/dom-api-shady.html index ccb93354..e1f62ffe 100644 --- a/src/lib/dom-api-shady.html +++ b/src/lib/dom-api-shady.html @@ -446,10 +446,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN // This node is either the document or a shady root of which the active // element is a (composed) descendant of its host; iterate upwards to // find the active element's most shallow host within it. - var activeRoot = Polymer.dom(active).getOwnerRoot(); + var activeRoot = dom(active).getOwnerRoot(); while (activeRoot && activeRoot !== this.node) { active = activeRoot.host; - activeRoot = Polymer.dom(active).getOwnerRoot(); + activeRoot = dom(active).getOwnerRoot(); } if (this.node === document) { // This node is the document, so activeRoot should be null. diff --git a/test/unit/polymer-dom-elements.html b/test/unit/polymer-dom-elements.html index a4c39fd7..64ac6b59 100644 --- a/test/unit/polymer-dom-elements.html +++ b/test/unit/polymer-dom-elements.html @@ -359,25 +359,13 @@ - + - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -