tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit cde18d32020c4b6dbc6dc62f0653ed17aeca30ec
parent 82b6d07b8f25677997aada620d8a7a2b590d4386
Author: Mark Banner <standard8@mozilla.com>
Date:   Wed,  5 Nov 2025 10:53:23 +0000

Bug 1996979 - Convert the Search object in UrlbarProviderPlaces to a class. r=urlbar-reviewers,jteow

Differential Revision: https://phabricator.services.mozilla.com/D270413

Diffstat:
Mbrowser/components/urlbar/UrlbarProviderPlaces.sys.mjs | 299++++++++++++++++++++++++++++++++++++++++---------------------------------------
1 file changed, 151 insertions(+), 148 deletions(-)

diff --git a/browser/components/urlbar/UrlbarProviderPlaces.sys.mjs b/browser/components/urlbar/UrlbarProviderPlaces.sys.mjs @@ -426,145 +426,148 @@ const MATCH_TYPE = { /** * Manages a single instance of a Places search. - * - * @param {UrlbarQueryContext} queryContext - * The query context. - * @param {Function} listener - * Called as: `listener(matches, searchOngoing)` - * @param {UrlbarProviderPlaces} provider - * The UrlbarProviderPlaces instance that started this search. */ -function Search(queryContext, listener, provider) { - // We want to store the original string for case sensitive searches. - this._originalSearchString = queryContext.searchString; - this._trimmedOriginalSearchString = queryContext.trimmedSearchString; - let unescapedSearchString = UrlbarUtils.unEscapeURIForUI( - this._trimmedOriginalSearchString - ); - // We want to make sure "about:" is not stripped as a prefix so that the - // about pages provider will run and ultimately only suggest about pages when - // a user types "about:" into the address bar. - let prefix, suffix; - if (unescapedSearchString.startsWith("about:")) { - prefix = ""; - suffix = unescapedSearchString; - } else { - [prefix, suffix] = UrlbarUtils.stripURLPrefix(unescapedSearchString); - } - this._searchString = suffix; - this._strippedPrefix = prefix.toLowerCase(); - - this._matchBehavior = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY; - // Set the default behavior for this search. - this._behavior = this._searchString - ? lazy.UrlbarPrefs.get("defaultBehavior") - : this._emptySearchDefaultBehavior; - - this._inPrivateWindow = queryContext.isPrivate; - this._prohibitAutoFill = !queryContext.allowAutofill; - // Increase the limit for the query because some results might - // get deduplicated if their URLs only differ by their refs. - this._maxResults = Math.round(queryContext.maxResults * 1.5); - this._userContextId = queryContext.userContextId; - this._currentPage = queryContext.currentPage; - this._searchModeEngine = queryContext.searchMode?.engineName; - this._searchMode = queryContext.searchMode; - if (this._searchModeEngine) { - // Filter Places results on host. - let engine = Services.search.getEngineByName(this._searchModeEngine); - this._filterOnHost = engine.searchUrlDomain; - } +class Search { + /** + * + * @param {UrlbarQueryContext} queryContext + * The query context. + * @param {Function} listener + * Called as: `listener(matches, searchOngoing)` + * @param {UrlbarProviderPlaces} provider + * The UrlbarProviderPlaces instance that started this search. + */ + constructor(queryContext, listener, provider) { + // We want to store the original string for case sensitive searches. + this._originalSearchString = queryContext.searchString; + this._trimmedOriginalSearchString = queryContext.trimmedSearchString; + let unescapedSearchString = UrlbarUtils.unEscapeURIForUI( + this._trimmedOriginalSearchString + ); + // We want to make sure "about:" is not stripped as a prefix so that the + // about pages provider will run and ultimately only suggest about pages when + // a user types "about:" into the address bar. + let prefix, suffix; + if (unescapedSearchString.startsWith("about:")) { + prefix = ""; + suffix = unescapedSearchString; + } else { + [prefix, suffix] = UrlbarUtils.stripURLPrefix(unescapedSearchString); + } + this._searchString = suffix; + this._strippedPrefix = prefix.toLowerCase(); + + this._matchBehavior = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY; + // Set the default behavior for this search. + this._behavior = this._searchString + ? lazy.UrlbarPrefs.get("defaultBehavior") + : this._emptySearchDefaultBehavior; + + this._inPrivateWindow = queryContext.isPrivate; + this._prohibitAutoFill = !queryContext.allowAutofill; + // Increase the limit for the query because some results might + // get deduplicated if their URLs only differ by their refs. + this._maxResults = Math.round(queryContext.maxResults * 1.5); + this._userContextId = queryContext.userContextId; + this._currentPage = queryContext.currentPage; + this._searchModeEngine = queryContext.searchMode?.engineName; + this._searchMode = queryContext.searchMode; + if (this._searchModeEngine) { + // Filter Places results on host. + let engine = Services.search.getEngineByName(this._searchModeEngine); + this._filterOnHost = engine.searchUrlDomain; + } - // Use the original string here, not the stripped one, so the tokenizer can - // properly recognize token types. - let { tokens } = lazy.UrlbarTokenizer.tokenize({ - searchString: unescapedSearchString, - trimmedSearchString: unescapedSearchString.trim(), - }); + // Use the original string here, not the stripped one, so the tokenizer can + // properly recognize token types. + let { tokens } = lazy.UrlbarTokenizer.tokenize({ + searchString: unescapedSearchString, + trimmedSearchString: unescapedSearchString.trim(), + }); - // This allows to handle leading or trailing restriction characters specially. - this._leadingRestrictionToken = null; - if (tokens.length) { - if ( - lazy.UrlbarTokenizer.isRestrictionToken(tokens[0]) && - (tokens.length > 1 || - tokens[0].type == lazy.UrlbarTokenizer.TYPE.RESTRICT_SEARCH) - ) { - this._leadingRestrictionToken = tokens[0].value; + // This allows to handle leading or trailing restriction characters specially. + this._leadingRestrictionToken = null; + if (tokens.length) { + if ( + lazy.UrlbarTokenizer.isRestrictionToken(tokens[0]) && + (tokens.length > 1 || + tokens[0].type == lazy.UrlbarTokenizer.TYPE.RESTRICT_SEARCH) + ) { + this._leadingRestrictionToken = tokens[0].value; + } + + // Check if the first token has a strippable prefix other than "about:" + // and remove it, but don't create an empty token. We preserve "about:" + // so that the about pages provider will run and ultimately only suggest + // about pages when a user types "about:" into the address bar. + if ( + prefix && + prefix != "about:" && + tokens[0].value.length > prefix.length + ) { + tokens[0].value = tokens[0].value.substring(prefix.length); + } } - // Check if the first token has a strippable prefix other than "about:" - // and remove it, but don't create an empty token. We preserve "about:" - // so that the about pages provider will run and ultimately only suggest - // about pages when a user types "about:" into the address bar. + // Eventually filter restriction tokens. In general it's a good idea, but if + // the consumer requested search mode, we should use the full string to avoid + // ignoring valid tokens. + this._searchTokens = + !queryContext || queryContext.restrictToken + ? this.filterTokens(tokens) + : tokens; + + // The behavior can be set through: + // 1. a specific restrictSource in the QueryContext + // 2. typed restriction tokens if ( - prefix && - prefix != "about:" && - tokens[0].value.length > prefix.length + queryContext && + queryContext.restrictSource && + lazy.sourceToBehaviorMap.has(queryContext.restrictSource) ) { - tokens[0].value = tokens[0].value.substring(prefix.length); - } - } + this._behavior = 0; + this.setBehavior("restrict"); + let behavior = lazy.sourceToBehaviorMap.get(queryContext.restrictSource); + this.setBehavior(behavior); - // Eventually filter restriction tokens. In general it's a good idea, but if - // the consumer requested search mode, we should use the full string to avoid - // ignoring valid tokens. - this._searchTokens = - !queryContext || queryContext.restrictToken - ? this.filterTokens(tokens) - : tokens; - - // The behavior can be set through: - // 1. a specific restrictSource in the QueryContext - // 2. typed restriction tokens - if ( - queryContext && - queryContext.restrictSource && - lazy.sourceToBehaviorMap.has(queryContext.restrictSource) - ) { - this._behavior = 0; - this.setBehavior("restrict"); - let behavior = lazy.sourceToBehaviorMap.get(queryContext.restrictSource); - this.setBehavior(behavior); - - // When we are in restrict mode, all the tokens are valid for searching, so - // there is no _heuristicToken. - this._heuristicToken = null; - } else { - // The heuristic token is the first filtered search token, but only when it's - // actually the first thing in the search string. If a prefix or restriction - // character occurs first, then the heurstic token is null. We use the - // heuristic token to help determine the heuristic result. - let firstToken = !!this._searchTokens.length && this._searchTokens[0].value; - this._heuristicToken = - firstToken && this._trimmedOriginalSearchString.startsWith(firstToken) - ? firstToken - : null; - } + // When we are in restrict mode, all the tokens are valid for searching, so + // there is no _heuristicToken. + this._heuristicToken = null; + } else { + // The heuristic token is the first filtered search token, but only when it's + // actually the first thing in the search string. If a prefix or restriction + // character occurs first, then the heurstic token is null. We use the + // heuristic token to help determine the heuristic result. + let firstToken = + !!this._searchTokens.length && this._searchTokens[0].value; + this._heuristicToken = + firstToken && this._trimmedOriginalSearchString.startsWith(firstToken) + ? firstToken + : null; + } - // Set the right JavaScript behavior based on our preference. Note that the - // preference is whether or not we should filter JavaScript, and the - // behavior is if we should search it or not. - if (!lazy.UrlbarPrefs.get("filter.javascript")) { - this.setBehavior("javascript"); - } + // Set the right JavaScript behavior based on our preference. Note that the + // preference is whether or not we should filter JavaScript, and the + // behavior is if we should search it or not. + if (!lazy.UrlbarPrefs.get("filter.javascript")) { + this.setBehavior("javascript"); + } - this._listener = listener; - this._provider = provider; - this._matches = []; + this._listener = listener; + this._provider = provider; + this._matches = []; - // These are used to avoid adding duplicate entries to the results. - this._usedURLs = []; - this._usedPlaceIds = new Set(); + // These are used to avoid adding duplicate entries to the results. + this._usedURLs = []; + this._usedPlaceIds = new Set(); - // Counters for the number of results per MATCH_TYPE. - this._counts = Object.values(MATCH_TYPE).reduce((o, p) => { - o[p] = 0; - return o; - }, {}); -} + // Counters for the number of results per MATCH_TYPE. + this._counts = Object.values(MATCH_TYPE).reduce((o, p) => { + o[p] = 0; + return o; + }, {}); + } -Search.prototype = { /** * Enables the desired AutoComplete behavior. * @@ -574,7 +577,7 @@ Search.prototype = { setBehavior(type) { type = type.toUpperCase(); this._behavior |= Ci.mozIPlacesAutoComplete["BEHAVIOR_" + type]; - }, + } /** * Determines if the specified AutoComplete behavior is set. @@ -586,7 +589,7 @@ Search.prototype = { hasBehavior(type) { let behavior = Ci.mozIPlacesAutoComplete["BEHAVIOR_" + type.toUpperCase()]; return this._behavior & behavior; - }, + } /** * Given an array of tokens, this function determines which query should be @@ -625,7 +628,7 @@ Search.prototype = { } } return filtered; - }, + } /** * Stop this search. @@ -645,12 +648,12 @@ Search.prototype = { this.interrupt(); } this.pending = false; - }, + } /** * Whether this search is active. */ - pending: true, + pending = true; /** * Execute the search and populate results. @@ -742,7 +745,7 @@ Search.prototype = { } } } - }, + } async _checkIfFirstTokenIsKeyword() { if (!this._heuristicToken) { @@ -768,7 +771,7 @@ Search.prototype = { } return false; - }, + } _onResultRow(row, cancel) { this._addFilteredQueryMatch(row); @@ -779,7 +782,7 @@ Search.prototype = { if (!this.pending || count >= this._maxResults) { cancel(); } - }, + } /** * Maybe restyle a SERP in history as a search-type result. To do this, @@ -851,7 +854,7 @@ Search.prototype = { match.icon = match.icon || match.iconUrl; match.style = "action searchengine favicon suggestion"; return true; - }, + } _addMatch(match) { if (typeof match.frecency != "number") { @@ -900,7 +903,7 @@ Search.prototype = { this._counts[match.type]++; this.notifyResult(true); - }, + } /** * @typedef {object} MatchPositionInformation @@ -1050,7 +1053,7 @@ Search.prototype = { comment: match.comment || "", }; return { index, replace }; - }, + } _makeGroups(resultGroup, maxResultCount) { if (!resultGroup.children) { @@ -1109,7 +1112,7 @@ Search.prototype = { for (let child of resultGroup.children) { this._makeGroups(child, childMaxResultCount); } - }, + } _addFilteredQueryMatch(row) { let placeId = row.getResultByName("id"); @@ -1167,7 +1170,7 @@ Search.prototype = { } this._addMatch(match); - }, + } /** * @returns {string} @@ -1244,7 +1247,7 @@ Search.prototype = { } return defaultQuery(conditions.join(" AND ")); - }, + } get _emptySearchDefaultBehavior() { // Further restrictions to apply for "empty searches" (searching for @@ -1260,7 +1263,7 @@ Search.prototype = { val |= Ci.mozIPlacesAutoComplete.BEHAVIOR_OPENPAGE; } return val; - }, + } /** * If the user-provided string starts with a keyword that gave a heuristic @@ -1274,7 +1277,7 @@ Search.prototype = { tokens = tokens.slice(1); } return tokens.join(" "); - }, + } /** * Obtains the search query to be used based on the previously set search @@ -1310,7 +1313,7 @@ Search.prototype = { params.host = this._filterOnHost; } return [this._suggestionPrefQuery, params]; - }, + } /** * Obtains the query to search for switch-to-tab entries. @@ -1337,7 +1340,7 @@ Search.prototype = { maxResults: this._maxResults, }, ]; - }, + } /** * The result is notified to the search listener on a timer, to chunk multiple @@ -1345,7 +1348,7 @@ Search.prototype = { * * @type {?nsITimer} */ - _notifyTimer: null, + _notifyTimer = null; /** * Notifies the current result to the listener. @@ -1353,7 +1356,7 @@ Search.prototype = { * @param searchOngoing * Indicates whether the search result should be marked as ongoing. */ - _notifyDelaysCount: 0, + _notifyDelaysCount = 0; notifyResult(searchOngoing) { let notify = () => { if (!this.pending) { @@ -1380,8 +1383,8 @@ Search.prototype = { this._notifyDelaysCount++; this._notifyTimer = setTimeout(notify, NOTIFYRESULT_DELAY_MS); } - }, -}; + } +} /** * Promise resolved when the database initialization has completed, or null