From 298457610b957199088468ac0a58572e967bb7b4 Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Tue, 15 Dec 2015 17:47:15 -0800 Subject: [PATCH] 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 b6655cda87..a13c6ad749 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 cc73842b6f..3cdb7ea8fd 100644 --- a/src/lib/dom-api-shadow.html +++ b/src/lib/dom-api-shadow.html @@ -58,6 +58,13 @@ 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 64e41c1c49..9d00661e95 100644 --- a/src/lib/dom-api-shady.html +++ b/src/lib/dom-api-shady.html @@ -422,6 +422,47 @@ 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 @@ }; })(); - \ No newline at end of file + diff --git a/test/unit/polymer-dom-elements.html b/test/unit/polymer-dom-elements.html index c0b28546aa..a4c39fd7a1 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 f1f5267810..cc2a5c2c81 100644 --- a/test/unit/polymer-dom-shadow.html +++ b/test/unit/polymer-dom-shadow.html @@ -57,6 +57,10 @@ + + + + diff --git a/test/unit/polymer-dom.html b/test/unit/polymer-dom.html index 7899b1c2df..7f0e15c52e 100644 --- a/test/unit/polymer-dom.html +++ b/test/unit/polymer-dom.html @@ -57,6 +57,10 @@ + + + + diff --git a/test/unit/polymer-dom.js b/test/unit/polymer-dom.js index c11a6e8dd5..f6e06747ea 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() {