diff --git a/src/background.js b/src/background.js index 9b2a601..a82e5a6 100644 --- a/src/background.js +++ b/src/background.js @@ -89,13 +89,36 @@ async function start() { requestHeaders, }; }, { urls: [`${SERP_BASE_URL}/search*`]}, ["blocking", "requestHeaders"]); - - browser.runtime.onMessage.addListener(({ action }) => { - if (action === 'getTokenCount') { - return Promise.resolve(tokenPool.tokens.length); - } - return false; - }) } +browser.runtime.onMessage.addListener(async ({ action, args }, { tab }) => { + if (action === 'getTokenCount') { + return Promise.resolve(tokenPool.tokens.length); + } + + if (action === 'getTopSites') { + return (await browser.topSites.get({ + newtab: true, + includeFavicon: true, + })).filter(site => site.type === 'url'); + } + + if (action === 'getSearchEngines') { + return (await browser.search.get()).filter( + engine => engine.name !== browser.runtime.getManifest()["chrome_settings_overrides"]["search_provider"].name + ); + } + + if (action === 'search') { + const { query, engine } = args[0]; + return browser.search.search({ + query, + engine, + tabId: tab.id, + }); + } + + return false; +}); + start(); diff --git a/src/content/additional-search-engines.js b/src/content/additional-search-engines.js new file mode 100644 index 0000000..a316d9c --- /dev/null +++ b/src/content/additional-search-engines.js @@ -0,0 +1,76 @@ +"use strict"; + +(async function () { + + function cleanup() { + const $content = document.querySelector('.main-content'); + const $searchEngines = document.querySelector('.searchengines'); + if ($searchEngines) { + $content.removeChild($searchEngines); + } + } + + async function addSearchEngines() { + const query = new URLSearchParams(window.location.search).get('q'); + const $content = document.querySelector('.main-content'); + const searchEngines = await browser.runtime.sendMessage({ + action: 'getSearchEngines', + }); + const $searchEnginesWrapper = document.createElement('div'); + $searchEnginesWrapper.classList.add('searchengines'); + $searchEnginesWrapper.style.display = 'flex'; + $searchEnginesWrapper.style.flexDirection = 'row'; + $searchEnginesWrapper.style.margin = '40px 0 40px 0'; + $searchEnginesWrapper.style.flexWrap = 'wrap'; + + searchEngines.forEach(engine => { + const $engine = document.createElement('a'); + $engine.style.display = 'flex'; + $engine.style.flexDirection = 'column'; + $engine.style.alignItems = 'center'; + $engine.style.margin = '10px 7px'; + $engine.style.textDecoration = 'none'; + $engine.style.color = 'black'; + $engine.style.cursor = 'pointer'; + $engine.addEventListener('click', () => { + browser.runtime.sendMessage({ + action: 'search', + args: [{ + query, + engine: engine.name, + }], + }); + }); + + const $favicon = document.createElement('img'); + $favicon.setAttribute('src', engine.favIconUrl); + $favicon.style.height = '24px'; + $favicon.style.width = '24px'; + $favicon.style.boxShadow = 'inset 0 0 0 1px rgba(249, 249, 250, 0.2), 0 1px 8px 0 rgba(12, 12, 13, 0.2)'; + $favicon.style.transition = 'box-shadow 150ms'; + $favicon.style.borderRadius = '5px'; + $favicon.style.backgroundColor = 'white'; + $engine.appendChild($favicon); + + const $title = document.createElement('span'); + $title.innerText = engine.name; + $title.style.marginTop = '5px'; + $engine.appendChild($title); + + $searchEnginesWrapper.appendChild($engine); + }); + + $content.appendChild($searchEnginesWrapper); + } + + if (document.readyState === 'complete' || document.readyState === 'interactive') { + cleanup(); + addSearchEngines(); + } else { + document.addEventListener('DOMContentLoaded', function onLoad() { + document.removeEventListener('DOMContentLoaded', onLoad); + cleanup(); + addSearchEngines(); + }); + } +}()); diff --git a/src/content/top-sites.js b/src/content/top-sites.js new file mode 100644 index 0000000..aa3ec2c --- /dev/null +++ b/src/content/top-sites.js @@ -0,0 +1,67 @@ +"use strict"; + +(async function () { + function cleanup() { + const $content = document.querySelector('.content'); + const $oldTopSites = $content.querySelector('.topsites'); + if ($oldTopSites) { + $content.removeChild($oldTopSites); + } + } + + async function loadTopSites() { + const $content = document.querySelector('.content'); + const topSites = await browser.runtime.sendMessage({ + action: 'getTopSites' + }); + + const $topSitesWrapper = document.createElement('div'); + $topSitesWrapper.classList.add('topsites'); + $topSitesWrapper.style.display = 'flex'; + $topSitesWrapper.style.flexDirection = 'row'; + $topSitesWrapper.style.margin = '40px 0 0 0'; + $topSitesWrapper.style.flexWrap = 'wrap'; + $topSitesWrapper.style.justifyContent = 'center'; + + topSites.forEach(site => { + const $site = document.createElement('a'); + $site.setAttribute('href', site.url); + $site.style.display = 'flex'; + $site.style.flexDirection = 'column'; + $site.style.alignItems = 'center'; + $site.style.margin = '10px 7px'; + $site.style.textDecoration = 'none'; + $site.style.color = 'black'; + + const $favicon = document.createElement('img'); + $favicon.setAttribute('src', site.favicon); + $favicon.style.height = '48px'; + $favicon.style.width = '48px'; + $favicon.style.boxShadow = 'inset 0 0 0 1px rgba(249, 249, 250, 0.2), 0 1px 8px 0 rgba(12, 12, 13, 0.2)'; + $favicon.style.transition = 'box-shadow 150ms'; + $favicon.style.borderRadius = '5px'; + $favicon.style.backgroundColor = 'white'; + $site.appendChild($favicon); + + const $title = document.createElement('span'); + $title.innerText = site.title; + $title.style.marginTop = '5px'; + $site.appendChild($title); + + $topSitesWrapper.appendChild($site); + }); + + $content.appendChild($topSitesWrapper); + } + + if (document.readyState === 'complete' || document.readyState === 'interactive') { + cleanup(); + loadTopSites(); + } else { + document.addEventListener('DOMContentLoaded', function onLoad() { + document.removeEventListener('DOMContentLoaded', onLoad); + cleanup(); + loadTopSites(); + }); + } +}()); diff --git a/src/manifest.json b/src/manifest.json index 186afc8..d63b471 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -19,15 +19,23 @@ "https://*.ghosterysearch.com/", "http://localhost/*" ], - "js": ["content/login-cta.js"] + "js": ["content/login-cta.js", "content/top-sites.js"] + }, { + "matches": [ + "https://*.ghosterysearch.com/search*", + "http://localhost/search*" + ], + "js": ["content/additional-search-engines.js"] }], "manifest_version": 2, "name": "Ghostery Search", "permissions": [ + "search", "storage", "cookies", "webRequest", "webRequestBlocking", + "topSites", "https://www.ghostery.com/*", "https://consumerapi.ghostery.com/*", "https://www.ghosterystage.com/*",