Commit d7fab5c5 authored by Dan Beam's avatar Dan Beam Committed by Commit Bot

Add an option to include shadow hosts to findAncestor() in util.js

This allows findAncestor() to continue when it reaches a shadow boundary.

Bug: 355446
Change-Id: I2588b04b545572535bb2a58450a3cca7b65454c0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1963137
Commit-Queue: Dan Beam <dbeam@chromium.org>
Commit-Queue: Demetrios Papadopoulos <dpapad@chromium.org>
Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Auto-Submit: Dan Beam <dbeam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#724101}
parent 139ebe2b
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {$, quoteString} from 'chrome://resources/js/util.m.js';
import {$, findAncestor, quoteString} from 'chrome://resources/js/util.m.js';
suite('UtilModuleTest', function() {
test('quote string', function() {
......@@ -22,4 +22,30 @@ suite('UtilModuleTest', function() {
match = re.exec('Hello, world');
assertEquals(null, match);
});
test('findAncestor', function() {
const option = document.createElement('option');
option.value = 'success';
const failure = document.createTextNode('is not an option');
option.appendChild(failure);
const select = document.createElement('select');
select.appendChild(option);
const div = document.createElement('div');
const root = div.attachShadow({mode: 'open'});
root.appendChild(select);
assertEquals(findAncestor(failure, n => n.nodeName === 'SELECT'), select);
// findAncestor() only traverses shadow roots (which |div| is outside of) if
// |includeShadowHosts| is true. If omitted, |div| shouldn't be found.
assertEquals(findAncestor(failure, n => n.nodeName === 'DIV'), null);
assertEquals(
findAncestor(
failure, n => n.nodeName === 'DIV',
/*includeShadowHosts=*/ true),
div);
});
});
......@@ -14,14 +14,38 @@ function testQuoteString() {
quoteString('(._.) ( :l ) (.-.)'));
// Using the output as a regex.
var re = new RegExp(quoteString('"hello"'), 'gim');
var match = re.exec('She said "Hello" loudly');
let re = new RegExp(quoteString('"hello"'), 'gim');
let match = re.exec('She said "Hello" loudly');
assertEquals(9, match.index);
re = new RegExp(quoteString('Hello, .*'), 'gim');
match = re.exec('Hello, world');
assertEquals(null, match);
}
function testFindAncestor() {
const option = document.createElement('option');
option.value = 'success';
const failure = document.createTextNode('is not an option');
option.appendChild(failure);
const select = document.createElement('select');
select.appendChild(option);
const div = document.createElement('div');
const root = div.attachShadow({mode: 'open'});
root.appendChild(select);
assertEquals(findAncestor(failure, n => n.nodeName === 'SELECT'), select);
// findAncestor() only traverses shadow roots (which |div| is outside of) if
// |includeShadowHosts| is true. If omitted, |div| shouldn't be found.
assertEquals(findAncestor(failure, n => n.nodeName === 'DIV'), null);
assertEquals(findAncestor(failure, n => n.nodeName === 'DIV',
/*includeShadowHosts=*/true), div);
}
</script>
</body>
</html>
......@@ -85,14 +85,18 @@
* @param {Node} node The node to check.
* @param {function(Node):boolean} predicate The function that tests the
* nodes.
* @param {boolean=} includeShadowHosts
* @return {Node} The found ancestor or null if not found.
*/
/* #export */ function findAncestor(node, predicate) {
let last = false;
while (node != null && !(last = predicate(node))) {
node = node.parentNode;
/* #export */ function findAncestor(node, predicate, includeShadowHosts) {
while (node !== null) {
if (predicate(node)) {
break;
}
node = includeShadowHosts && node instanceof ShadowRoot ? node.host :
node.parentNode;
}
return last ? node : null;
return node;
}
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment