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