Commit 9edebb56 authored by Anastasia Helfinstein's avatar Anastasia Helfinstein Committed by Commit Bot

Add RepeatedTreeChangeHandler to accessibility/common

AX-Relnotes: n/a.
Bug: None
Change-Id: Ia65bacff95aed253d5ef7fd1bb286d0f19723e5d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2302737
Commit-Queue: Anastasia Helfinstein <anastasi@google.com>
Reviewed-by: default avatarKatie Dektar <katie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#789330}
parent b3ec47af
...@@ -30,6 +30,7 @@ run_jsbundler("accessibility_common_copied_files") { ...@@ -30,6 +30,7 @@ run_jsbundler("accessibility_common_copied_files") {
"closure_shim.js", "closure_shim.js",
"constants.js", "constants.js",
"repeated_event_handler.js", "repeated_event_handler.js",
"repeated_tree_change_handler.js",
"tree_walker.js", "tree_walker.js",
] ]
rewrite_rules = [ rebase_path(".", root_build_dir) + ":" ] rewrite_rules = [ rebase_path(".", root_build_dir) + ":" ]
...@@ -83,6 +84,10 @@ js_library("repeated_event_handler") { ...@@ -83,6 +84,10 @@ js_library("repeated_event_handler") {
externs_list = [ "$externs_path/automation.js" ] externs_list = [ "$externs_path/automation.js" ]
} }
js_library("repeated_tree_change_handler") {
externs_list = [ "$externs_path/automation.js" ]
}
source_set("browser_tests") { source_set("browser_tests") {
testonly = true testonly = true
assert(enable_extensions) assert(enable_extensions)
...@@ -114,6 +119,7 @@ js2gtest("accessibility_tests") { ...@@ -114,6 +119,7 @@ js2gtest("accessibility_tests") {
"array_util_test.js", "array_util_test.js",
"automation_util_test.js", "automation_util_test.js",
"repeated_event_handler_test.js", "repeated_event_handler_test.js",
"repeated_tree_change_handler_test.js",
"tree_walker_test.js", "tree_walker_test.js",
] ]
gen_include_files = [ gen_include_files = [
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* This class assists with processing repeated tree changes in nontrivial ways
* by allowing only the most recent tree change to be processed.
*/
class RepeatedTreeChangeHandler {
/**
* @param {!chrome.automation.TreeChangeObserverFilter} filter
* @param {!function(!chrome.automation.TreeChange)} callback
* @param {{predicate: (function(!chrome.automation.TreeChange): boolean)}}
* options
* predicate A generic predicate that filters for changes of interest.
*/
constructor(filter, callback, options = {}) {
/** @private {!Array<!chrome.automation.TreeChange>} */
this.changeStack_ = [];
/** @private {!function(!chrome.automation.TreeChange)} */
this.callback_ = callback;
/**
* A predicate for which tree changes are of interest. If none is provided,
* default to always return true.
* @private {!function(!chrome.automation.TreeChange)}
*/
this.predicate_ = options.predicate || ((c) => true);
/** @private {!function(!chrome.automation.TreeChange)} */
this.handler_ = this.onChange_.bind(this);
chrome.automation.addTreeChangeObserver(filter, this.handler_);
}
/**
* @param {!chrome.automation.TreeChange} change
* @private
*/
onChange_(change) {
if (this.predicate_(change)) {
this.changeStack_.push(change);
setTimeout(this.handleChange_.bind(this), 0);
}
}
/** @private */
handleChange_() {
if (this.changeStack_.length === 0) {
return;
}
const change = this.changeStack_.pop();
this.changeStack_ = [];
this.callback_(change);
}
}
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Include test fixture.
GEN_INCLUDE([
'../chromevox/testing/chromevox_next_e2e_test_base.js',
'repeated_tree_change_handler.js'
]);
/** Test fixture for array_util.js. */
RepeatedTreeChangeHandlerTest = class extends ChromeVoxNextE2ETest {};
TEST_F(
'RepeatedTreeChangeHandlerTest', 'RepeatedTreeChangeHandledOnce',
function() {
this.runWithLoadedTree('', (root) => {
this.handlerCallCount = 0;
const handler = () => this.handlerCallCount++;
const repeatedHandler =
new RepeatedTreeChangeHandler('allTreeChanges', handler);
// Simulate events being fired.
repeatedHandler.onChange_();
repeatedHandler.onChange_();
repeatedHandler.onChange_();
repeatedHandler.onChange_();
repeatedHandler.onChange_();
// Yield before verifying how many times the handler was called.
setTimeout(() => assertEquals(this.handlerCallCount, 1), 0);
});
});
TEST_F('RepeatedTreeChangeHandlerTest', 'Predicate', function() {
this.runWithLoadedTree('', (root) => {
this.handlerCallCount = 0;
const handler = () => this.handlerCallCount++;
const repeatedHandler = new RepeatedTreeChangeHandler(
'allTreeChanges', handler,
{predicate: (c) => c.type === 'nodeRemoved'});
// Simulate events being fired.
repeatedHandler.onChange_({type: 'nodeAdded'});
repeatedHandler.onChange_({type: 'nodeAdded'});
repeatedHandler.onChange_({type: 'nodeAdded'});
repeatedHandler.onChange_({type: 'nodeRemoved'});
repeatedHandler.onChange_({type: 'nodeRemoved'});
repeatedHandler.onChange_({type: 'nodeRemoved'});
repeatedHandler.onChange_({type: 'nodeRemoved'});
// Verify that nodes that don't satisfy the predicate aren't added to the
// change stack.
assertEquals(repeatedHandler.changeStack_.length, 4);
// Yield before verifying how many times the handler was called.
setTimeout(() => assertEquals(this.handlerCallCount, 1), 0);
});
});
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