зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 6 changesets (bug 1650099, bug 1647881, bug 1645521, bug 1645324) for causing Bug 1652024.
Backed out changeset f66c5cce9088 (bug 1650099) Backed out changeset bf67c2159244 (bug 1645324) Backed out changeset 76d81e1e728b (bug 1645521) Backed out changeset ab3766fa81f9 (bug 1645521) Backed out changeset ff56bb6cbfb7 (bug 1645521) Backed out changeset aceb6f9acf3b (bug 1647881)
This commit is contained in:
Родитель
eee112f8f9
Коммит
b74c685d0f
|
@ -289,9 +289,6 @@ pref("browser.urlbar.speculativeConnect.enabled", true);
|
|||
// search for bookmarklets typing "javascript: " followed by the actual query.
|
||||
pref("browser.urlbar.filter.javascript", true);
|
||||
|
||||
// Enable a certain level of urlbar logging to the Browser Console. See Log.jsm.
|
||||
pref("browser.urlbar.loglevel", "Error");
|
||||
|
||||
// the maximum number of results to show in autocomplete when doing richResults
|
||||
pref("browser.urlbar.maxRichResults", 10);
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ add_task(async function test_registerProvider() {
|
|||
});
|
||||
|
||||
// Adds a single active provider that returns many kinds of results. This also
|
||||
// checks that the heuristic result from the built-in HeuristicFallback provider
|
||||
// checks that the heuristic result from the built-in UnifiedComplete provider
|
||||
// is included.
|
||||
add_task(async function test_onProviderResultsRequested() {
|
||||
let ext = ExtensionTestUtils.loadExtension({
|
||||
|
@ -276,7 +276,7 @@ add_task(async function test_onProviderResultsRequested() {
|
|||
|
||||
// Check the results.
|
||||
let expectedResults = [
|
||||
// The first result should be a search result returned by HeuristicFallback.
|
||||
// The first result should be a search result returned by UnifiedComplete.
|
||||
{
|
||||
type: UrlbarUtils.RESULT_TYPE.SEARCH,
|
||||
source: UrlbarUtils.RESULT_SOURCE.SEARCH,
|
||||
|
|
|
@ -14,11 +14,11 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
clearTimeout: "resource://gre/modules/Timer.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
setTimeout: "resource://gre/modules/Timer.jsm",
|
||||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
UrlbarUtils.getLogger({ prefix: "EventBufferer" })
|
||||
Log.repository.getLogger("Urlbar.EventBufferer")
|
||||
);
|
||||
|
||||
// Maximum time events can be deferred for.
|
||||
|
|
|
@ -14,6 +14,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
|
||||
UrlbarMuxer: "resource:///modules/UrlbarUtils.jsm",
|
||||
|
@ -21,7 +22,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
UrlbarUtils.getLogger({ prefix: "MuxerUnifiedComplete" })
|
||||
Log.repository.getLogger("Urlbar.Muxer.UnifiedComplete")
|
||||
);
|
||||
|
||||
function groupFromResult(result) {
|
||||
|
@ -40,16 +41,6 @@ function groupFromResult(result) {
|
|||
}
|
||||
}
|
||||
|
||||
// Breaks ties among heuristic results. Providers higher up the list are higher
|
||||
// priority.
|
||||
const heuristicOrder = [
|
||||
// Test providers are handled in sort(),
|
||||
// Extension providers are handled in sort(),
|
||||
"UrlbarProviderSearchTips",
|
||||
"Omnibox",
|
||||
"UnifiedComplete",
|
||||
"HeuristicFallback",
|
||||
];
|
||||
/**
|
||||
* Class used to create a muxer.
|
||||
* The muxer receives and sorts results in a UrlbarQueryContext.
|
||||
|
@ -63,19 +54,11 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
|
|||
return "UnifiedComplete";
|
||||
}
|
||||
|
||||
/* eslint-disable complexity */
|
||||
/**
|
||||
* Sorts results in the given UrlbarQueryContext.
|
||||
*
|
||||
* sort() is not suitable to be broken up into smaller functions or to rely
|
||||
* on more convenience functions. It exists to efficiently group many
|
||||
* conditions into just three loops. As a result, we must disable complexity
|
||||
* linting.
|
||||
*
|
||||
* @param {UrlbarQueryContext} context
|
||||
* The query context.
|
||||
* @returns {boolean} If results were successfully sorted. This return value
|
||||
* is a stopgap and can be removed when bug 1648468 lands.
|
||||
*/
|
||||
sort(context) {
|
||||
// This method is called multiple times per keystroke, so it should be as
|
||||
|
@ -87,42 +70,19 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
|
|||
|
||||
// Capture information about the heuristic result to dedupe results from the
|
||||
// heuristic more quickly.
|
||||
let topHeuristicRank = Infinity;
|
||||
for (let result of context.allHeuristicResults) {
|
||||
// Determine the highest-ranking heuristic result.
|
||||
if (!result.heuristic) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// + 2 to reserve the highest-priority slots for test and extension
|
||||
// providers.
|
||||
let heuristicRank = heuristicOrder.indexOf(result.providerName) + 2;
|
||||
// Extension and test provider names vary widely and aren't suitable
|
||||
// for a static safelist like heuristicOrder.
|
||||
if (result.providerType == UrlbarUtils.PROVIDER_TYPE.EXTENSION) {
|
||||
heuristicRank = 1;
|
||||
} else if (result.providerName.startsWith("TestProvider")) {
|
||||
heuristicRank = 0;
|
||||
} else if (heuristicRank - 2 == -1) {
|
||||
throw new Error(
|
||||
`Heuristic result returned by unexpected provider: ${result.providerName}`
|
||||
);
|
||||
}
|
||||
// Replace in case of ties, which would occur if a provider sent two
|
||||
// heuristic results.
|
||||
if (heuristicRank <= topHeuristicRank) {
|
||||
topHeuristicRank = heuristicRank;
|
||||
context.heuristicResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
let heuristicResultQuery;
|
||||
let heuristicResultOmniboxContent;
|
||||
if (context.heuristicResult) {
|
||||
if (
|
||||
context.heuristicResult.type == UrlbarUtils.RESULT_TYPE.SEARCH &&
|
||||
context.heuristicResult.payload.query
|
||||
) {
|
||||
heuristicResultQuery = context.heuristicResult.payload.query.toLocaleLowerCase();
|
||||
} else if (
|
||||
context.heuristicResult.type == UrlbarUtils.RESULT_TYPE.OMNIBOX &&
|
||||
context.heuristicResult.payload.content
|
||||
) {
|
||||
heuristicResultOmniboxContent = context.heuristicResult.payload.content.toLocaleLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,17 +95,10 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
|
|||
UrlbarPrefs.get("maxHistoricalSearchSuggestions"),
|
||||
context.maxResults
|
||||
);
|
||||
let hasUnifiedComplete = false;
|
||||
|
||||
// Do the first pass through the results. We only collect info for the
|
||||
// second pass here.
|
||||
for (let result of context.results) {
|
||||
// Keep track of whether UnifiedComplete has returned results. We will
|
||||
// quit early if it hasn't.
|
||||
if (result.providerName == "UnifiedComplete") {
|
||||
hasUnifiedComplete = true;
|
||||
}
|
||||
|
||||
// The "Search in a Private Window" result should only be shown when there
|
||||
// are other results and all of them are searches. It should not be shown
|
||||
// if the user typed an alias because that's an explicit engine choice.
|
||||
|
@ -186,24 +139,9 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
|
|||
}
|
||||
}
|
||||
|
||||
// Quit early if we're still waiting on UnifiedComplete. If it turns out
|
||||
// UnifiedComplete doesn't need to return any results, it will call sort()
|
||||
// regardless to unblock showing results.
|
||||
if (
|
||||
!hasUnifiedComplete &&
|
||||
context.pendingHeuristicProviders.has("UnifiedComplete")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do the second pass through results to build the list of unsorted results.
|
||||
let unsortedResults = [];
|
||||
for (let result of context.results) {
|
||||
// Exclude low-ranked heuristic results.
|
||||
if (result.heuristic && result != context.heuristicResult) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude "Search in a Private Window" as determined in the first pass.
|
||||
if (
|
||||
result.type == UrlbarUtils.RESULT_TYPE.SEARCH &&
|
||||
|
@ -276,6 +214,15 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
|
|||
}
|
||||
}
|
||||
|
||||
// Exclude omnibox results that dupe the heuristic.
|
||||
if (
|
||||
!result.heuristic &&
|
||||
result.type == UrlbarUtils.RESULT_TYPE.OMNIBOX &&
|
||||
result.payload.content == heuristicResultOmniboxContent
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Include this result.
|
||||
unsortedResults.push(result);
|
||||
}
|
||||
|
@ -325,7 +272,6 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
|
|||
}
|
||||
|
||||
context.results = sortedResults;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -286,7 +286,6 @@ class UrlbarProviderExtension extends UrlbarProvider {
|
|||
name: "UrlbarProviderExtension notification timer",
|
||||
time: UrlbarProviderExtension.notificationTimeout,
|
||||
reportErrorOnTimeout: true,
|
||||
logger: this.logger,
|
||||
});
|
||||
result = await Promise.race([
|
||||
timer.promise,
|
||||
|
|
|
@ -1,283 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This module exports a provider that provides a heuristic result. The result
|
||||
* either vists a URL or does a search with the current engine. This result is
|
||||
* always the ultimate fallback for any query, so this provider is always active.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ["UrlbarProviderHeuristicFallback"];
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
|
||||
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
|
||||
UrlbarResult: "resource:///modules/UrlbarResult.jsm",
|
||||
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.jsm",
|
||||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
});
|
||||
|
||||
/**
|
||||
* Class used to create the provider.
|
||||
*/
|
||||
class ProviderHeuristicFallback extends UrlbarProvider {
|
||||
constructor() {
|
||||
super();
|
||||
// Maps the running queries by queryContext.
|
||||
this.queries = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this provider.
|
||||
* @returns {string} the name of this provider.
|
||||
*/
|
||||
get name() {
|
||||
return "HeuristicFallback";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this provider.
|
||||
* @returns {integer} one of the types from UrlbarUtils.PROVIDER_TYPE.*
|
||||
*/
|
||||
get type() {
|
||||
return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this provider should be invoked for the given context.
|
||||
* If this method returns false, the providers manager won't start a query
|
||||
* with this provider, to save on resources.
|
||||
* @param {UrlbarQueryContext} queryContext The query context object
|
||||
* @returns {boolean} Whether this provider should be invoked for the search.
|
||||
*/
|
||||
isActive(queryContext) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the provider's priority.
|
||||
* @param {UrlbarQueryContext} queryContext The query context object
|
||||
* @returns {number} The provider's priority for the given query.
|
||||
*/
|
||||
getPriority(queryContext) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts querying.
|
||||
* @param {object} queryContext The query context object
|
||||
* @param {function} addCallback Callback invoked by the provider to add a new
|
||||
* result.
|
||||
* @returns {Promise} resolved when the query stops.
|
||||
*/
|
||||
async startQuery(queryContext, addCallback) {
|
||||
let instance = {};
|
||||
this.queries.set(queryContext, instance);
|
||||
|
||||
let result = this._matchUnknownUrl(queryContext);
|
||||
if (result) {
|
||||
addCallback(this, result);
|
||||
// Since we can't tell if this is a real URL and whether the user wants
|
||||
// to visit or search for it, we provide an alternative searchengine
|
||||
// match if the string looks like an alphanumeric origin or an e-mail.
|
||||
let str = queryContext.searchString;
|
||||
try {
|
||||
new URL(str);
|
||||
} catch (ex) {
|
||||
if (
|
||||
UrlbarPrefs.get("keyword.enabled") &&
|
||||
(UrlbarTokenizer.looksLikeOrigin(str, {
|
||||
noIp: true,
|
||||
noPort: true,
|
||||
}) ||
|
||||
UrlbarTokenizer.REGEXP_COMMON_EMAIL.test(str))
|
||||
) {
|
||||
let searchResult = await this._defaultEngineSearchResult(
|
||||
queryContext
|
||||
);
|
||||
if (!this.queries.has(queryContext)) {
|
||||
return;
|
||||
}
|
||||
addCallback(this, searchResult);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = await this._defaultEngineSearchResult(queryContext);
|
||||
if (!result || !this.queries.has(queryContext)) {
|
||||
return;
|
||||
}
|
||||
result.heuristic = true;
|
||||
addCallback(this, result);
|
||||
}
|
||||
|
||||
this.queries.delete(queryContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a running query.
|
||||
* @param {object} queryContext The query context object
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
this.queries.delete(queryContext);
|
||||
}
|
||||
|
||||
// TODO (bug 1054814): Use visited URLs to inform which scheme to use, if the
|
||||
// scheme isn't specificed.
|
||||
_matchUnknownUrl(queryContext) {
|
||||
let unescapedSearchString = Services.textToSubURI.unEscapeURIForUI(
|
||||
queryContext.searchString
|
||||
);
|
||||
let [prefix, suffix] = UrlbarUtils.stripURLPrefix(unescapedSearchString);
|
||||
if (!suffix && prefix) {
|
||||
// The user just typed a stripped protocol, don't build a non-sense url
|
||||
// like http://http/ for it.
|
||||
return null;
|
||||
}
|
||||
// The user may have typed something like "word?" to run a search, we should
|
||||
// not convert that to a url.
|
||||
if (
|
||||
queryContext.restrictSource &&
|
||||
queryContext.restrictSource == UrlbarUtils.RESULT_SOURCE.SEARCH
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let searchUrl = queryContext.searchString.trim();
|
||||
|
||||
if (queryContext.fixupError) {
|
||||
if (
|
||||
queryContext.fixupError == Cr.NS_ERROR_MALFORMED_URI &&
|
||||
!UrlbarPrefs.get("keyword.enabled")
|
||||
) {
|
||||
let result = new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.URL,
|
||||
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
|
||||
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
|
||||
title: [searchUrl, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
url: [searchUrl, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
icon: "",
|
||||
})
|
||||
);
|
||||
result.heuristic = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the URI cannot be fixed or the preferred URI would do a keyword search,
|
||||
// that basically means this isn't useful to us. Note that
|
||||
// fixupInfo.keywordAsSent will never be true if the keyword.enabled pref
|
||||
// is false or there are no engines, so in that case we will always return
|
||||
// a "visit".
|
||||
if (!queryContext.fixupInfo?.href || queryContext.fixupInfo?.isSearch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let uri = new URL(queryContext.fixupInfo.href);
|
||||
// Check the host, as "http:///" is a valid nsIURI, but not useful to us.
|
||||
// But, some schemes are expected to have no host. So we check just against
|
||||
// schemes we know should have a host. This allows new schemes to be
|
||||
// implemented without us accidentally blocking access to them.
|
||||
let hostExpected = ["http:", "https:", "ftp:", "chrome:"].includes(
|
||||
uri.protocol
|
||||
);
|
||||
if (hostExpected && !uri.host) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// getFixupURIInfo() escaped the URI, so it may not be pretty. Embed the
|
||||
// escaped URL in the result since that URL should be "canonical". But
|
||||
// pass the pretty, unescaped URL as the result's title, since it is
|
||||
// displayed to the user.
|
||||
let escapedURL = uri.toString();
|
||||
let displayURL = decodeURI(uri);
|
||||
|
||||
// We don't know if this url is in Places or not, and checking that would
|
||||
// be expensive. Thus we also don't know if we may have an icon.
|
||||
// If we'd just try to fetch the icon for the typed string, we'd cause icon
|
||||
// flicker, since the url keeps changing while the user types.
|
||||
// By default we won't provide an icon, but for the subset of urls with a
|
||||
// host we'll check for a typed slash and set favicon for the host part.
|
||||
let iconUri = "";
|
||||
if (hostExpected && (searchUrl.endsWith("/") || uri.pathname.length > 1)) {
|
||||
// Look for an icon with the entire URL except for the pathname, including
|
||||
// scheme, usernames, passwords, hostname, and port.
|
||||
let pathIndex = uri.toString().lastIndexOf(uri.pathname);
|
||||
let prePath = uri.toString().slice(0, pathIndex);
|
||||
iconUri = `page-icon:${prePath}/`;
|
||||
}
|
||||
|
||||
let result = new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.URL,
|
||||
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
|
||||
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
|
||||
title: [displayURL, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
url: [escapedURL, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
icon: iconUri,
|
||||
})
|
||||
);
|
||||
result.heuristic = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
async _defaultEngineSearchResult(queryContext) {
|
||||
let engine;
|
||||
if (queryContext.engineName) {
|
||||
engine = Services.search.getEngineByName(queryContext.engineName);
|
||||
} else if (queryContext.isPrivate) {
|
||||
engine = Services.search.defaultPrivateEngine;
|
||||
} else {
|
||||
engine = Services.search.defaultEngine;
|
||||
}
|
||||
|
||||
if (!engine) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Strip a leading search restriction char, because we prepend it to text
|
||||
// when the search shortcut is used and it's not user typed. Don't strip
|
||||
// other restriction chars, so that it's possible to search for things
|
||||
// including one of those (e.g. "c#").
|
||||
let query = queryContext.searchString;
|
||||
if (
|
||||
queryContext.tokens[0] &&
|
||||
queryContext.tokens[0].value === UrlbarTokenizer.RESTRICT.SEARCH
|
||||
) {
|
||||
query = UrlbarUtils.substringAfter(
|
||||
query,
|
||||
queryContext.tokens[0].value
|
||||
).trim();
|
||||
}
|
||||
|
||||
let result = new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.SEARCH,
|
||||
UrlbarUtils.RESULT_SOURCE.SEARCH,
|
||||
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
|
||||
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
icon: [engine.iconURI?.spec || ""],
|
||||
query: [query, UrlbarUtils.HIGHLIGHT.NONE],
|
||||
// We're confident that there is no alias, since UnifiedComplete
|
||||
// handles heuristic searches with aliases.
|
||||
keyword: undefined,
|
||||
keywordOffer: UrlbarUtils.KEYWORD_OFFER.NONE,
|
||||
// For test interoperabilty with UrlbarProviderSearchSuggestions.
|
||||
suggestion: undefined,
|
||||
tailPrefix: undefined,
|
||||
tail: undefined,
|
||||
tailOffsetIndex: -1,
|
||||
isSearchHistory: false,
|
||||
})
|
||||
);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
var UrlbarProviderHeuristicFallback = new ProviderHeuristicFallback();
|
|
@ -14,6 +14,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AppUpdater: "resource:///modules/AppUpdater.jsm",
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
NLP: "resource://gre/modules/NLP.jsm",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
ResetProfile: "resource://gre/modules/ResetProfile.jsm",
|
||||
|
@ -24,6 +25,10 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.repository.getLogger("Urlbar.Provider.Interventions")
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "appUpdater", () => new AppUpdater());
|
||||
|
||||
// The possible tips to show. These names (except NONE) are used in the names
|
||||
|
@ -661,6 +666,7 @@ class ProviderInterventions extends UrlbarProvider {
|
|||
* query for.
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
logger.info(`Canceling query for ${queryContext.searchString}`);
|
||||
this.queries.delete(queryContext);
|
||||
|
||||
// If we're waiting for appUpdater to finish its update check,
|
||||
|
|
|
@ -15,6 +15,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
ExtensionSearchHandler: "resource://gre/modules/ExtensionSearchHandler.jsm",
|
||||
SkippableTimer: "resource:///modules/UrlbarUtils.jsm",
|
||||
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
|
||||
|
@ -22,6 +23,10 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.repository.getLogger("Urlbar.Provider.Omnibox")
|
||||
);
|
||||
|
||||
// After this time, we'll give up waiting for the extension to return matches.
|
||||
const MAXIMUM_ALLOWED_EXTENSION_TIME_MS = 3000;
|
||||
|
||||
|
@ -50,7 +55,7 @@ class ProviderOmnibox extends UrlbarProvider {
|
|||
* @returns {integer} one of the types from UrlbarUtils.PROVIDER_TYPE.*
|
||||
*/
|
||||
get type() {
|
||||
return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
|
||||
return UrlbarUtils.PROVIDER_TYPE.EXTENSION;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,28 +116,12 @@ class ProviderOmnibox extends UrlbarProvider {
|
|||
* The callback invoked by this method to add each result.
|
||||
*/
|
||||
async startQuery(queryContext, addCallback) {
|
||||
logger.info(`Starting query for ${queryContext.searchString}`);
|
||||
let instance = {};
|
||||
this.queries.set(queryContext, instance);
|
||||
|
||||
// Fetch heuristic result.
|
||||
let keyword = queryContext.tokens[0].value;
|
||||
let description = ExtensionSearchHandler.getDescription(keyword);
|
||||
let heuristicResult = new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.OMNIBOX,
|
||||
UrlbarUtils.RESULT_SOURCE.OTHER_NETWORK,
|
||||
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
|
||||
title: [description, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
content: [queryContext.searchString, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
keyword: [queryContext.tokens[0].value, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
icon: UrlbarUtils.ICON.EXTENSION,
|
||||
})
|
||||
);
|
||||
heuristicResult.heuristic = true;
|
||||
addCallback(this, heuristicResult);
|
||||
|
||||
// Fetch non-heuristic results.
|
||||
let data = {
|
||||
keyword,
|
||||
keyword: queryContext.tokens[0].value,
|
||||
text: queryContext.searchString,
|
||||
inPrivateWindow: queryContext.isPrivate,
|
||||
};
|
||||
|
@ -141,9 +130,6 @@ class ProviderOmnibox extends UrlbarProvider {
|
|||
suggestions => {
|
||||
for (let suggestion of suggestions) {
|
||||
let content = `${queryContext.tokens[0].value} ${suggestion.content}`;
|
||||
if (content == heuristicResult.payload.content) {
|
||||
continue;
|
||||
}
|
||||
let result = new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.OMNIBOX,
|
||||
UrlbarUtils.RESULT_SOURCE.OTHER_NETWORK,
|
||||
|
@ -167,7 +153,7 @@ class ProviderOmnibox extends UrlbarProvider {
|
|||
let timeoutPromise = new SkippableTimer({
|
||||
name: "ProviderOmnibox",
|
||||
time: MAXIMUM_ALLOWED_EXTENSION_TIME_MS,
|
||||
logger: this.logger,
|
||||
logger,
|
||||
}).promise;
|
||||
await Promise.race([timeoutPromise, this._resultsPromise]).catch(
|
||||
Cu.reportError
|
||||
|
|
|
@ -15,6 +15,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
||||
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
|
||||
UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.jsm",
|
||||
|
@ -22,6 +23,10 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.repository.getLogger("Urlbar.Provider.OpenTabs")
|
||||
);
|
||||
|
||||
/**
|
||||
* Class used to create the provider.
|
||||
*/
|
||||
|
@ -151,6 +156,7 @@ class ProviderOpenTabs extends UrlbarProvider {
|
|||
// temp table to return proper frecency.
|
||||
// TODO:
|
||||
// * properly search and handle tokens, this is just a mock for now.
|
||||
logger.info(`Starting query for ${queryContext.searchString}`);
|
||||
let instance = {};
|
||||
this.queries.set(queryContext, instance);
|
||||
let conn = await this.promiseDb();
|
||||
|
@ -187,6 +193,7 @@ class ProviderOpenTabs extends UrlbarProvider {
|
|||
* @param {object} queryContext The query context object
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
logger.info(`Canceling query for ${queryContext.searchString}`);
|
||||
this.queries.delete(queryContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
SkippableTimer: "resource:///modules/UrlbarUtils.jsm",
|
||||
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
|
||||
|
@ -22,6 +23,10 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.repository.getLogger("Urlbar.Provider.PrivateSearch")
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"separatePrivateDefaultUIEnabled",
|
||||
|
@ -87,6 +92,8 @@ class ProviderPrivateSearch extends UrlbarProvider {
|
|||
* @returns {Promise} resolved when the query stops.
|
||||
*/
|
||||
async startQuery(queryContext, addCallback) {
|
||||
logger.info(`Starting query for ${queryContext.searchString}`);
|
||||
|
||||
let searchString = queryContext.searchString.trim();
|
||||
if (
|
||||
queryContext.tokens.some(
|
||||
|
@ -112,7 +119,7 @@ class ProviderPrivateSearch extends UrlbarProvider {
|
|||
: await Services.search.getDefaultPrivate();
|
||||
let isPrivateEngine =
|
||||
separatePrivateDefault && engine != (await Services.search.getDefault());
|
||||
this.logger.info(`isPrivateEngine: ${isPrivateEngine}`);
|
||||
logger.info(`isPrivateEngine: ${isPrivateEngine}`);
|
||||
|
||||
// This is a delay added before returning results, to avoid flicker.
|
||||
// Our result must appear only when all results are searches, but if search
|
||||
|
@ -121,7 +128,7 @@ class ProviderPrivateSearch extends UrlbarProvider {
|
|||
await new SkippableTimer({
|
||||
name: "ProviderPrivateSearch",
|
||||
time: 100,
|
||||
logger: this.logger,
|
||||
logger,
|
||||
}).promise;
|
||||
|
||||
let result = new UrlbarResult(
|
||||
|
@ -145,6 +152,7 @@ class ProviderPrivateSearch extends UrlbarProvider {
|
|||
* @param {object} queryContext The query context object
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
logger.info(`Canceling query for ${queryContext.searchString}`);
|
||||
this.queries.delete(queryContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
SearchSuggestionController:
|
||||
"resource://gre/modules/SearchSuggestionController.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
|
@ -26,6 +27,10 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.repository.getLogger("Urlbar.Provider.SearchSuggestions")
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns whether the passed in string looks like a url.
|
||||
* @param {string} str
|
||||
|
@ -194,7 +199,10 @@ class ProviderSearchSuggestions extends UrlbarProvider {
|
|||
|
||||
// Disallow remote suggestions for strings containing tokens that look like
|
||||
// URIs, to avoid disclosing information about networks or passwords.
|
||||
if (queryContext.fixupInfo?.href && !queryContext.fixupInfo?.isSearch) {
|
||||
if (
|
||||
queryContext.fixupInfo.fixedURI &&
|
||||
!queryContext.fixupInfo.keywordAsSent
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -210,6 +218,7 @@ class ProviderSearchSuggestions extends UrlbarProvider {
|
|||
* @returns {Promise} resolved when the query stops.
|
||||
*/
|
||||
async startQuery(queryContext, addCallback) {
|
||||
logger.info(`Starting query for ${queryContext.searchString}`);
|
||||
let instance = {};
|
||||
this.queries.set(queryContext, instance);
|
||||
|
||||
|
@ -321,6 +330,8 @@ class ProviderSearchSuggestions extends UrlbarProvider {
|
|||
* @param {object} queryContext The query context object
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
logger.info(`Canceling query for ${queryContext.searchString}`);
|
||||
|
||||
if (this._suggestionsController) {
|
||||
this._suggestionsController.stop();
|
||||
this._suggestionsController = null;
|
||||
|
@ -426,7 +437,7 @@ class ProviderSearchSuggestions extends UrlbarProvider {
|
|||
let tailTimer = new SkippableTimer({
|
||||
name: "ProviderSearchSuggestions",
|
||||
time: 100,
|
||||
logger: this.logger,
|
||||
logger,
|
||||
});
|
||||
|
||||
for (let entry of fetchData.remote) {
|
||||
|
|
|
@ -19,6 +19,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.jsm",
|
||||
DefaultBrowserCheck: "resource:///modules/BrowserGlue.jsm",
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
ProfileAge: "resource://gre/modules/ProfileAge.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
setTimeout: "resource://gre/modules/Timer.jsm",
|
||||
|
@ -29,6 +30,10 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.repository.getLogger("Urlbar.Provider.SearchTips")
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"updateManager",
|
||||
|
@ -225,6 +230,7 @@ class ProviderSearchTips extends UrlbarProvider {
|
|||
* query for.
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
logger.info(`Canceling query for ${queryContext.searchString}`);
|
||||
this.queries.delete(queryContext);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,17 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
|
||||
UrlbarResult: "resource:///modules/UrlbarResult.jsm",
|
||||
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.jsm",
|
||||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.repository.getLogger("Urlbar.Provider.TokenAliasEngines")
|
||||
);
|
||||
|
||||
/**
|
||||
* Class used to create the provider.
|
||||
*/
|
||||
|
@ -75,6 +80,7 @@ class ProviderTokenAliasEngines extends UrlbarProvider {
|
|||
* result.
|
||||
*/
|
||||
async startQuery(queryContext, addCallback) {
|
||||
logger.info(`Starting query for ${queryContext.searchString}`);
|
||||
let instance = {};
|
||||
this.queries.set(queryContext, instance);
|
||||
|
||||
|
@ -121,6 +127,7 @@ class ProviderTokenAliasEngines extends UrlbarProvider {
|
|||
* @param {object} queryContext The query context object
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
logger.info(`Canceling query for ${queryContext.searchString}`);
|
||||
this.queries.delete(queryContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AboutNewTab: "resource:///modules/AboutNewTab.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
|
||||
|
@ -24,6 +25,10 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
TOP_SITES_DEFAULT_ROWS: "resource://activity-stream/common/Reducers.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.repository.getLogger("Urlbar.Provider.TopSites")
|
||||
);
|
||||
|
||||
/**
|
||||
* This module exports a provider returning the user's newtab Top Sites.
|
||||
*/
|
||||
|
@ -242,6 +247,7 @@ class ProviderTopSites extends UrlbarProvider {
|
|||
* query for.
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
logger.info(`Canceling query for ${queryContext.searchString}`);
|
||||
this.queries.delete(queryContext);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
|
||||
|
@ -30,6 +31,10 @@ XPCOMUtils.defineLazyServiceGetter(
|
|||
"nsIAutoCompleteSearch"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
Log.repository.getLogger("Urlbar.Provider.UnifiedComplete")
|
||||
);
|
||||
|
||||
/**
|
||||
* Class used to create the provider.
|
||||
*/
|
||||
|
@ -75,6 +80,7 @@ class ProviderUnifiedComplete extends UrlbarProvider {
|
|||
* @returns {Promise} resolved when the query stops.
|
||||
*/
|
||||
async startQuery(queryContext, addCallback) {
|
||||
logger.info(`Starting query for ${queryContext.searchString}`);
|
||||
let instance = {};
|
||||
this.queries.set(queryContext, instance);
|
||||
let urls = new Set();
|
||||
|
@ -84,17 +90,8 @@ class ProviderUnifiedComplete extends UrlbarProvider {
|
|||
acResult,
|
||||
urls
|
||||
);
|
||||
// The Muxer gives UnifiedComplete special status and waits for it to
|
||||
// return results before sorting them. We need to know that
|
||||
// UnifiedComplete has finished even if it isn't returning results, so we
|
||||
// call addCallback with an empty result here, which is something only
|
||||
// UnifiedComplete is allowed to do.
|
||||
if (!results.length) {
|
||||
addCallback(this, null);
|
||||
} else {
|
||||
for (let result of results) {
|
||||
addCallback(this, result);
|
||||
}
|
||||
for (let result of results) {
|
||||
addCallback(this, result);
|
||||
}
|
||||
});
|
||||
this.queries.delete(queryContext);
|
||||
|
@ -105,6 +102,7 @@ class ProviderUnifiedComplete extends UrlbarProvider {
|
|||
* @param {object} queryContext The query context object
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
logger.info(`Canceling query for ${queryContext.searchString}`);
|
||||
// This doesn't properly support being used concurrently by multiple fields.
|
||||
this.queries.delete(queryContext);
|
||||
unifiedComplete.stopSearch();
|
||||
|
@ -256,6 +254,17 @@ function makeUrlbarResult(tokens, info) {
|
|||
})
|
||||
);
|
||||
}
|
||||
case "extension":
|
||||
return new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.OMNIBOX,
|
||||
UrlbarUtils.RESULT_SOURCE.OTHER_NETWORK,
|
||||
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
|
||||
title: [info.comment, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
content: [action.params.content, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
keyword: [action.params.keyword, UrlbarUtils.HIGHLIGHT.TYPED],
|
||||
icon: [info.icon],
|
||||
})
|
||||
);
|
||||
case "remotetab":
|
||||
return new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.REMOTE_TAB,
|
||||
|
|
|
@ -15,6 +15,7 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
||||
SkippableTimer: "resource:///modules/UrlbarUtils.jsm",
|
||||
UrlbarMuxer: "resource:///modules/UrlbarUtils.jsm",
|
||||
|
@ -26,7 +27,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
UrlbarUtils.getLogger({ prefix: "ProvidersManager" })
|
||||
Log.repository.getLogger("Urlbar.ProvidersManager")
|
||||
);
|
||||
|
||||
// List of available local providers, each is implemented in its own jsm module
|
||||
|
@ -34,8 +35,6 @@ XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
|||
var localProviderModules = {
|
||||
UrlbarProviderUnifiedComplete:
|
||||
"resource:///modules/UrlbarProviderUnifiedComplete.jsm",
|
||||
UrlbarProviderHeuristicFallback:
|
||||
"resource:///modules/UrlbarProviderHeuristicFallback.jsm",
|
||||
UrlbarProviderInterventions:
|
||||
"resource:///modules/UrlbarProviderInterventions.jsm",
|
||||
UrlbarProviderOmnibox: "resource:///modules/UrlbarProviderOmnibox.jsm",
|
||||
|
@ -233,7 +232,7 @@ class ProvidersManager {
|
|||
* @param {object} queryContext
|
||||
*/
|
||||
cancelQuery(queryContext) {
|
||||
logger.info(`Query cancel "${queryContext.searchString}"`);
|
||||
logger.info(`Query cancel ${queryContext.searchString}`);
|
||||
let query = this.queries.get(queryContext);
|
||||
if (!query) {
|
||||
throw new Error("Couldn't find a matching query for the given context");
|
||||
|
@ -362,21 +361,12 @@ class Query {
|
|||
}
|
||||
|
||||
// Start querying active providers.
|
||||
|
||||
let queryPromises = [];
|
||||
let startQuery = provider => {
|
||||
provider.logger.info(`Starting query for "${this.context.searchString}"`);
|
||||
return provider.tryMethod(
|
||||
"startQuery",
|
||||
this.context,
|
||||
this.add.bind(this)
|
||||
);
|
||||
};
|
||||
|
||||
for (let provider of activeProviders) {
|
||||
if (provider.type == UrlbarUtils.PROVIDER_TYPE.HEURISTIC) {
|
||||
this.context.pendingHeuristicProviders.add(provider.name);
|
||||
queryPromises.push(startQuery(provider));
|
||||
queryPromises.push(
|
||||
provider.tryMethod("startQuery", this.context, this.add.bind(this))
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (!this._sleepTimer) {
|
||||
|
@ -386,13 +376,20 @@ class Query {
|
|||
this._sleepTimer = new SkippableTimer({
|
||||
name: "Query provider timer",
|
||||
time: UrlbarPrefs.get("delay"),
|
||||
logger: provider.logger,
|
||||
logger,
|
||||
});
|
||||
}
|
||||
queryPromises.push(
|
||||
this._sleepTimer.promise.then(() =>
|
||||
this.canceled ? undefined : startQuery(provider)
|
||||
)
|
||||
this._sleepTimer.promise.then(() => {
|
||||
if (this.canceled) {
|
||||
return undefined;
|
||||
}
|
||||
return provider.tryMethod(
|
||||
"startQuery",
|
||||
this.context,
|
||||
this.add.bind(this)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -418,9 +415,6 @@ class Query {
|
|||
}
|
||||
this.canceled = true;
|
||||
for (let provider of this.providers) {
|
||||
provider.logger.info(
|
||||
`Canceling query for "${this.context.searchString}"`
|
||||
);
|
||||
provider.tryMethod("cancelQuery", this.context);
|
||||
}
|
||||
if (this._chunkTimer) {
|
||||
|
@ -440,29 +434,13 @@ class Query {
|
|||
if (!(provider instanceof UrlbarProvider)) {
|
||||
throw new Error("Invalid provider passed to the add callback");
|
||||
}
|
||||
|
||||
// When this set is empty, we can display heuristic results early. We remove
|
||||
// the provider from the list without checking result.heuristic since
|
||||
// heuristic providers don't necessarily have to return heuristic results.
|
||||
// We expect a provider with type HEURISTIC will return its heuristic
|
||||
// result(s) first.
|
||||
this.context.pendingHeuristicProviders.delete(provider.name);
|
||||
|
||||
// Stop returning results as soon as we've been canceled.
|
||||
if (this.canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let addResult = true;
|
||||
|
||||
if (!result) {
|
||||
addResult = false;
|
||||
}
|
||||
|
||||
// Check if the result source should be filtered out. Pay attention to the
|
||||
// heuristic result though, that is supposed to be added regardless.
|
||||
if (
|
||||
addResult &&
|
||||
!this.acceptableSources.includes(result.source) &&
|
||||
!result.heuristic &&
|
||||
// Treat form history as searches for the purpose of acceptableSources.
|
||||
|
@ -470,95 +448,53 @@ class Query {
|
|||
result.source != UrlbarUtils.RESULT_SOURCE.HISTORY ||
|
||||
!this.acceptableSources.includes(UrlbarUtils.RESULT_SOURCE.SEARCH))
|
||||
) {
|
||||
addResult = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter out javascript results for safety. The provider is supposed to do
|
||||
// it, but we don't want to risk leaking these out.
|
||||
if (
|
||||
addResult &&
|
||||
result.type != UrlbarUtils.RESULT_TYPE.KEYWORD &&
|
||||
result.payload.url &&
|
||||
result.payload.url.startsWith("javascript:") &&
|
||||
!this.context.searchString.startsWith("javascript:") &&
|
||||
UrlbarPrefs.get("filter.javascript")
|
||||
) {
|
||||
addResult = false;
|
||||
}
|
||||
|
||||
// We wait on UnifiedComplete to return a heuristic result. If it has no
|
||||
// heuristic result to return, we still need to sort and display results, so
|
||||
// we follow the usual codepath to muxer.sort. We only offer this for
|
||||
// UnifiedComplete, so we check the provider's name here. This is a stopgap
|
||||
// measure until bug 1648468 lands.
|
||||
if (!addResult) {
|
||||
if (provider.name == "UnifiedComplete") {
|
||||
this._notifyResultsFromProvider(provider);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
result.providerName = provider.name;
|
||||
result.providerType = provider.type;
|
||||
this.context.results.push(result);
|
||||
if (result.heuristic) {
|
||||
this.context.allHeuristicResults.push(result);
|
||||
this.context.heuristicResult = result;
|
||||
}
|
||||
|
||||
this._notifyResultsFromProvider(provider);
|
||||
}
|
||||
|
||||
_notifyResultsFromProvider(provider) {
|
||||
// We create two chunking timers: one for heuristic results, and one for
|
||||
// other results. We expect heuristic providers to return their heuristic
|
||||
// results before other results/providers in most cases. When all heuristic
|
||||
// providers have returned some results, we fire the heuristic timer early.
|
||||
// If the timer fires first, we stop waiting on the remaining heuristic
|
||||
// providers.
|
||||
// Both timers are used to reduce UI flicker.
|
||||
// If the provider is not of heuristic type, chunk results, to improve the
|
||||
// dataflow and reduce UI flicker.
|
||||
if (provider.type == UrlbarUtils.PROVIDER_TYPE.HEURISTIC) {
|
||||
if (!this._heuristicProviderTimer) {
|
||||
this._heuristicProviderTimer = new SkippableTimer({
|
||||
name: "Heuristic provider timer",
|
||||
callback: () => this._notifyResults(),
|
||||
time: CHUNK_RESULTS_DELAY_MS,
|
||||
logger: provider.logger,
|
||||
});
|
||||
}
|
||||
this._notifyResults();
|
||||
} else if (!this._chunkTimer) {
|
||||
this._chunkTimer = new SkippableTimer({
|
||||
name: "Query chunk timer",
|
||||
callback: () => this._notifyResults(),
|
||||
time: CHUNK_RESULTS_DELAY_MS,
|
||||
logger: provider.logger,
|
||||
logger,
|
||||
});
|
||||
}
|
||||
// If all active heuristic providers have returned results, we can skip the
|
||||
// heuristic results timer and start showing results immediately.
|
||||
if (
|
||||
this._heuristicProviderTimer &&
|
||||
!this.context.pendingHeuristicProviders.size
|
||||
) {
|
||||
this._heuristicProviderTimer.fire().catch(Cu.reportError);
|
||||
}
|
||||
}
|
||||
|
||||
_notifyResults() {
|
||||
let sorted = this.muxer.sort(this.context);
|
||||
|
||||
if (this._heuristicProviderTimer) {
|
||||
this._heuristicProviderTimer.cancel().catch(Cu.reportError);
|
||||
this._heuristicProviderTimer = null;
|
||||
}
|
||||
this.muxer.sort(this.context);
|
||||
|
||||
if (this._chunkTimer) {
|
||||
this._chunkTimer.cancel().catch(Cu.reportError);
|
||||
this._chunkTimer = null;
|
||||
}
|
||||
|
||||
if (!sorted) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Before the muxer.sort call above, this.context.results should never be
|
||||
// empty since this method is called when results are added. But the muxer
|
||||
// may have excluded one or more results from the final sorted list. For
|
||||
|
@ -573,13 +509,13 @@ class Query {
|
|||
|
||||
// Crop results to the requested number, taking their result spans into
|
||||
// account.
|
||||
logger.debug(
|
||||
`Cropping ${this.context.results.length} results to ${this.context.maxResults}`
|
||||
);
|
||||
let resultCount = this.context.maxResults;
|
||||
for (let i = 0; i < this.context.results.length; i++) {
|
||||
resultCount -= UrlbarUtils.getSpanForResult(this.context.results[i]);
|
||||
if (resultCount < 0) {
|
||||
logger.debug(
|
||||
`Splicing results from ${i} to crop results to ${this.context.maxResults}`
|
||||
);
|
||||
this.context.results.splice(i, this.context.results.length - i);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -15,13 +15,11 @@ var EXPORTED_SYMBOLS = ["UrlbarTokenizer"];
|
|||
const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Services: "resource://gre/modules/Services.jsm",
|
||||
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
||||
});
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Log", "resource://gre/modules/Log.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
UrlbarUtils.getLogger({ prefix: "Tokenizer" })
|
||||
Log.repository.getLogger("Urlbar.Tokenizer")
|
||||
);
|
||||
|
||||
var UrlbarTokenizer = {
|
||||
|
|
|
@ -23,7 +23,6 @@ const { XPCOMUtils } = ChromeUtils.import(
|
|||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
Log: "resource://gre/modules/Log.jsm",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
PlacesUIUtils: "resource:///modules/PlacesUIUtils.jsm",
|
||||
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
||||
|
@ -608,28 +607,6 @@ var UrlbarUtils = {
|
|||
return index < 0 ? "" : sourceStr.substr(index + targetStr.length);
|
||||
},
|
||||
|
||||
/**
|
||||
* Strips the prefix from a URL and returns the prefix and the remainder of the
|
||||
* URL. "Prefix" is defined to be the scheme and colon, plus, if present, two
|
||||
* slashes. If the given string is not actually a URL, then an empty prefix and
|
||||
* the string itself is returned.
|
||||
*
|
||||
* @param {string} str The possible URL to strip.
|
||||
* @returns {array} If `str` is a URL, then [prefix, remainder]. Otherwise, ["", str].
|
||||
*/
|
||||
stripURLPrefix(str) {
|
||||
const REGEXP_STRIP_PREFIX = /^[a-z]+:(?:\/){0,2}/i;
|
||||
let match = REGEXP_STRIP_PREFIX.exec(str);
|
||||
if (!match) {
|
||||
return ["", str];
|
||||
}
|
||||
let prefix = match[0];
|
||||
if (prefix.length < str.length && str[prefix.length] == " ") {
|
||||
return ["", str];
|
||||
}
|
||||
return [prefix, str.substr(prefix.length)];
|
||||
},
|
||||
|
||||
/**
|
||||
* Runs a search for the given string, and returns the heuristic result.
|
||||
* @param {string} searchString The string to search for.
|
||||
|
@ -652,7 +629,7 @@ var UrlbarUtils = {
|
|||
"usercontextid"
|
||||
),
|
||||
allowSearchSuggestions: false,
|
||||
providers: ["UnifiedComplete", "HeuristicFallback"],
|
||||
providers: ["UnifiedComplete"],
|
||||
});
|
||||
await UrlbarProvidersManager.startQuery(context);
|
||||
if (!context.heuristicResult) {
|
||||
|
@ -660,30 +637,6 @@ var UrlbarUtils = {
|
|||
}
|
||||
return context.heuristicResult;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a logger.
|
||||
* Logging level can be controlled through browser.urlbar.loglevel.
|
||||
* @param {string} [prefix] Prefix to use for the logged messages, "::" will
|
||||
* be appended automatically to the prefix.
|
||||
* @returns {object} The logger.
|
||||
*/
|
||||
getLogger({ prefix = "" } = {}) {
|
||||
if (!this._logger) {
|
||||
this._logger = Log.repository.getLogger("urlbar");
|
||||
this._logger.manageLevelFromPref("browser.urlbar.loglevel");
|
||||
this._logger.addAppender(
|
||||
new Log.ConsoleAppender(new Log.BasicFormatter())
|
||||
);
|
||||
}
|
||||
if (prefix) {
|
||||
// This is not an early return because it is necessary to invoke getLogger
|
||||
// at least once before getLoggerWithMessagePrefix; it replaces a
|
||||
// method of the original logger, rather than using an actual Proxy.
|
||||
return Log.repository.getLoggerWithMessagePrefix("urlbar", prefix + "::");
|
||||
}
|
||||
return this._logger;
|
||||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(UrlbarUtils.ICON, "DEFAULT", () => {
|
||||
|
@ -1025,8 +978,6 @@ class UrlbarQueryContext {
|
|||
}
|
||||
|
||||
this.lastResultCount = 0;
|
||||
this.allHeuristicResults = [];
|
||||
this.pendingHeuristicProviders = new Set();
|
||||
this.userContextId =
|
||||
options.userContextId ||
|
||||
Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID;
|
||||
|
@ -1052,12 +1003,9 @@ class UrlbarQueryContext {
|
|||
|
||||
/**
|
||||
* Caches and returns fixup info from URIFixup for the current search string.
|
||||
* Only returns a subset of the properties from URIFixup. This is both to
|
||||
* reduce the memory footprint of UrlbarQueryContexts and to keep them
|
||||
* serializable so they can be sent to extensions.
|
||||
*/
|
||||
get fixupInfo() {
|
||||
if (this.searchString.trim() && !this._fixupInfo) {
|
||||
if (this.searchString && !this._fixupInfo) {
|
||||
let flags =
|
||||
Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
|
||||
Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
|
||||
|
@ -1065,35 +1013,14 @@ class UrlbarQueryContext {
|
|||
flags |= Ci.nsIURIFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
|
||||
}
|
||||
|
||||
try {
|
||||
let info = Services.uriFixup.getFixupURIInfo(
|
||||
this.searchString.trim(),
|
||||
flags
|
||||
);
|
||||
this._fixupInfo = {
|
||||
href: info.fixedURI.spec,
|
||||
isSearch: !!info.keywordAsSent,
|
||||
};
|
||||
} catch (ex) {
|
||||
this._fixupError = ex.result;
|
||||
}
|
||||
this._fixupInfo = Services.uriFixup.getFixupURIInfo(
|
||||
this.searchString.trim(),
|
||||
flags
|
||||
);
|
||||
}
|
||||
|
||||
return this._fixupInfo || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error that was thrown when fixupInfo was fetched, if any. If
|
||||
* fixupInfo has not yet been fetched for this queryContext, it is fetched
|
||||
* here.
|
||||
*/
|
||||
get fixupError() {
|
||||
if (!this.fixupInfo) {
|
||||
return this._fixupError;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1125,12 +1052,6 @@ class UrlbarMuxer {
|
|||
* The provider scope is to query a datasource and return results from it.
|
||||
*/
|
||||
class UrlbarProvider {
|
||||
constructor() {
|
||||
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
||||
UrlbarUtils.getLogger({ prefix: `Provider.${this.name}` })
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unique name for the provider, used by the context to filter on providers.
|
||||
* Not using a unique name will cause the newest registration to win.
|
||||
|
|
|
@ -12,7 +12,6 @@ EXTRA_JS_MODULES += [
|
|||
'UrlbarMuxerUnifiedComplete.jsm',
|
||||
'UrlbarPrefs.jsm',
|
||||
'UrlbarProviderExtension.jsm',
|
||||
'UrlbarProviderHeuristicFallback.jsm',
|
||||
'UrlbarProviderInterventions.jsm',
|
||||
'UrlbarProviderOmnibox.jsm',
|
||||
'UrlbarProviderOpenTabs.jsm',
|
||||
|
|
|
@ -598,7 +598,7 @@ class TestProvider extends UrlbarProvider {
|
|||
*/
|
||||
constructor({
|
||||
results,
|
||||
name = Math.floor(Math.random() * 100000),
|
||||
name = "TestProvider" + Math.floor(Math.random() * 100000),
|
||||
type = UrlbarUtils.PROVIDER_TYPE.PROFILE,
|
||||
priority = 0,
|
||||
addTimeout = 0,
|
||||
|
@ -613,7 +613,7 @@ class TestProvider extends UrlbarProvider {
|
|||
this._onCancel = onCancel;
|
||||
}
|
||||
get name() {
|
||||
return "TestProvider" + this._name;
|
||||
return this._name;
|
||||
}
|
||||
get type() {
|
||||
return this._type;
|
||||
|
|
|
@ -21,19 +21,19 @@ add_task(async function urlToTip() {
|
|||
]);
|
||||
|
||||
// Add a provider that returns a tip result when the search string is "testx".
|
||||
let tipResult = new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.TIP,
|
||||
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
|
||||
{
|
||||
text: "This is a test tip.",
|
||||
buttonText: "OK",
|
||||
helpUrl: "http://example.com/",
|
||||
type: "test",
|
||||
}
|
||||
);
|
||||
tipResult.suggestedIndex = 1;
|
||||
let provider = new UrlbarTestUtils.TestProvider({
|
||||
results: [tipResult],
|
||||
results: [
|
||||
new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.TIP,
|
||||
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
|
||||
{
|
||||
text: "This is a test tip.",
|
||||
buttonText: "OK",
|
||||
helpUrl: "http://example.com/",
|
||||
type: "test",
|
||||
}
|
||||
),
|
||||
],
|
||||
});
|
||||
provider.isActive = context => context.searchString == "testx";
|
||||
UrlbarProvidersManager.registerProvider(provider);
|
||||
|
@ -122,19 +122,19 @@ add_task(async function tipToURL() {
|
|||
|
||||
// Add a provider that returns a tip result when the search string is "test"
|
||||
// or "testxx".
|
||||
let tipResult = new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.TIP,
|
||||
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
|
||||
{
|
||||
text: "This is a test tip.",
|
||||
buttonText: "OK",
|
||||
helpUrl: "http://example.com/",
|
||||
type: "test",
|
||||
}
|
||||
);
|
||||
tipResult.suggestedIndex = 1;
|
||||
let provider = new UrlbarTestUtils.TestProvider({
|
||||
results: [tipResult],
|
||||
results: [
|
||||
new UrlbarResult(
|
||||
UrlbarUtils.RESULT_TYPE.TIP,
|
||||
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
|
||||
{
|
||||
text: "This is a test tip.",
|
||||
buttonText: "OK",
|
||||
helpUrl: "http://example.com/",
|
||||
type: "test",
|
||||
}
|
||||
),
|
||||
],
|
||||
});
|
||||
provider.isActive = context =>
|
||||
["test", "testxx"].includes(context.searchString);
|
||||
|
|
|
@ -1,536 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that visit-url and search engine heuristic results are returned by
|
||||
* UrlbarProviderHeuristicFallback.
|
||||
*/
|
||||
|
||||
const ENGINE_NAME = "engine-suggestions.xml";
|
||||
const SUGGEST_PREF = "browser.urlbar.suggest.searches";
|
||||
const SUGGEST_ENABLED_PREF = "browser.search.suggest.enabled";
|
||||
const PRIVATE_SEARCH_PREF = "browser.search.separatePrivateDefault.ui.enabled";
|
||||
|
||||
add_task(async function setup() {
|
||||
// Install a test engine so we're sure of ENGINE_NAME.
|
||||
let engine = await addTestSuggestionsEngine();
|
||||
|
||||
// Install the test engine.
|
||||
let oldDefaultEngine = await Services.search.getDefault();
|
||||
registerCleanupFunction(async () => {
|
||||
Services.search.setDefault(oldDefaultEngine);
|
||||
Services.prefs.clearUserPref(SUGGEST_PREF);
|
||||
Services.prefs.clearUserPref(SUGGEST_ENABLED_PREF);
|
||||
Services.prefs.clearUserPref(PRIVATE_SEARCH_PREF);
|
||||
});
|
||||
Services.search.setDefault(engine);
|
||||
Services.prefs.setBoolPref(SUGGEST_PREF, false);
|
||||
Services.prefs.setBoolPref(SUGGEST_ENABLED_PREF, false);
|
||||
Services.prefs.setBoolPref(PRIVATE_SEARCH_PREF, false);
|
||||
});
|
||||
|
||||
add_task(async function() {
|
||||
info("visit url, no protocol");
|
||||
let query = "mozilla.org";
|
||||
let context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}/`,
|
||||
title: `http://${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, no protocol but with 2 dots");
|
||||
query = "www.mozilla.org";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}/`,
|
||||
title: `http://${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, no protocol, e-mail like");
|
||||
query = "a@b.com";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}/`,
|
||||
title: `http://${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, with protocol but with 2 dots");
|
||||
query = "https://www.mozilla.org";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `${query}/`,
|
||||
title: `${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// info("visit url, with protocol but with 3 dots");
|
||||
query = "https://www.mozilla.org.tw";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `${query}/`,
|
||||
title: `${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, with protocol");
|
||||
query = "https://mozilla.org";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `${query}/`,
|
||||
title: `${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, about: protocol (no host)");
|
||||
query = "about:nonexistent";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: query,
|
||||
title: query,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, with non-standard whitespace");
|
||||
query = "https://mozilla.org";
|
||||
context = createContext(`${query}\u2028`, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `${query}/`,
|
||||
title: `${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// This is distinct because of how we predict being able to url autofill via
|
||||
// host lookups.
|
||||
info("visit url, host matching visited host but not visited url");
|
||||
await PlacesTestUtils.addVisits([
|
||||
{
|
||||
uri: Services.io.newURI("http://mozilla.org/wine/"),
|
||||
title: "Mozilla Wine",
|
||||
transition: PlacesUtils.history.TRANSITION_TYPED,
|
||||
},
|
||||
]);
|
||||
query = "mozilla.org/rum";
|
||||
context = createContext(`${query}\u2028`, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}`,
|
||||
title: `http://${query}`,
|
||||
iconUri: "page-icon:http://mozilla.org/",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
await PlacesUtils.history.clear();
|
||||
|
||||
// And hosts with no dot in them are special, due to requiring safelisting.
|
||||
info("unknown host");
|
||||
query = "firefox";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("string with known host");
|
||||
Services.prefs.setBoolPref("browser.fixup.defaultToSearch", true);
|
||||
query = "firefox/get";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref("browser.fixup.defaultToSearch", false);
|
||||
query = "firefox/get";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}`,
|
||||
title: `http://${query}`,
|
||||
iconUri: "page-icon:http://firefox/",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
Services.prefs.clearUserPref("browser.fixup.defaultToSearch");
|
||||
|
||||
Services.prefs.setBoolPref("browser.fixup.domainwhitelist.firefox", true);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("browser.fixup.domainwhitelist.firefox");
|
||||
});
|
||||
|
||||
info("known host");
|
||||
query = "firefox";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}/`,
|
||||
title: `http://${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("url with known host");
|
||||
query = "firefox/get";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}`,
|
||||
title: `http://${query}`,
|
||||
iconUri: "page-icon:http://firefox/",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, host matching visited host but not visited url, known host");
|
||||
Services.prefs.setBoolPref("browser.fixup.domainwhitelist.mozilla", true);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("browser.fixup.domainwhitelist.mozilla");
|
||||
});
|
||||
query = "mozilla/rum";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}`,
|
||||
title: `http://${query}`,
|
||||
iconUri: "page-icon:http://mozilla/",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// ipv4 and ipv6 literal addresses should offer to visit.
|
||||
info("visit url, ipv4 literal");
|
||||
query = "127.0.0.1";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}/`,
|
||||
title: `http://${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, ipv6 literal");
|
||||
query = "[2001:db8::1]";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}/`,
|
||||
title: `http://${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// Setting keyword.enabled to false should always try to visit.
|
||||
let keywordEnabled = Services.prefs.getBoolPref("keyword.enabled");
|
||||
Services.prefs.setBoolPref("keyword.enabled", false);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("keyword.enabled");
|
||||
});
|
||||
info("visit url, keyword.enabled = false");
|
||||
query = "bacon";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}/`,
|
||||
title: `http://${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit two word query, keyword.enabled = false");
|
||||
query = "bacon lovers";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: query,
|
||||
title: query,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
Services.prefs.setBoolPref("keyword.enabled", true);
|
||||
info("visit two word query, keyword.enabled = true");
|
||||
query = "bacon lovers";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref("keyword.enabled", keywordEnabled);
|
||||
|
||||
info("visit url, scheme+host");
|
||||
query = "http://example";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `${query}/`,
|
||||
title: `${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, scheme+host");
|
||||
query = "ftp://example";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `${query}/`,
|
||||
title: `${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, host+port");
|
||||
query = "example:8080";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: `http://${query}/`,
|
||||
title: `http://${query}/`,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("numerical operations that look like urls should search");
|
||||
query = "123/12";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("numerical operations that look like urls should search");
|
||||
query = "123.12/12.1";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
query = "resource:///modules";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: query,
|
||||
title: query,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("access resource://app/modules");
|
||||
query = "resource://app/modules";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeVisitResult(context, {
|
||||
uri: query,
|
||||
title: query,
|
||||
iconUri: "",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("protocol with an extra slash");
|
||||
query = "http:///";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("change default engine");
|
||||
let originalTestEngine = Services.search.getEngineByName(ENGINE_NAME);
|
||||
let engine2 = await Services.search.addEngineWithDetails("AliasEngine", {
|
||||
alias: "alias",
|
||||
method: "GET",
|
||||
template: "http://example.com/?q={searchTerms}",
|
||||
});
|
||||
Assert.notEqual(
|
||||
Services.search.defaultEngine,
|
||||
engine2,
|
||||
"New engine shouldn't be the current engine yet"
|
||||
);
|
||||
await Services.search.setDefault(engine2);
|
||||
query = "toronto";
|
||||
context = createContext(query, { isPrivate: false });
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeSearchResult(context, {
|
||||
engineName: "AliasEngine",
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
await Services.search.setDefault(originalTestEngine);
|
||||
|
||||
info(
|
||||
"Leading restriction tokens are not removed from the search result, apart from the search token."
|
||||
);
|
||||
// Note that we use the alias from AliasEngine in the query. Since we're using
|
||||
// a restriction token, we expect that the default engine be used.
|
||||
for (let token of Object.values(UrlbarTokenizer.RESTRICT)) {
|
||||
for (query of [`${token} alias query`, `query ${token}`]) {
|
||||
let expectedQuery =
|
||||
token == UrlbarTokenizer.RESTRICT.SEARCH &&
|
||||
query.startsWith(UrlbarTokenizer.RESTRICT.SEARCH)
|
||||
? query.substring(2)
|
||||
: query;
|
||||
context = createContext(query, { isPrivate: false });
|
||||
info(`Searching for "${query}", expecting "${expectedQuery}"`);
|
||||
await check_results({
|
||||
context,
|
||||
matches: [
|
||||
makeSearchResult(context, {
|
||||
engineName: ENGINE_NAME,
|
||||
query: expectedQuery,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
await Services.search.removeEngine(engine2);
|
||||
});
|
|
@ -359,16 +359,30 @@ add_task(async function test_filter_priority() {
|
|||
/**
|
||||
* A test provider.
|
||||
*/
|
||||
class TestProvider extends UrlbarTestUtils.TestProvider {
|
||||
class TestProvider extends UrlbarProvider {
|
||||
constructor(priority, shouldBeInvoked, namePart = "") {
|
||||
super();
|
||||
this._priority = priority;
|
||||
this._name = `${priority}` + namePart;
|
||||
this._name = `Provider-${priority}` + namePart;
|
||||
this._shouldBeInvoked = shouldBeInvoked;
|
||||
}
|
||||
get name() {
|
||||
return this._name;
|
||||
}
|
||||
get type() {
|
||||
return UrlbarUtils.PROVIDER_TYPE.PROFILE;
|
||||
}
|
||||
isActive(context) {
|
||||
return true;
|
||||
}
|
||||
getPriority(context) {
|
||||
return this._priority;
|
||||
}
|
||||
async startQuery(context, add) {
|
||||
Assert.ok(this._shouldBeInvoked, `${this.name} was invoked`);
|
||||
}
|
||||
cancelQuery(context) {}
|
||||
pickResult(result) {}
|
||||
}
|
||||
|
||||
// Test all possible orderings of the providers to make sure the logic that
|
||||
|
|
|
@ -6,7 +6,6 @@ support-files =
|
|||
data/engine-tail-suggestions.xml
|
||||
|
||||
[test_muxer.js]
|
||||
[test_providerHeuristicFallback.js]
|
||||
[test_providerOmnibox.js]
|
||||
[test_providerOpenTabs.js]
|
||||
[test_providersManager.js]
|
||||
|
|
|
@ -122,7 +122,7 @@ class TipProvider extends UrlbarProvider {
|
|||
this._results = results;
|
||||
}
|
||||
get name() {
|
||||
return "TestProviderTip";
|
||||
return "TestTipProvider";
|
||||
}
|
||||
get type() {
|
||||
return UrlbarUtils.PROVIDER_TYPE.PROFILE;
|
||||
|
|
|
@ -340,6 +340,7 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
|||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AboutPagesUtils: "resource://gre/modules/AboutPagesUtils.jsm",
|
||||
BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
|
||||
ExtensionSearchHandler: "resource://gre/modules/ExtensionSearchHandler.jsm",
|
||||
ObjectUtils: "resource://gre/modules/ObjectUtils.jsm",
|
||||
PlacesRemoteTabsAutocompleteProvider:
|
||||
"resource://gre/modules/PlacesRemoteTabsAutocompleteProvider.jsm",
|
||||
|
@ -759,9 +760,9 @@ function Search(
|
|||
// 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. It may be a Places
|
||||
// keyword, a search engine alias, or simply a URL or part of the search
|
||||
// string the user has typed. We won't know until we create the heuristic
|
||||
// result.
|
||||
// keyword, a search engine alias, an extension keyword, or simply a URL or
|
||||
// part of the search string the user has typed. We won't know until we
|
||||
// create the heuristic result.
|
||||
let firstToken = !!this._searchTokens.length && this._searchTokens[0].value;
|
||||
this._heuristicToken =
|
||||
firstToken && this._trimmedOriginalSearchString.startsWith(firstToken)
|
||||
|
@ -1271,6 +1272,16 @@ Search.prototype = {
|
|||
// We always try to make the first result a special "heuristic" result. The
|
||||
// heuristics below determine what type of result it will be, if any.
|
||||
|
||||
if (this._heuristicToken) {
|
||||
// It may be a keyword registered by an extension.
|
||||
let matched = await this._matchExtensionHeuristicResult(
|
||||
this._heuristicToken
|
||||
);
|
||||
if (matched) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pending && this._enableActions && this._heuristicToken) {
|
||||
// It may be a search engine with an alias - which works like a keyword.
|
||||
let matched = await this._matchSearchEngineAlias(this._heuristicToken);
|
||||
|
@ -1327,7 +1338,50 @@ Search.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
// Fall back to UrlbarProviderHeuristicFallback.
|
||||
if (this.pending && this._searchTokens.length && this._enableActions) {
|
||||
// If we don't have a result that matches what we know about, then
|
||||
// we use a fallback for things we don't know about.
|
||||
|
||||
// We may not have auto-filled, but this may still look like a URL.
|
||||
// However, even if the input is a valid URL, we may not want to use
|
||||
// it as such. This can happen if the host isn't using a known TLD
|
||||
// and hasn't been added to a user-controlled list of known domains,
|
||||
// and/or if it looks like an email address.
|
||||
let matched = await this._matchUnknownUrl();
|
||||
if (matched) {
|
||||
// Since we can't tell if this is a real URL and whether the user wants
|
||||
// to visit or search for it, we provide an alternative searchengine
|
||||
// match if the string looks like an alphanumeric origin or an e-mail.
|
||||
let str = this._originalSearchString;
|
||||
try {
|
||||
new URL(str);
|
||||
} catch (ex) {
|
||||
if (
|
||||
UrlbarPrefs.get("keyword.enabled") &&
|
||||
(UrlbarTokenizer.looksLikeOrigin(str, {
|
||||
noIp: true,
|
||||
noPort: true,
|
||||
}) ||
|
||||
UrlbarTokenizer.REGEXP_COMMON_EMAIL.test(str))
|
||||
) {
|
||||
this._addingHeuristicResult = false;
|
||||
await this._matchCurrentSearchEngine();
|
||||
this._addingHeuristicResult = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.pending && this._enableActions && this._originalSearchString) {
|
||||
// When all else fails, and the search string is non-empty, we search
|
||||
// using the current search engine.
|
||||
let matched = await this._matchCurrentSearchEngine();
|
||||
if (matched) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
|
@ -1358,6 +1412,18 @@ Search.prototype = {
|
|||
return gotResult;
|
||||
},
|
||||
|
||||
_matchExtensionHeuristicResult(keyword) {
|
||||
if (
|
||||
ExtensionSearchHandler.isKeywordRegistered(keyword) &&
|
||||
substringAfter(this._originalSearchString, keyword)
|
||||
) {
|
||||
let description = ExtensionSearchHandler.getDescription(keyword);
|
||||
this._addExtensionMatch(this._originalSearchString, description);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
async _matchPlacesKeyword(keyword) {
|
||||
let entry = await PlacesUtils.keywords.fetch(keyword);
|
||||
if (!entry) {
|
||||
|
@ -1498,6 +1564,46 @@ Search.prototype = {
|
|||
return true;
|
||||
},
|
||||
|
||||
async _matchCurrentSearchEngine() {
|
||||
let engine;
|
||||
if (this._engineName) {
|
||||
engine = Services.search.getEngineByName(this._engineName);
|
||||
} else if (this._inPrivateWindow) {
|
||||
engine = Services.search.defaultPrivateEngine;
|
||||
} else {
|
||||
engine = Services.search.defaultEngine;
|
||||
}
|
||||
|
||||
if (!engine || !this.pending) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Strip a leading search restriction char, because we prepend it to text
|
||||
// when the search shortcut is used and it's not user typed. Don't strip
|
||||
// other restriction chars, so that it's possible to search for things
|
||||
// including one of those (e.g. "c#").
|
||||
let query = this._trimmedOriginalSearchString;
|
||||
if (this._leadingRestrictionToken === UrlbarTokenizer.RESTRICT.SEARCH) {
|
||||
query = substringAfter(query, this._leadingRestrictionToken).trim();
|
||||
}
|
||||
this._addSearchEngineMatch({ engine, query });
|
||||
return true;
|
||||
},
|
||||
|
||||
_addExtensionMatch(content, comment) {
|
||||
this._addMatch({
|
||||
value: makeActionUrl("extension", {
|
||||
content,
|
||||
keyword: this._heuristicToken,
|
||||
}),
|
||||
comment,
|
||||
icon: "chrome://browser/content/extension.svg",
|
||||
style: "action extension",
|
||||
frecency: Infinity,
|
||||
type: UrlbarUtils.RESULT_GROUP.EXTENSION,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a search engine match.
|
||||
*
|
||||
|
@ -1597,6 +1703,106 @@ Search.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
// TODO (bug 1054814): Use visited URLs to inform which scheme to use, if the
|
||||
// scheme isn't specificed.
|
||||
_matchUnknownUrl() {
|
||||
if (!this._searchString && this._strippedPrefix) {
|
||||
// The user just typed a stripped protocol, don't build a non-sense url
|
||||
// like http://http/ for it.
|
||||
return false;
|
||||
}
|
||||
// The user may have typed something like "word?" to run a search, we should
|
||||
// not convert that to a url.
|
||||
if (this.hasBehavior("search") && this.hasBehavior("restrict")) {
|
||||
return false;
|
||||
}
|
||||
let flags =
|
||||
Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
|
||||
Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
|
||||
if (this._inPrivateWindow) {
|
||||
flags |= Ci.nsIURIFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
|
||||
}
|
||||
let fixupInfo = null;
|
||||
let searchUrl = this._trimmedOriginalSearchString;
|
||||
try {
|
||||
fixupInfo = Services.uriFixup.getFixupURIInfo(searchUrl, flags);
|
||||
} catch (e) {
|
||||
if (
|
||||
e.result == Cr.NS_ERROR_MALFORMED_URI &&
|
||||
!UrlbarPrefs.get("keyword.enabled")
|
||||
) {
|
||||
let value = makeActionUrl("visiturl", {
|
||||
url: searchUrl,
|
||||
input: searchUrl,
|
||||
});
|
||||
this._addMatch({
|
||||
value,
|
||||
comment: searchUrl,
|
||||
style: "action visiturl",
|
||||
frecency: Infinity,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the URI cannot be fixed or the preferred URI would do a keyword search,
|
||||
// that basically means this isn't useful to us. Note that
|
||||
// fixupInfo.keywordAsSent will never be true if the keyword.enabled pref
|
||||
// is false or there are no engines, so in that case we will always return
|
||||
// a "visit".
|
||||
if (!fixupInfo.fixedURI || fixupInfo.keywordAsSent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let uri = fixupInfo.fixedURI;
|
||||
// Check the host, as "http:///" is a valid nsIURI, but not useful to us.
|
||||
// But, some schemes are expected to have no host. So we check just against
|
||||
// schemes we know should have a host. This allows new schemes to be
|
||||
// implemented without us accidentally blocking access to them.
|
||||
let hostExpected = ["http", "https", "ftp", "chrome"].includes(uri.scheme);
|
||||
if (hostExpected && !uri.host) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// getFixupURIInfo() escaped the URI, so it may not be pretty. Embed the
|
||||
// escaped URL in the action URI since that URL should be "canonical". But
|
||||
// pass the pretty, unescaped URL as the match comment, since it's likely
|
||||
// to be displayed to the user, and in any case the front-end should not
|
||||
// rely on it being canonical.
|
||||
let escapedURL = uri.displaySpec;
|
||||
let displayURL = Services.textToSubURI.unEscapeURIForUI(escapedURL);
|
||||
|
||||
let value = makeActionUrl("visiturl", {
|
||||
url: escapedURL,
|
||||
input: searchUrl,
|
||||
});
|
||||
|
||||
let match = {
|
||||
value,
|
||||
comment: displayURL,
|
||||
style: "action visiturl",
|
||||
frecency: Infinity,
|
||||
};
|
||||
|
||||
// We don't know if this url is in Places or not, and checking that would
|
||||
// be expensive. Thus we also don't know if we may have an icon.
|
||||
// If we'd just try to fetch the icon for the typed string, we'd cause icon
|
||||
// flicker, since the url keeps changing while the user types.
|
||||
// By default we won't provide an icon, but for the subset of urls with a
|
||||
// host we'll check for a typed slash and set favicon for the host part.
|
||||
if (
|
||||
hostExpected &&
|
||||
(searchUrl.endsWith("/") || uri.pathQueryRef.length > 1)
|
||||
) {
|
||||
match.icon = `page-icon:${uri.prePath}/`;
|
||||
}
|
||||
|
||||
this._addMatch(match);
|
||||
return true;
|
||||
},
|
||||
|
||||
_onResultRow(row, cancel) {
|
||||
let queryType = row.getResultByIndex(QUERYINDEX_QUERYTYPE);
|
||||
switch (queryType) {
|
||||
|
|
|
@ -591,14 +591,15 @@ function addAutofillTasks(origins) {
|
|||
}
|
||||
|
||||
// Enable actions. In the `origins` case, the failure to make an autofill
|
||||
// match means UnifiedComplete should not create a heuristic result. In the
|
||||
// `!origins` case, autofill should still happen since there's no threshold
|
||||
// comparison.
|
||||
// match should not interrupt creating another type of heuristic match, in
|
||||
// this case a search (for "ex"). In the `!origins` case, autofill should
|
||||
// still happen since there's no threshold comparison.
|
||||
if (origins) {
|
||||
await check_autocomplete({
|
||||
search,
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch(search, { style: ["heuristic"] }),
|
||||
{
|
||||
value: "https://not-" + url,
|
||||
comment: "test visit for https://not-" + url,
|
||||
|
|
|
@ -298,24 +298,20 @@ async function check_autocomplete(test) {
|
|||
if (matches.length) {
|
||||
let firstIndexToCheck = 0;
|
||||
if (test.searchParam && test.searchParam.includes("enable-actions")) {
|
||||
firstIndexToCheck = 1;
|
||||
info("Checking first match is first autocomplete entry");
|
||||
let result = {
|
||||
value: controller.getValueAt(0),
|
||||
comment: controller.getCommentAt(0),
|
||||
style: controller.getStyleAt(0),
|
||||
image: controller.getImageAt(0),
|
||||
};
|
||||
// We only care about the positioning of the first result if it is
|
||||
// heuristic.
|
||||
if (result.style.includes("heuristic")) {
|
||||
info("Checking first match is first autocomplete entry");
|
||||
info(`First match is "${result.value}", "${result.comment}"`);
|
||||
Assert.ok(
|
||||
await _check_autocomplete_matches(matches[0], result),
|
||||
"first item is correct"
|
||||
);
|
||||
info("Checking rest of the matches");
|
||||
firstIndexToCheck = 1;
|
||||
}
|
||||
info(`First match is "${result.value}", "${result.comment}"`);
|
||||
Assert.ok(
|
||||
await _check_autocomplete_matches(matches[0], result),
|
||||
"first item is correct"
|
||||
);
|
||||
info("Checking rest of the matches");
|
||||
}
|
||||
|
||||
for (let i = firstIndexToCheck; i < controller.matchCount; i++) {
|
||||
|
|
|
@ -40,6 +40,7 @@ add_task(async function test_javascript_match() {
|
|||
search: "foo",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("foo", { heuristic: true }),
|
||||
{ uri: uri1, title: "title" },
|
||||
{ uri: uri2, title: "title", style: ["bookmark"] },
|
||||
{ uri: uri3, title: "title" },
|
||||
|
|
|
@ -251,6 +251,18 @@ add_task(async function test_keyword_search() {
|
|||
],
|
||||
});
|
||||
|
||||
info("Bug 420328: no-param keyword with a param");
|
||||
await check_autocomplete({
|
||||
search: "noparam foo",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("noparam foo", { heuristic: true })],
|
||||
});
|
||||
await check_autocomplete({
|
||||
search: "post_noparam foo",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("post_noparam foo", { heuristic: true })],
|
||||
});
|
||||
|
||||
info("escaping with default UTF-8 charset");
|
||||
await check_autocomplete({
|
||||
search: "encoded foé",
|
||||
|
|
|
@ -66,6 +66,28 @@ function makeRemoteTabMatch(url, deviceName, extra = {}) {
|
|||
};
|
||||
}
|
||||
|
||||
// The tests.
|
||||
add_task(async function test_nomatch() {
|
||||
// Nothing matches.
|
||||
configureEngine({
|
||||
guid_desktop: {
|
||||
id: "desktop",
|
||||
tabs: [
|
||||
{
|
||||
urlHistory: ["http://foo.com/"],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// No remote tabs match here, so we only expect search results.
|
||||
await check_autocomplete({
|
||||
search: "ex",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("ex", { heuristic: true })],
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_minimal() {
|
||||
// The minimal client and tabs info we can get away with.
|
||||
configureEngine({
|
||||
|
@ -82,7 +104,10 @@ add_task(async function test_minimal() {
|
|||
await check_autocomplete({
|
||||
search: "ex",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeRemoteTabMatch("http://example.com/", "My Desktop")],
|
||||
matches: [
|
||||
makeSearchMatch("ex", { heuristic: true }),
|
||||
makeRemoteTabMatch("http://example.com/", "My Desktop"),
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -105,6 +130,7 @@ add_task(async function test_maximal() {
|
|||
search: "ex",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("ex", { heuristic: true }),
|
||||
makeRemoteTabMatch("http://example.com/", "My Phone", {
|
||||
title: "An Example",
|
||||
icon: "moz-anno:favicon:http://favicon/",
|
||||
|
@ -132,6 +158,7 @@ add_task(async function test_noShowIcons() {
|
|||
search: "ex",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("ex", { heuristic: true }),
|
||||
makeRemoteTabMatch("http://example.com/", "My Phone", {
|
||||
title: "An Example",
|
||||
// expecting the default favicon due to that pref.
|
||||
|
@ -160,7 +187,7 @@ add_task(async function test_dontMatchSyncedTabs() {
|
|||
await check_autocomplete({
|
||||
search: "ex",
|
||||
searchParam: "enable-actions",
|
||||
matches: [],
|
||||
matches: [makeSearchMatch("ex", { heuristic: true })],
|
||||
});
|
||||
Services.prefs.clearUserPref("services.sync.syncedTabs.showRemoteTabs");
|
||||
});
|
||||
|
@ -183,6 +210,7 @@ add_task(async function test_matches_title() {
|
|||
search: "ex",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("ex", { heuristic: true }),
|
||||
makeRemoteTabMatch("http://foo.com/", "My Phone", {
|
||||
title: "An Example",
|
||||
}),
|
||||
|
@ -215,7 +243,10 @@ add_task(async function test_localtab_matches_override() {
|
|||
await check_autocomplete({
|
||||
search: "ex",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSwitchToTabMatch("http://foo.com/", { title: "An Example" })],
|
||||
matches: [
|
||||
makeSearchMatch("ex", { heuristic: true }),
|
||||
makeSwitchToTabMatch("http://foo.com/", { title: "An Example" }),
|
||||
],
|
||||
});
|
||||
await removeOpenPages(uri, 1);
|
||||
});
|
||||
|
@ -244,6 +275,7 @@ add_task(async function test_remotetab_matches_override() {
|
|||
search: "rem",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("rem", { heuristic: true }),
|
||||
makeRemoteTabMatch("http://foo.remote.com/", "My Phone", {
|
||||
title: "An Example",
|
||||
}),
|
||||
|
@ -280,6 +312,7 @@ add_task(async function test_many_remotetab_matches() {
|
|||
searchParam: "enable-actions",
|
||||
checkSorting: true,
|
||||
matches: [
|
||||
makeSearchMatch("rem", { heuristic: true }),
|
||||
makeRemoteTabMatch("http://foo.remote.com/0", "My Phone", {
|
||||
title: "A title",
|
||||
}),
|
||||
|
@ -328,12 +361,15 @@ add_task(async function test_maxResults() {
|
|||
},
|
||||
});
|
||||
|
||||
// Set maxResults to 4 in our search.
|
||||
// Set maxResults to 5 in our search. 5 results total should be returned: the
|
||||
// heuristic followed by ceil(maxResults / 2) remote tabs, then two more
|
||||
// remote tabs to round out the number of results to 5.
|
||||
await check_autocomplete({
|
||||
search: "rem",
|
||||
searchParam: "enable-actions max-results:4",
|
||||
searchParam: "enable-actions max-results:5",
|
||||
checkSorting: true,
|
||||
matches: [
|
||||
makeSearchMatch("rem", { heuristic: true }),
|
||||
makeRemoteTabMatch("http://foo.remote.com/0", "My Phone", {
|
||||
title: "A title",
|
||||
}),
|
||||
|
@ -373,14 +409,15 @@ add_task(async function test_restrictionCharacter() {
|
|||
await PlacesTestUtils.addVisits([{ uri, title: "An Example" }]);
|
||||
await addOpenPages(uri, 1);
|
||||
|
||||
// Set maxResults to 7 in our search. 7 results should be returned:
|
||||
// ceil(maxResults / 2) remote tabs, then the open tab, then 2 more remote tab
|
||||
// results to get to 7 total.
|
||||
// Set maxResults to 8 in our search. 8 results should be returned: the
|
||||
// heuristic followed by (maxResults / 2) remote tabs, then the open tab, then
|
||||
// 2 more remote tab results to get to 8 total.
|
||||
await check_autocomplete({
|
||||
search: UrlbarTokenizer.RESTRICT.OPENPAGE,
|
||||
searchParam: "enable-actions max-results:7",
|
||||
searchParam: "enable-actions max-results:8",
|
||||
checkSorting: true,
|
||||
matches: [
|
||||
makeSearchMatch(UrlbarTokenizer.RESTRICT.OPENPAGE, { heuristic: true }),
|
||||
makeRemoteTabMatch("http://foo.remote.com/0", "My Phone", {
|
||||
title: "A title",
|
||||
}),
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Test that restriction tokens are not removed from the search string, apart
|
||||
* from a leading search restriction token.
|
||||
*/
|
||||
|
||||
add_task(async function test_searchstring() {
|
||||
for (let token of Object.values(UrlbarTokenizer.RESTRICT)) {
|
||||
for (let search of [`${token} query`, `query ${token}`]) {
|
||||
let searchQuery =
|
||||
token == UrlbarTokenizer.RESTRICT.SEARCH &&
|
||||
search.startsWith(UrlbarTokenizer.RESTRICT.SEARCH)
|
||||
? search.substring(2)
|
||||
: search;
|
||||
info(`Searching for "${search}", expecting "${searchQuery}"`);
|
||||
await check_autocomplete({
|
||||
search,
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch(search, {
|
||||
engineName: "MozSearch",
|
||||
searchQuery,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
|
@ -111,6 +111,30 @@ add_task(async function basicGetAndPost() {
|
|||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// When a restriction token is used before the alias, the alias should *not*
|
||||
// be recognized. It should be treated as part of the search string. Try
|
||||
// all the restriction tokens to test that. We should get a single "search
|
||||
// with" heuristic result without an alias.
|
||||
for (let token of Object.values(UrlbarTokenizer.RESTRICT)) {
|
||||
let search = `${token} ${alias} query string`;
|
||||
let searchQuery =
|
||||
token == UrlbarTokenizer.RESTRICT.SEARCH &&
|
||||
search.startsWith(UrlbarTokenizer.RESTRICT.SEARCH)
|
||||
? search.substring(2)
|
||||
: search;
|
||||
await check_autocomplete({
|
||||
search,
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch(search, {
|
||||
engineName: "MozSearch",
|
||||
searchQuery,
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
await cleanup();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(async function() {
|
||||
// Note that head_autocomplete.js has already added a MozSearch engine.
|
||||
// Here we add another engine with a search alias.
|
||||
await Services.search.addEngineWithDetails("AliasedMozSearch", {
|
||||
alias: "doit",
|
||||
method: "GET",
|
||||
template: "http://s.example.com/search",
|
||||
});
|
||||
|
||||
info("search engine");
|
||||
await check_autocomplete({
|
||||
search: "mozilla",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("mozilla", { heuristic: true })],
|
||||
});
|
||||
|
||||
info("search engine, uri-like input");
|
||||
await check_autocomplete({
|
||||
search: "http:///",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("http:///", { heuristic: true })],
|
||||
});
|
||||
|
||||
info("search engine, multiple words");
|
||||
await check_autocomplete({
|
||||
search: "mozzarella cheese",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("mozzarella cheese", { heuristic: true })],
|
||||
});
|
||||
|
||||
info("search engine, after current engine has changed");
|
||||
await Services.search.addEngineWithDetails("MozSearch2", {
|
||||
method: "GET",
|
||||
template: "http://s.example.com/search2",
|
||||
});
|
||||
let engine = Services.search.getEngineByName("MozSearch2");
|
||||
notEqual(
|
||||
Services.search.defaultEngine,
|
||||
engine,
|
||||
"New engine shouldn't be the current engine yet"
|
||||
);
|
||||
await Services.search.setDefault(engine);
|
||||
await check_autocomplete({
|
||||
search: "mozilla",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("mozilla", { engineName: "MozSearch2", heuristic: true }),
|
||||
],
|
||||
});
|
||||
|
||||
await cleanup();
|
||||
});
|
|
@ -25,11 +25,15 @@ add_task(async function test_tab_matches() {
|
|||
await addOpenPages(uri3, 1);
|
||||
await addOpenPages(uri4, 1);
|
||||
|
||||
info("basic tab match");
|
||||
info("two results, normal result is a tab match");
|
||||
await check_autocomplete({
|
||||
search: "abc.com",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" })],
|
||||
matches: [
|
||||
makeVisitMatch("abc.com", "http://abc.com/", { heuristic: true }),
|
||||
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
|
||||
makeSearchMatch("abc.com", { heuristic: false }),
|
||||
],
|
||||
});
|
||||
|
||||
info("three results, one tab match");
|
||||
|
@ -37,6 +41,7 @@ add_task(async function test_tab_matches() {
|
|||
search: "abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("abc", { heuristic: true }),
|
||||
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
|
||||
{
|
||||
uri: uri2,
|
||||
|
@ -57,6 +62,7 @@ add_task(async function test_tab_matches() {
|
|||
search: "abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("abc", { heuristic: true }),
|
||||
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
|
||||
makeSwitchToTabMatch("http://xyz.net/", {
|
||||
title: "xyz.net - we're better than ABC",
|
||||
|
@ -75,6 +81,7 @@ add_task(async function test_tab_matches() {
|
|||
search: "abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("abc", { heuristic: true }),
|
||||
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
|
||||
makeSwitchToTabMatch("http://xyz.net/", {
|
||||
title: "xyz.net - we're better than ABC",
|
||||
|
@ -94,6 +101,7 @@ add_task(async function test_tab_matches() {
|
|||
search: "abc",
|
||||
searchParam: "enable-actions user-context-id:3",
|
||||
matches: [
|
||||
makeSearchMatch("abc", { heuristic: true }),
|
||||
makeSwitchToTabMatch("http://foobar.org/", {
|
||||
title: "foobar.org - much better than ABC, definitely better than XYZ",
|
||||
}),
|
||||
|
@ -111,6 +119,7 @@ add_task(async function test_tab_matches() {
|
|||
search: "abc",
|
||||
searchParam: "enable-actions user-context-id:2",
|
||||
matches: [
|
||||
makeSearchMatch("abc", { heuristic: true }),
|
||||
{ uri: uri1, title: "ABC rocks", style: ["favicon"] },
|
||||
{
|
||||
uri: uri2,
|
||||
|
@ -133,6 +142,7 @@ add_task(async function test_tab_matches() {
|
|||
search: "abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("abc", { heuristic: true }),
|
||||
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
|
||||
makeSwitchToTabMatch("http://xyz.net/", {
|
||||
title: "xyz.net - we're better than ABC",
|
||||
|
@ -150,6 +160,7 @@ add_task(async function test_tab_matches() {
|
|||
search: "abc",
|
||||
searchParam: "enable-actions disable-private-actions",
|
||||
matches: [
|
||||
makeSearchMatch("abc", { heuristic: true }),
|
||||
{ uri: uri1, title: "ABC rocks", style: ["favicon"] },
|
||||
{
|
||||
uri: uri2,
|
||||
|
@ -184,12 +195,13 @@ add_task(async function test_tab_matches() {
|
|||
});
|
||||
|
||||
info("three results, no tab matches");
|
||||
await removeOpenPages(uri1, 1);
|
||||
await removeOpenPages(uri2, 6);
|
||||
removeOpenPages(uri1, 1);
|
||||
removeOpenPages(uri2, 6);
|
||||
await check_autocomplete({
|
||||
search: "abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch("abc", { heuristic: true }),
|
||||
{ uri: uri1, title: "ABC rocks", style: ["favicon"] },
|
||||
{
|
||||
uri: uri2,
|
||||
|
@ -209,28 +221,46 @@ add_task(async function test_tab_matches() {
|
|||
await check_autocomplete({
|
||||
search: UrlbarTokenizer.RESTRICT.OPENPAGE + " abc",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" })],
|
||||
matches: [
|
||||
makeSearchMatch(UrlbarTokenizer.RESTRICT.OPENPAGE + " abc", {
|
||||
heuristic: true,
|
||||
searchQuery: UrlbarTokenizer.RESTRICT.OPENPAGE + " abc",
|
||||
}),
|
||||
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
|
||||
],
|
||||
});
|
||||
|
||||
info("tab match with not-addable pages");
|
||||
await check_autocomplete({
|
||||
search: "mozilla",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSwitchToTabMatch("about:mozilla")],
|
||||
matches: [
|
||||
makeSearchMatch("mozilla", { heuristic: true }),
|
||||
makeSwitchToTabMatch("about:mozilla"),
|
||||
],
|
||||
});
|
||||
|
||||
info("tab match with not-addable pages, no boundary search");
|
||||
await check_autocomplete({
|
||||
search: "ut:mo",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSwitchToTabMatch("about:mozilla")],
|
||||
matches: [
|
||||
makeSearchMatch("ut:mo", { heuristic: true }),
|
||||
makeSwitchToTabMatch("about:mozilla"),
|
||||
],
|
||||
});
|
||||
|
||||
info("tab match with not-addable pages and restriction character");
|
||||
await check_autocomplete({
|
||||
search: UrlbarTokenizer.RESTRICT.OPENPAGE + " mozilla",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSwitchToTabMatch("about:mozilla")],
|
||||
matches: [
|
||||
makeSearchMatch(UrlbarTokenizer.RESTRICT.OPENPAGE + " mozilla", {
|
||||
heuristic: true,
|
||||
searchQuery: UrlbarTokenizer.RESTRICT.OPENPAGE + " mozilla",
|
||||
}),
|
||||
makeSwitchToTabMatch("about:mozilla"),
|
||||
],
|
||||
});
|
||||
|
||||
info("tab match with not-addable pages and only restriction character");
|
||||
|
@ -238,6 +268,7 @@ add_task(async function test_tab_matches() {
|
|||
search: UrlbarTokenizer.RESTRICT.OPENPAGE,
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeSearchMatch(UrlbarTokenizer.RESTRICT.OPENPAGE, { heuristic: true }),
|
||||
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
|
||||
makeSwitchToTabMatch("about:mozilla"),
|
||||
makeSwitchToTabMatch("data:text/html,test"),
|
||||
|
@ -255,7 +286,11 @@ add_task(async function test_tab_matches() {
|
|||
await check_autocomplete({
|
||||
search: "abc.com",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" })],
|
||||
matches: [
|
||||
makeVisitMatch("abc.com", "http://abc.com/", { heuristic: true }),
|
||||
makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
|
||||
makeSearchMatch("abc.com", { heuristic: false }),
|
||||
],
|
||||
});
|
||||
await PlacesUtils.bookmarks.remove(bm);
|
||||
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
add_task(async function() {
|
||||
info("visit url, no protocol");
|
||||
await check_autocomplete({
|
||||
search: "mozilla.org",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
{
|
||||
uri: makeActionURI("visiturl", {
|
||||
url: "http://mozilla.org/",
|
||||
input: "mozilla.org",
|
||||
}),
|
||||
title: "http://mozilla.org/",
|
||||
style: ["action", "visiturl", "heuristic"],
|
||||
},
|
||||
{
|
||||
uri: makeActionURI("searchengine", {
|
||||
engineName: "MozSearch",
|
||||
input: "mozilla.org",
|
||||
searchQuery: "mozilla.org",
|
||||
}),
|
||||
title: "MozSearch",
|
||||
style: ["action", "searchengine"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, no protocol but with 2 dots");
|
||||
await check_autocomplete({
|
||||
search: "www.mozilla.org",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
{
|
||||
uri: makeActionURI("visiturl", {
|
||||
url: "http://www.mozilla.org/",
|
||||
input: "www.mozilla.org",
|
||||
}),
|
||||
title: "http://www.mozilla.org/",
|
||||
style: ["action", "visiturl", "heuristic"],
|
||||
},
|
||||
{
|
||||
uri: makeActionURI("searchengine", {
|
||||
engineName: "MozSearch",
|
||||
input: "www.mozilla.org",
|
||||
searchQuery: "www.mozilla.org",
|
||||
}),
|
||||
title: "MozSearch",
|
||||
style: ["action", "searchengine"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, no protocol, e-mail like");
|
||||
await check_autocomplete({
|
||||
search: "a@b.com",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
{
|
||||
uri: makeActionURI("visiturl", {
|
||||
url: "http://a@b.com/",
|
||||
input: "a@b.com",
|
||||
}),
|
||||
title: "http://a@b.com/",
|
||||
style: ["action", "visiturl", "heuristic"],
|
||||
},
|
||||
{
|
||||
uri: makeActionURI("searchengine", {
|
||||
engineName: "MozSearch",
|
||||
input: "a@b.com",
|
||||
searchQuery: "a@b.com",
|
||||
}),
|
||||
title: "MozSearch",
|
||||
style: ["action", "searchengine"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, with protocol but with 2 dots");
|
||||
await check_autocomplete({
|
||||
search: "https://www.mozilla.org",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
{
|
||||
uri: makeActionURI("visiturl", {
|
||||
url: "https://www.mozilla.org/",
|
||||
input: "https://www.mozilla.org",
|
||||
}),
|
||||
title: "https://www.mozilla.org/",
|
||||
style: ["action", "visiturl", "heuristic"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, with protocol but with 3 dots");
|
||||
await check_autocomplete({
|
||||
search: "https://www.mozilla.org.tw",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
{
|
||||
uri: makeActionURI("visiturl", {
|
||||
url: "https://www.mozilla.org.tw/",
|
||||
input: "https://www.mozilla.org.tw",
|
||||
}),
|
||||
title: "https://www.mozilla.org.tw/",
|
||||
style: ["action", "visiturl", "heuristic"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, with protocol");
|
||||
await check_autocomplete({
|
||||
search: "https://mozilla.org",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
{
|
||||
uri: makeActionURI("visiturl", {
|
||||
url: "https://mozilla.org/",
|
||||
input: "https://mozilla.org",
|
||||
}),
|
||||
title: "https://mozilla.org/",
|
||||
style: ["action", "visiturl", "heuristic"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, about: protocol (no host)");
|
||||
await check_autocomplete({
|
||||
search: "about:nonexistent",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
{
|
||||
uri: makeActionURI("visiturl", {
|
||||
url: "about:nonexistent",
|
||||
input: "about:nonexistent",
|
||||
}),
|
||||
title: "about:nonexistent",
|
||||
style: ["action", "visiturl", "heuristic"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, with non-standard whitespace");
|
||||
await check_autocomplete({
|
||||
search: "https://www.mozilla.org\u2028",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
{
|
||||
uri: makeActionURI("visiturl", {
|
||||
url: "https://www.mozilla.org/",
|
||||
input: "https://www.mozilla.org",
|
||||
}),
|
||||
title: "https://www.mozilla.org/",
|
||||
style: ["action", "visiturl", "heuristic"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// This is distinct because of how we predict being able to url autofill via
|
||||
// host lookups.
|
||||
info("visit url, host matching visited host but not visited url");
|
||||
await PlacesTestUtils.addVisits([
|
||||
{
|
||||
uri: NetUtil.newURI("http://mozilla.org/wine/"),
|
||||
title: "Mozilla Wine",
|
||||
transition: TRANSITION_TYPED,
|
||||
},
|
||||
]);
|
||||
await check_autocomplete({
|
||||
search: "mozilla.org/rum",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("mozilla.org/rum", "http://mozilla.org/rum", {
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// And hosts with no dot in them are special, due to requiring whitelisting.
|
||||
info("non-whitelisted host");
|
||||
await check_autocomplete({
|
||||
search: "firefox",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("firefox", { heuristic: true })],
|
||||
});
|
||||
|
||||
info("string with non-whitelisted host");
|
||||
if (Services.prefs.getBoolPref("browser.fixup.defaultToSearch", true)) {
|
||||
await check_autocomplete({
|
||||
search: "firefox/get",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("firefox/get", { heuristic: true })],
|
||||
});
|
||||
} else {
|
||||
await check_autocomplete({
|
||||
search: "firefox/get",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("firefox/get", "http://firefox/get", {
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
Services.prefs.setBoolPref("browser.fixup.domainwhitelist.firefox", true);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("browser.fixup.domainwhitelist.firefox");
|
||||
});
|
||||
|
||||
info("whitelisted host");
|
||||
await check_autocomplete({
|
||||
search: "firefox",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("firefox", "http://firefox/", { heuristic: true }),
|
||||
makeSearchMatch("firefox", { heuristic: false }),
|
||||
],
|
||||
});
|
||||
|
||||
info("url with whitelisted host");
|
||||
await check_autocomplete({
|
||||
search: "firefox/get",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("firefox/get", "http://firefox/get", { heuristic: true }),
|
||||
],
|
||||
});
|
||||
|
||||
info(
|
||||
"visit url, host matching visited host but not visited url, whitelisted host"
|
||||
);
|
||||
Services.prefs.setBoolPref("browser.fixup.domainwhitelist.mozilla", true);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("browser.fixup.domainwhitelist.mozilla");
|
||||
});
|
||||
await check_autocomplete({
|
||||
search: "mozilla/rum",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("mozilla/rum", "http://mozilla/rum", { heuristic: true }),
|
||||
],
|
||||
});
|
||||
|
||||
// ipv4 and ipv6 literal addresses should offer to visit.
|
||||
info("visit url, ipv4 literal");
|
||||
await check_autocomplete({
|
||||
search: "127.0.0.1",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("127.0.0.1", "http://127.0.0.1/", { heuristic: true }),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, ipv6 literal");
|
||||
await check_autocomplete({
|
||||
search: "[2001:db8::1]",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("[2001:db8::1]", "http://[2001:db8::1]/", {
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// Setting keyword.enabled to false should always try to visit.
|
||||
let keywordEnabled = Services.prefs.getBoolPref("keyword.enabled");
|
||||
Services.prefs.setBoolPref("keyword.enabled", false);
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("keyword.enabled");
|
||||
});
|
||||
info("visit url, keyword.enabled = false");
|
||||
await check_autocomplete({
|
||||
search: "bacon",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeVisitMatch("bacon", "http://bacon/", { heuristic: true })],
|
||||
});
|
||||
info("visit two word query, keyword.enabled = false");
|
||||
await check_autocomplete({
|
||||
search: "bacon lovers",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("bacon lovers", "bacon lovers", { heuristic: true }),
|
||||
],
|
||||
});
|
||||
Services.prefs.setBoolPref("keyword.enabled", keywordEnabled);
|
||||
|
||||
info("visit url, scheme+host");
|
||||
await check_autocomplete({
|
||||
search: "http://example",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("http://example", "http://example/", { heuristic: true }),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, scheme+host");
|
||||
await check_autocomplete({
|
||||
search: "ftp://example",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("ftp://example", "ftp://example/", { heuristic: true }),
|
||||
],
|
||||
});
|
||||
|
||||
info("visit url, host+port");
|
||||
await check_autocomplete({
|
||||
search: "example:8080",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("example:8080", "http://example:8080/", {
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("numerical operations that look like urls should search");
|
||||
await check_autocomplete({
|
||||
search: "123/12",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("123/12", { heuristic: true })],
|
||||
});
|
||||
|
||||
info("numerical operations that look like urls should search");
|
||||
await check_autocomplete({
|
||||
search: "123.12/12.1",
|
||||
searchParam: "enable-actions",
|
||||
matches: [makeSearchMatch("123.12/12.1", { heuristic: true })],
|
||||
});
|
||||
|
||||
info("access resource:///modules");
|
||||
await check_autocomplete({
|
||||
search: "resource:///modules",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("resource:///modules", "resource:///modules", {
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
info("access resource://app/modules");
|
||||
await check_autocomplete({
|
||||
search: "resource://app/modules",
|
||||
searchParam: "enable-actions",
|
||||
matches: [
|
||||
makeVisitMatch("resource://app/modules", "resource://app/modules", {
|
||||
heuristic: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
});
|
|
@ -40,11 +40,14 @@ support-files =
|
|||
[test_query_url.js]
|
||||
[test_remote_tab_matches.js]
|
||||
skip-if = !sync
|
||||
[test_restrict_searchstring.js]
|
||||
[test_search_engine_alias.js]
|
||||
[test_search_engine_default.js]
|
||||
[test_search_engine_host.js]
|
||||
[test_search_engine_restyle.js]
|
||||
[test_special_search.js]
|
||||
[test_swap_protocol.js]
|
||||
[test_tab_matches.js]
|
||||
[test_trimming.js]
|
||||
[test_visit_url.js]
|
||||
[test_word_boundary_search.js]
|
||||
|
|
|
@ -69,7 +69,6 @@ avoid-blacklist-and-whitelist:
|
|||
- browser/components/uitour/UITourChild.jsm
|
||||
- browser/components/urlbar/tests/browser/browser_searchSingleWordNotification.js
|
||||
- browser/components/urlbar/tests/browser/browser_UrlbarInput_trimURLs.js
|
||||
- browser/components/urlbar/tests/unit/test_providerHeuristicFallback.js
|
||||
- browser/components/urlbar/tests/unit/test_search_suggestions.js
|
||||
- browser/components/urlbar/tests/unit/test_tokenizer.js
|
||||
- browser/extensions/formautofill/FormAutofillSync.jsm
|
||||
|
@ -359,6 +358,7 @@ avoid-blacklist-and-whitelist:
|
|||
- toolkit/components/crashes/tests/xpcshell/test_crash_manager.js
|
||||
- toolkit/components/extensions/Extension.jsm
|
||||
- toolkit/components/extensions/test/xpcshell/test_WebExtensionPolicy.js
|
||||
- toolkit/components/places/tests/unifiedcomplete/test_visit_url.js
|
||||
- toolkit/components/remotepagemanager/RemotePageManagerParent.jsm
|
||||
- toolkit/components/reputationservice/ApplicationReputation.cpp
|
||||
- toolkit/components/reputationservice/chromium/chrome/common/safe_browsing/csd.pb.h
|
||||
|
|
Загрузка…
Ссылка в новой задаче