зеркало из https://github.com/mozilla/gecko-dev.git
232 строки
7.2 KiB
JavaScript
232 строки
7.2 KiB
JavaScript
/* 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";
|
|
|
|
var EXPORTED_SYMBOLS = ["UrlbarProviderTopSites"];
|
|
|
|
const { XPCOMUtils } = ChromeUtils.import(
|
|
"resource://gre/modules/XPCOMUtils.jsm"
|
|
);
|
|
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
AboutNewTab: "resource:///modules/AboutNewTab.jsm",
|
|
Log: "resource://gre/modules/Log.jsm",
|
|
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
|
|
PlacesSearchAutocompleteProvider:
|
|
"resource://gre/modules/PlacesSearchAutocompleteProvider.jsm",
|
|
Services: "resource://gre/modules/Services.jsm",
|
|
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
|
|
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
|
|
UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.jsm",
|
|
UrlbarResult: "resource:///modules/UrlbarResult.jsm",
|
|
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
|
|
});
|
|
|
|
XPCOMUtils.defineLazyGetter(this, "logger", () =>
|
|
Log.repository.getLogger("Urlbar.Provider.TopSites")
|
|
);
|
|
|
|
/**
|
|
* This module exports a provider returning the user's newtab Top Sites.
|
|
*/
|
|
|
|
/**
|
|
* A provider that returns the Top Sites shown on about:newtab.
|
|
*/
|
|
class ProviderTopSites extends UrlbarProvider {
|
|
constructor() {
|
|
super();
|
|
// Maps the running queries by queryContext.
|
|
this.queries = new Map();
|
|
}
|
|
|
|
get PRIORITY() {
|
|
// Top sites are prioritized over the UnifiedComplete provider.
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
get name() {
|
|
return "UrlbarProviderTopSites";
|
|
}
|
|
|
|
/**
|
|
* The type of the provider.
|
|
*/
|
|
get type() {
|
|
return UrlbarUtils.PROVIDER_TYPE.PROFILE;
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
// If top sites on new tab are disabled, the pref below will be false, and
|
|
// activity stream's top sites will be unavailable (an empty array), so we
|
|
// make this provider inactive. For empty search strings, we instead show
|
|
// the most frecent URLs in the user's history from the UnifiedComplete
|
|
// provider.
|
|
return (
|
|
UrlbarPrefs.get("openViewOnFocus") &&
|
|
!queryContext.searchString &&
|
|
Services.prefs.getBoolPref(
|
|
"browser.newtabpage.activity-stream.feeds.topsites",
|
|
false
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 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 this.PRIORITY;
|
|
}
|
|
|
|
/**
|
|
* Starts querying.
|
|
* @param {UrlbarQueryContext} queryContext The query context object
|
|
* @param {function} addCallback Callback invoked by the provider to add a new
|
|
* result. A UrlbarResult should be passed to it.
|
|
* @note Extended classes should return a Promise resolved when the provider
|
|
* is done searching AND returning results.
|
|
*/
|
|
async startQuery(queryContext, addCallback) {
|
|
let sites = AboutNewTab.getTopSites();
|
|
|
|
let instance = {};
|
|
this.queries.set(queryContext, instance);
|
|
|
|
// Filter out empty values. Site is empty when there's a gap between tiles
|
|
// on about:newtab.
|
|
sites = sites.filter(site => site);
|
|
// We want the top 8 sites.
|
|
sites = sites.slice(0, 8);
|
|
|
|
sites = sites.map(link => ({
|
|
type: link.searchTopSite ? "search" : "url",
|
|
url: link.url,
|
|
isPinned: link.isPinned,
|
|
// The newtab page allows the user to set custom site titles, which
|
|
// are stored in `label`, so prefer it. Search top sites currently
|
|
// don't have titles but `hostname` instead.
|
|
title: link.label || link.title || link.hostname || "",
|
|
favicon: link.smallFavicon || link.favicon || null,
|
|
}));
|
|
|
|
for (let site of sites) {
|
|
switch (site.type) {
|
|
case "url": {
|
|
let result = new UrlbarResult(
|
|
UrlbarUtils.RESULT_TYPE.URL,
|
|
UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
|
|
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
|
|
title: site.title,
|
|
url: site.url,
|
|
icon: site.favicon,
|
|
isPinned: site.isPinned,
|
|
})
|
|
);
|
|
|
|
let tabs;
|
|
if (UrlbarPrefs.get("suggest.openpage")) {
|
|
tabs = UrlbarProviderOpenTabs.openTabs.get(
|
|
queryContext.userContextId || 0
|
|
);
|
|
}
|
|
|
|
if (tabs && tabs.includes(site.url.replace(/#.*$/, ""))) {
|
|
result.type = UrlbarUtils.RESULT_TYPE.TAB_SWITCH;
|
|
result.source = UrlbarUtils.RESULT_SOURCE.TABS;
|
|
} else if (UrlbarPrefs.get("suggest.bookmark")) {
|
|
let bookmark = await PlacesUtils.bookmarks.fetch({
|
|
url: new URL(result.payload.url),
|
|
});
|
|
if (bookmark) {
|
|
result.source = UrlbarUtils.RESULT_SOURCE.BOOKMARKS;
|
|
}
|
|
}
|
|
|
|
// Our query has been cancelled.
|
|
if (!this.queries.get(queryContext)) {
|
|
break;
|
|
}
|
|
|
|
addCallback(this, result);
|
|
break;
|
|
}
|
|
case "search": {
|
|
let engine = await PlacesSearchAutocompleteProvider.engineForAlias(
|
|
site.title
|
|
);
|
|
|
|
if (!engine && site.url) {
|
|
// Look up the engine by its domain.
|
|
let host;
|
|
try {
|
|
host = new URL(site.url).hostname;
|
|
} catch (err) {}
|
|
if (host) {
|
|
engine = await PlacesSearchAutocompleteProvider.engineForDomainPrefix(
|
|
host
|
|
);
|
|
}
|
|
}
|
|
|
|
if (!engine) {
|
|
// No engine found. We skip this Top Site.
|
|
break;
|
|
}
|
|
|
|
if (!this.queries.get(queryContext)) {
|
|
break;
|
|
}
|
|
|
|
let result = new UrlbarResult(
|
|
UrlbarUtils.RESULT_TYPE.SEARCH,
|
|
UrlbarUtils.RESULT_SOURCE.SEARCH,
|
|
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
|
|
title: site.title,
|
|
keyword: site.title,
|
|
keywordOffer: UrlbarUtils.KEYWORD_OFFER.HIDE,
|
|
engine: engine.name,
|
|
query: "",
|
|
icon: site.favicon,
|
|
isPinned: site.isPinned,
|
|
})
|
|
);
|
|
addCallback(this, result);
|
|
break;
|
|
}
|
|
default:
|
|
Cu.reportError(`Unknown Top Site type: ${site.type}`);
|
|
break;
|
|
}
|
|
}
|
|
this.queries.delete(queryContext);
|
|
}
|
|
|
|
/**
|
|
* Cancels a running query,
|
|
* @param {UrlbarQueryContext} queryContext the query context object to cancel
|
|
* query for.
|
|
*/
|
|
cancelQuery(queryContext) {
|
|
logger.info(`Canceling query for ${queryContext.searchString}`);
|
|
this.queries.delete(queryContext);
|
|
}
|
|
}
|
|
|
|
var UrlbarProviderTopSites = new ProviderTopSites();
|