Files
Netzenbot f2ad0c1142 Fix flaky AIChatRenderViewContextMenuBrowserTest.RewriteInPlace_InputText (#34118)
The wait_for_text() JavaScript function in rewrite.html used only a
MutationObserver to detect text changes. MutationObserver observes DOM
node mutations (childList, subtree, characterData) but does NOT observe
.value property changes on <input> and <textarea> elements. When the
Replace() IPC updates an input element's value asynchronously, the
MutationObserver never fires, causing EvalJs to time out.

Add an 'input' event listener alongside the MutationObserver so that
value changes on form elements are properly detected. MutationObserver
continues to handle contenteditable elements. A resolved flag prevents
duplicate resolution.

Resolves brave/brave-browser#53073
2026-02-23 19:06:53 -05:00

91 lines
2.9 KiB
HTML

<!DOCTYPE HTML>
<html>
<head>
<title>Text Rewrite</title>
</head>
<style>
.container {
display: flex;
flex-direction: row;
}
.container > * {
margin-right: 200px;
}
</style>
</head>
<script>
function get_text(id) {
var element = document.getElementById(id);
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
return element.value;
}
return element.innerText;
}
// Returns a promise that resolves when the element's text equals expected.
// Used to wait for async DOM updates from Replace() IPC.
function wait_for_text(id, expected) {
var element = document.getElementById(id);
if (get_text(id) === expected) {
return Promise.resolve(get_text(id));
}
return new Promise(function(resolve) {
var resolved = false;
function checkAndResolve() {
if (!resolved && get_text(id) === expected) {
resolved = true;
observer.disconnect();
element.removeEventListener('input', checkAndResolve);
resolve(get_text(id));
}
}
// MutationObserver for contenteditable elements (DOM node changes).
var observer = new MutationObserver(checkAndResolve);
observer.observe(element,
{childList: true, subtree: true, characterData: true});
// input event for input/textarea elements whose .value property
// changes are not observed by MutationObserver.
element.addEventListener('input', checkAndResolve);
});
}
function select_all(id) {
var element = document.getElementById(id);
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
element.select();
return element.value.substring(
element.selectionStart, element.selectionEnd);
} else {
// Focus the element first to ensure the browser recognizes the context
// as editable for contenteditable elements.
element.focus();
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
return selection.toString();
}
}
function getRectX(id) {
var element = document.getElementById(id);
var rect = element.getBoundingClientRect();
return Math.ceil(rect.x);
}
function getRectY(id) {
var element = document.getElementById(id);
var rect = element.getBoundingClientRect();
return Math.ceil(rect.y);
}
</script>
<body>
<div class="container">
<div id="contenteditable" contenteditable="true">I'm contenteditable.</div>
<div><textarea id="textarea">I'm textarea.</textarea></div>
<div><input type="input_text" id="input_text" value="I'm input."></div>
</div>
</body>
</html>