1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
/* 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";
ChromeUtils.defineESModuleGetters(this, {
NewTabUtils: "resource://gre/modules/NewTabUtils.sys.mjs",
});
XPCOMUtils.defineLazyModuleGetters(this, {
AboutNewTab: "resource:///modules/AboutNewTab.jsm",
shortURL: "resource://activity-stream/lib/ShortURL.jsm",
getSearchProvider: "resource://activity-stream/lib/SearchShortcuts.jsm",
});
const SHORTCUTS_PREF =
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts";
const TOPSITES_FEED_PREF =
"browser.newtabpage.activity-stream.feeds.system.topsites";
this.topSites = class extends ExtensionAPI {
getAPI(context) {
return {
topSites: {
get: async function(options) {
// We fallback to newtab = false behavior if the user disabled their
// Top Sites feed.
let getNewtabSites =
options.newtab &&
Services.prefs.getBoolPref(TOPSITES_FEED_PREF, false);
let links = getNewtabSites
? AboutNewTab.getTopSites()
: await NewTabUtils.activityStreamLinks.getTopSites({
ignoreBlocked: options.includeBlocked,
onePerDomain: options.onePerDomain,
numItems: options.limit,
includeFavicon: options.includeFavicon,
});
if (options.includePinned && !getNewtabSites) {
let pinnedLinks = NewTabUtils.pinnedLinks.links;
if (options.includeFavicon) {
pinnedLinks = NewTabUtils.activityStreamProvider._faviconBytesToDataURI(
await NewTabUtils.activityStreamProvider._addFavicons(
pinnedLinks
)
);
}
pinnedLinks.forEach((pinnedLink, index) => {
if (
pinnedLink &&
(!pinnedLink.searchTopSite || options.includeSearchShortcuts)
) {
// Remove any dupes from history.
links = links.filter(
link =>
link.url != pinnedLink.url &&
(!options.onePerDomain ||
NewTabUtils.extractSite(link.url) !=
pinnedLink.baseDomain)
);
links.splice(index, 0, pinnedLink);
}
});
}
// Convert links to search shortcuts, if necessary.
if (
options.includeSearchShortcuts &&
Services.prefs.getBoolPref(SHORTCUTS_PREF, false) &&
!getNewtabSites
) {
// Pinned shortcuts are already returned as searchTopSite links,
// with a proper label and url. But certain non-pinned links may
// also be promoted to search shortcuts; here we convert them.
links = links.map(link => {
let searchProvider = getSearchProvider(shortURL(link));
if (searchProvider) {
link.searchTopSite = true;
link.label = searchProvider.keyword;
link.url = searchProvider.url;
}
return link;
});
}
// Because we may have added links, we must crop again.
if (typeof options.limit == "number") {
links = links.slice(0, options.limit);
}
const makeDataURI = url => url && ExtensionUtils.makeDataURI(url);
return Promise.all(
links.map(async link => ({
type: link.searchTopSite ? "search" : "url",
url: link.url,
// 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 || "",
// Default top sites don't have a favicon property. Instead they
// have tippyTopIcon, a 96x96pt image used on the newtab page.
// We'll use it as the favicon for now, but ideally default top
// sites would have real favicons. Non-default top sites (i.e.,
// those from the user's history) will have favicons.
favicon: options.includeFavicon
? link.favicon || (await makeDataURI(link.tippyTopIcon)) || null
: null,
}))
);
},
},
};
}
};
|