Commit 94c1b063 authored by Moe Ahmadi's avatar Moe Ahmadi Committed by Commit Bot

Local NTP, Realbox: Stops tracking the match element being deleted

Currently we track the match element being deleted. This is in order to
detect focusout events on the realbox wrapper as a result of matches being
replaced by new ones after deletion. This CL avoids that by stopping to
listen for 'focusout' just before the matches are replaced and starting to
listen for it immediately after.

Bug: 243926
Change-Id: I8e37fdc7d6a1f52f052de6ef3ec711ed7bc927bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1879660
Commit-Queue: Moe Ahmadi <mahmadi@chromium.org>
Reviewed-by: default avatarDan Beam <dbeam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709701}
parent 4848564e
...@@ -268,13 +268,6 @@ let isDarkModeEnabled = false; ...@@ -268,13 +268,6 @@ let isDarkModeEnabled = false;
/** Used to prevent inline autocompleting recently deleted output. */ /** Used to prevent inline autocompleting recently deleted output. */
let isDeletingInput = false; let isDeletingInput = false;
/**
* The rendered autocomplete match currently being deleted, or null if there
* isn't one.
* @type {?Element}
*/
let matchElBeingDeleted = null;
/** /**
* The last blacklisted tile rid if any, which by definition should not be * The last blacklisted tile rid if any, which by definition should not be
* filler. * filler.
...@@ -761,9 +754,8 @@ function init() { ...@@ -761,9 +754,8 @@ function init() {
realboxEl.addEventListener('cut', onRealboxCutCopy); realboxEl.addEventListener('cut', onRealboxCutCopy);
realboxEl.addEventListener('input', onRealboxInput); realboxEl.addEventListener('input', onRealboxInput);
const realboxWrapper = $(IDS.REALBOX_INPUT_WRAPPER); setRealboxWrapperListenForFocusIn(true);
realboxWrapper.addEventListener('focusin', onRealboxWrapperFocusIn); setRealboxWrapperListenForFocusOut(true);
realboxWrapper.addEventListener('focusout', onRealboxWrapperFocusOut);
searchboxApiHandle.onqueryautocompletedone = onQueryAutocompleteDone; searchboxApiHandle.onqueryautocompletedone = onQueryAutocompleteDone;
searchboxApiHandle.ondeleteautocompletematch = onDeleteAutocompleteMatch; searchboxApiHandle.ondeleteautocompletematch = onDeleteAutocompleteMatch;
...@@ -1076,10 +1068,7 @@ function onAddCustomLinkDone(success) { ...@@ -1076,10 +1068,7 @@ function onAddCustomLinkDone(success) {
/** @param {!DeleteAutocompleteMatchResult} result */ /** @param {!DeleteAutocompleteMatchResult} result */
function onDeleteAutocompleteMatch(result) { function onDeleteAutocompleteMatch(result) {
assert(matchElBeingDeleted);
if (!result.success) { if (!result.success) {
matchElBeingDeleted = null;
return; return;
} }
...@@ -1091,7 +1080,6 @@ function onDeleteAutocompleteMatch(result) { ...@@ -1091,7 +1080,6 @@ function onDeleteAutocompleteMatch(result) {
const wasFocused = matchEls[selected].contains(document.activeElement); const wasFocused = matchEls[selected].contains(document.activeElement);
populateAutocompleteMatches(result.matches); populateAutocompleteMatches(result.matches);
matchElBeingDeleted = null;
if (result.matches.length === 0) { if (result.matches.length === 0) {
if (wasFocused) { if (wasFocused) {
...@@ -1248,18 +1236,14 @@ function onRealboxWrapperFocusIn(e) { ...@@ -1248,18 +1236,14 @@ function onRealboxWrapperFocusIn(e) {
/** @param {Event} e */ /** @param {Event} e */
function onRealboxWrapperFocusOut(e) { function onRealboxWrapperFocusOut(e) {
const target = /** @type {Element} */ (e.target); // Hide the matches and stop autocomplete only when the focus goes outside of
if (matchElBeingDeleted && matchElBeingDeleted.contains(target)) { // the realbox wrapper.
// When a match is being deleted, the focus gets dropped temporariliy as the
// element is deleted from the DOM. Don't stop autocomplete in those cases.
return;
}
const relatedTarget = /** @type {Element} */ (e.relatedTarget); const relatedTarget = /** @type {Element} */ (e.relatedTarget);
const realboxWrapper = $(IDS.REALBOX_INPUT_WRAPPER); const realboxWrapper = $(IDS.REALBOX_INPUT_WRAPPER);
if (!realboxWrapper.contains(relatedTarget)) { if (!realboxWrapper.contains(relatedTarget)) {
setRealboxMatchesVisible(false); setRealboxMatchesVisible(false);
// Note: intentionally leaving keydown listening and match data intact. // Note: intentionally leaving keydown listening (see
// onRealboxWrapperKeydown) and match data intact.
window.chrome.embeddedSearch.searchBox.stopAutocomplete( window.chrome.embeddedSearch.searchBox.stopAutocomplete(
/*clearResult=*/ true); /*clearResult=*/ true);
} }
...@@ -1307,7 +1291,6 @@ function onRealboxWrapperKeydown(e) { ...@@ -1307,7 +1291,6 @@ function onRealboxWrapperKeydown(e) {
if (key === 'Delete') { if (key === 'Delete') {
if (e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey && if (e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey &&
autocompleteMatches[selected].supportsDeletion) { autocompleteMatches[selected].supportsDeletion) {
matchElBeingDeleted = matchEls[selected];
window.chrome.embeddedSearch.searchBox.deleteAutocompleteMatch(selected); window.chrome.embeddedSearch.searchBox.deleteAutocompleteMatch(selected);
e.preventDefault(); e.preventDefault();
} }
...@@ -1506,7 +1489,6 @@ function populateAutocompleteMatches(matches) { ...@@ -1506,7 +1489,6 @@ function populateAutocompleteMatches(matches) {
e.preventDefault(); // Stops default browser action (focus) e.preventDefault(); // Stops default browser action (focus)
}; };
icon.onclick = e => { icon.onclick = e => {
matchElBeingDeleted = matchEl;
window.chrome.embeddedSearch.searchBox.deleteAutocompleteMatch(i); window.chrome.embeddedSearch.searchBox.deleteAutocompleteMatch(i);
e.preventDefault(); // Stops default browser action (navigation) e.preventDefault(); // Stops default browser action (navigation)
}; };
...@@ -1522,11 +1504,19 @@ function populateAutocompleteMatches(matches) { ...@@ -1522,11 +1504,19 @@ function populateAutocompleteMatches(matches) {
realboxMatchesEl.append(matchEl); realboxMatchesEl.append(matchEl);
} }
// When the matches are replaced, the focus gets dropped temporariliy as the
// focused element is being deleted from the DOM. Stop listening to 'focusout'
// event and retore it immediately after since we don't want to stop
// autocomplete in those cases.
setRealboxWrapperListenForFocusOut(false);
$(IDS.REALBOX_MATCHES).remove(); $(IDS.REALBOX_MATCHES).remove();
realboxMatchesEl.id = IDS.REALBOX_MATCHES; realboxMatchesEl.id = IDS.REALBOX_MATCHES;
$(IDS.REALBOX_INPUT_WRAPPER).appendChild(realboxMatchesEl); $(IDS.REALBOX_INPUT_WRAPPER).appendChild(realboxMatchesEl);
setRealboxWrapperListenForFocusOut(true);
const hasMatches = matches.length > 0; const hasMatches = matches.length > 0;
setRealboxMatchesVisible(hasMatches); setRealboxMatchesVisible(hasMatches);
setRealboxWrapperListenForKeydown(hasMatches); setRealboxWrapperListenForKeydown(hasMatches);
...@@ -1844,6 +1834,26 @@ function setRealboxMatchesVisible(visible) { ...@@ -1844,6 +1834,26 @@ function setRealboxMatchesVisible(visible) {
$(IDS.REALBOX_INPUT_WRAPPER).classList.toggle(CLASSES.SHOW_MATCHES, visible); $(IDS.REALBOX_INPUT_WRAPPER).classList.toggle(CLASSES.SHOW_MATCHES, visible);
} }
/** @param {boolean} listen */
function setRealboxWrapperListenForFocusIn(listen) {
const realboxWrapper = $(IDS.REALBOX_INPUT_WRAPPER);
if (listen) {
realboxWrapper.addEventListener('focusin', onRealboxWrapperFocusIn);
} else {
realboxWrapper.removeEventListener('focusin', onRealboxWrapperFocusIn);
}
}
/** @param {boolean} listen */
function setRealboxWrapperListenForFocusOut(listen) {
const realboxWrapper = $(IDS.REALBOX_INPUT_WRAPPER);
if (listen) {
realboxWrapper.addEventListener('focusout', onRealboxWrapperFocusOut);
} else {
realboxWrapper.removeEventListener('focusout', onRealboxWrapperFocusOut);
}
}
/** @param {boolean} listen */ /** @param {boolean} listen */
function setRealboxWrapperListenForKeydown(listen) { function setRealboxWrapperListenForKeydown(listen) {
const realboxWrapper = $(IDS.REALBOX_INPUT_WRAPPER); const realboxWrapper = $(IDS.REALBOX_INPUT_WRAPPER);
......
...@@ -111,15 +111,11 @@ test.realbox.setUp = function() { ...@@ -111,15 +111,11 @@ test.realbox.setUp = function() {
queryAutocomplete(query) { queryAutocomplete(query) {
test.realbox.queries.push(query); test.realbox.queries.push(query);
}, },
stopAutocomplete(clearResult) {
test.realbox.stops.push(clearResult);
},
}, },
}; };
test.realbox.deletedLines = []; test.realbox.deletedLines = [];
test.realbox.queries = []; test.realbox.queries = [];
test.realbox.stops = [];
initLocalNTP(/*isGooglePage=*/ true); initLocalNTP(/*isGooglePage=*/ true);
...@@ -559,14 +555,6 @@ test.realbox.testSupportedDeletion = function() { ...@@ -559,14 +555,6 @@ test.realbox.testSupportedDeletion = function() {
test.realbox.realboxEl.dispatchEvent(shiftDelete); test.realbox.realboxEl.dispatchEvent(shiftDelete);
assertTrue(shiftDelete.defaultPrevented); assertTrue(shiftDelete.defaultPrevented);
// Pretend like the focused match gets removed from DOM when deleted.
matchesEl.children[1].dispatchEvent(new Event('focusout', {bubbles: true}));
// stopAutocomplete() should not be called if the focused match gets removed
// from the DOM (and focus gets dropped). There's explicit code in the
// focusout handler to deal with this case.
assertEquals(0, test.realbox.stops.length);
assertEquals(1, test.realbox.deletedLines.length); assertEquals(1, test.realbox.deletedLines.length);
assertEquals(1, test.realbox.deletedLines[0]); assertEquals(1, test.realbox.deletedLines[0]);
...@@ -629,15 +617,6 @@ test.realbox.testRemoveIcon = function() { ...@@ -629,15 +617,6 @@ test.realbox.testRemoveIcon = function() {
assertEquals(1, test.realbox.deletedLines.length); assertEquals(1, test.realbox.deletedLines.length);
assertEquals(0, test.realbox.deletedLines[0]); assertEquals(0, test.realbox.deletedLines[0]);
assertEquals(0, test.realbox.stops.length);
icon.dispatchEvent(new Event('focusout', {
bubbles: true,
cancelable: true,
target: icon,
relatedTarget: document.body,
}));
assertEquals(0, test.realbox.stops.length);
chrome.embeddedSearch.searchBox.ondeleteautocompletematch( chrome.embeddedSearch.searchBox.ondeleteautocompletematch(
{success: true, matches: []}); {success: true, matches: []});
......
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