|
@ -0,0 +1,2 @@
|
|||
|
||||
.DS_Store
|
|
@ -0,0 +1,165 @@
|
|||
// onBeforeNavigate captures right before navigation to a new page starts;
|
||||
// onCreatedNavigationTarget captures new tabs/windows;
|
||||
// onCommitted captures after onBeforeNavigate, used to catch redirects.
|
||||
chrome.webNavigation.onBeforeNavigate.addListener(event => main(event, 'onBeforeNavigation'));
|
||||
chrome.webNavigation.onCreatedNavigationTarget.addListener(event => main(event, 'onCreatedNavigationTarget'));
|
||||
chrome.webNavigation.onCommitted.addListener(event => main(event, 'onCommitted'));
|
||||
|
||||
function redirectToBreezeWiki(storage, eventInfo, url) {
|
||||
function processRedirect(host) {
|
||||
const subdomain = url.hostname.split(".")[0];
|
||||
const article = url.href.split('fandom.com/wiki/')[1];
|
||||
if (article) {
|
||||
chrome.tabs.update(eventInfo.tabId, { url: host + '/' + subdomain + '/search?q=' + article });
|
||||
} else {
|
||||
chrome.tabs.update(eventInfo.tabId, { url: host + '/' + subdomain });
|
||||
}
|
||||
chrome.storage.sync.set({ 'countBreezeWiki': (storage.countBreezeWiki ?? 0) + 1 });
|
||||
if ((storage.notifications ?? 'on') === 'on') {
|
||||
// Notify that user is being redirected to BreezeWiki
|
||||
let notifID = 'independent-wiki-redirector-notification-' + Math.floor(Math.random() * 1E16);
|
||||
chrome.notifications.create(notifID, {
|
||||
"type": "basic",
|
||||
"iconUrl": 'images/logo-48.png',
|
||||
"title": "You've been redirected to BreezeWiki!",
|
||||
"message": "Indie Wiki Buddy has sent you to BreezeWiki for a cleaner, ad-free experience on Fandom."
|
||||
});
|
||||
// Self-clear notification after 6 seconds:
|
||||
setTimeout(function () { chrome.notifications.clear(notifID); }, 6000);
|
||||
}
|
||||
}
|
||||
|
||||
if (url.href.includes('fandom.com/wiki/')) {
|
||||
if (!(storage.breezewikiHost ?? null)) {
|
||||
fetch('http://bw.getindie.wiki/instances.json')
|
||||
.then((response) => response.json())
|
||||
.then((breezewikiHosts) => {
|
||||
const host = breezewikiHosts[Math.floor(Math.random() * breezewikiHosts.length)].instance;
|
||||
chrome.storage.sync.set({ 'breezewikiHost': host });
|
||||
chrome.storage.sync.set({ 'breezewikiHostOptions': breezewikiHosts });
|
||||
chrome.storage.sync.set({ 'breezewikiHostFetchTimestamp': Date.now() });
|
||||
processRedirect(host);
|
||||
});
|
||||
} else {
|
||||
processRedirect(storage.breezewikiHost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load website data.
|
||||
async function getData() {
|
||||
const LANGS = ["DE", "EN", "ES", "IT"];
|
||||
let sites = [];
|
||||
let promises = [];
|
||||
for (let i = 0; i < LANGS.length; i++) {
|
||||
promises.push(fetch(chrome.runtime.getURL('data/sites' + LANGS[i] + '.json'))
|
||||
.then((resp) => resp.json())
|
||||
.then(function (jsonData) {
|
||||
sites = sites.concat(jsonData);
|
||||
}));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
return sites;
|
||||
}
|
||||
|
||||
async function main(eventInfo, eventName) {
|
||||
// Create object prototypes for getting and setting attributes:
|
||||
Object.prototype.get = function(prop) {
|
||||
this[prop] = this[prop] || {};
|
||||
return this[prop];
|
||||
};
|
||||
Object.prototype.set = function(prop, value) {
|
||||
this[prop] = value;
|
||||
}
|
||||
|
||||
// Store tab URL and remove any search parameters and section anchors:
|
||||
const url = new URL(eventInfo.url.replace(/(\?|#).*/i, ''));
|
||||
|
||||
// Check if tabId is > 0 (some background events may have tabId < 0)
|
||||
// & check for fandom.com in hostname and quit early if it's not:
|
||||
if (eventInfo.tabId > 0 && url.hostname.includes('.fandom.com')) {
|
||||
// Check if tab is actually available
|
||||
// This is mainly to prevent background processes from triggering an event
|
||||
chrome.tabs.get(eventInfo.tabId, async function (tab) {
|
||||
if (tab) {
|
||||
let sites = [];
|
||||
|
||||
sites = await getData();
|
||||
|
||||
chrome.storage.sync.get(function (storage) {
|
||||
if ((storage.power ?? 'on') === 'on') {
|
||||
// Check if site is in our list of wikis:
|
||||
let matchingSites = sites.filter(el => url.href.replace(/^https?:\/\//, '').startsWith(el.origin_base_url));
|
||||
if (matchingSites.length > 0) {
|
||||
// Select match with longest base URL
|
||||
let closestMatch = "";
|
||||
matchingSites.forEach(site => {
|
||||
if (site.origin_base_url.length > closestMatch.length) {
|
||||
closestMatch = site.origin_base_url;
|
||||
}
|
||||
});
|
||||
let site = matchingSites.find(site => site.origin_base_url === closestMatch);
|
||||
if (site) {
|
||||
// Get user's settings for the wiki
|
||||
let settings = storage.siteSettings || {};
|
||||
let id = site['id'];
|
||||
let siteSetting = 'alert';
|
||||
if (settings.hasOwnProperty(id) && settings[id].hasOwnProperty('action')) {
|
||||
siteSetting = settings[id].action;
|
||||
}
|
||||
// Check if redirects are enabled for the site:
|
||||
if (siteSetting === 'redirect') {
|
||||
// Get article name from the end of the URL;
|
||||
// We can't just take the last part of the path due to subpages;
|
||||
// Instead, we take everything after the wiki's base URL + content path:
|
||||
let article = url.href.split(site['origin_base_url'] + site['origin_content_path'])[1];
|
||||
// Set up URL to redirect user to based on wiki platform:
|
||||
if (article || (!article && !url.href.split(site['origin_base_url'] + '/')[1])) {
|
||||
let newURL = '';
|
||||
if (article) {
|
||||
let searchParams = '';
|
||||
switch (site['destination_platform']) {
|
||||
case 'mediawiki':
|
||||
searchParams = '?title=Special:Search&search=' + article;
|
||||
break;
|
||||
case 'doku':
|
||||
searchParams = 'start?do=search&q=' + article;
|
||||
break;
|
||||
}
|
||||
newURL = 'https://' + site["destination_base_url"] + site["destination_content_path"] + searchParams;
|
||||
} else {
|
||||
newURL = 'https://' + site["destination_base_url"];
|
||||
}
|
||||
|
||||
// Perform redirect:
|
||||
chrome.tabs.update(eventInfo.tabId, { url: newURL });
|
||||
// Increase global redirect count:
|
||||
chrome.storage.sync.set({ 'countRedirects': (storage.countRedirects ?? 0) + 1 });
|
||||
|
||||
// Notify if enabled
|
||||
if ((storage.notifications ?? 'on') === 'on') {
|
||||
// Notify that user is being redirected
|
||||
let notifID = 'independent-wiki-redirector-notification-' + Math.floor(Math.random() * 1E16);
|
||||
chrome.notifications.create(notifID, {
|
||||
"type": "basic",
|
||||
"iconUrl": 'images/logo-48.png',
|
||||
"title": "You've been redirected!",
|
||||
"message": "Indie Wiki Buddy has sent you from " + site['origin'] + " to " + site['destination']
|
||||
});
|
||||
// Self-clear notification after 6 seconds:
|
||||
setTimeout(function () { chrome.notifications.clear(notifID); }, 6000);
|
||||
}
|
||||
}
|
||||
} else if ((storage.breezewiki ?? 'off') === 'on') {
|
||||
redirectToBreezeWiki(storage, eventInfo, url);
|
||||
}
|
||||
}
|
||||
} else if ((storage.breezewiki ?? 'off') === 'on') {
|
||||
redirectToBreezeWiki(storage, eventInfo, url);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,300 @@
|
|||
const searchEngineRegex = /www\.google\.|duckduckgo\.com|www\.bing\.com/;
|
||||
const fandomRegex = /\.fandom\.com$/;
|
||||
const breezeWikiRegex = /breezewiki\.pussthecat\.org$|bw\.odyssey346\.dev$|bw\.vern\.cc$|breezewiki\.esmailelbob\.xyz$|bw\.artemislena\.eu$/;
|
||||
const currentURL = new URL(document.location);
|
||||
|
||||
// Create object prototypes for getting and setting attributes:
|
||||
Object.prototype.get = function (prop) {
|
||||
this[prop] = this[prop] || {};
|
||||
return this[prop];
|
||||
};
|
||||
Object.prototype.set = function (prop, value) {
|
||||
this[prop] = value;
|
||||
}
|
||||
|
||||
// Create an observer to watch for mutations
|
||||
function addLocationObserver(callback) {
|
||||
const config = {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true
|
||||
}
|
||||
const observer = new MutationObserver(callback);
|
||||
observer.observe(document.body, config);
|
||||
}
|
||||
|
||||
// Load website data
|
||||
async function getData() {
|
||||
const LANGS = ["DE", "EN", "ES", "IT"];
|
||||
let sites = [];
|
||||
let promises = [];
|
||||
for (let i = 0; i < LANGS.length; i++) {
|
||||
promises.push(fetch(chrome.runtime.getURL('data/sites' + LANGS[i] + '.json'))
|
||||
.then((resp) => resp.json())
|
||||
.then(function (jsonData) {
|
||||
sites = sites.concat(jsonData);
|
||||
}));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
return sites;
|
||||
}
|
||||
|
||||
function displayRedirectBanner(url, destination, storage) {
|
||||
// Output banner
|
||||
var banner = document.createElement('div');
|
||||
banner.id = 'indie-wiki-banner';
|
||||
banner.style.fontSize = '1.2em';
|
||||
banner.style.fontFamily = 'sans-serif';
|
||||
banner.style.width = '100%';
|
||||
banner.style.zIndex = '2147483647';
|
||||
banner.style.position = 'fixed';
|
||||
banner.style.textAlign = 'center';
|
||||
banner.style.backgroundColor = '#acdae2';
|
||||
banner.style.minHeight = '40px';
|
||||
banner.style.lineHeight = '40px';
|
||||
var bannerExit = document.createElement('div');
|
||||
banner.appendChild(bannerExit);
|
||||
bannerExit.style.float = 'right';
|
||||
bannerExit.style.paddingRight = '10px';
|
||||
bannerExit.style.fontSize = '1.5em';
|
||||
bannerExit.style.color = '#333';
|
||||
bannerExit.style.cursor = 'pointer';
|
||||
bannerExit.innerText = '✕';
|
||||
bannerExit.onclick = function () { this.parentElement.remove(); };
|
||||
var bannerText = document.createElement('span');
|
||||
banner.appendChild(bannerText);
|
||||
bannerText.innerHTML = 'There is an independent wiki covering this topic! <br/>'
|
||||
var bannerLink = document.createElement('a');
|
||||
bannerText.appendChild(bannerLink);
|
||||
bannerLink.href = url;
|
||||
bannerLink.style.color = 'navy';
|
||||
bannerLink.style.fontWeight = '600';
|
||||
bannerLink.innerText = 'Visit ' + destination + '→';
|
||||
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
||||
document.body.insertAdjacentElement('beforeBegin', banner);
|
||||
if (storage.breezewiki === 'on') {
|
||||
if (currentURL.hostname.match(breezeWikiRegex)) {
|
||||
chrome.storage.sync.set({ 'countAlerts': (storage.countAlerts ?? 0) + 1 });
|
||||
}
|
||||
} else {
|
||||
chrome.storage.sync.set({ 'countAlerts': (storage.countAlerts ?? 0) + 1 });
|
||||
}
|
||||
} else {
|
||||
document.addEventListener('readystatechange', e => {
|
||||
if (document.readyState === 'interactive' || document.readyState === 'complete') {
|
||||
document.body.insertAdjacentElement('beforeBegin', banner);
|
||||
if (storage.breezewiki === 'on') {
|
||||
if (currentURL.hostname.match(breezeWikiRegex)) {
|
||||
chrome.storage.sync.set({ 'countAlerts': (storage.countAlerts ?? 0) + 1 });
|
||||
}
|
||||
} else {
|
||||
chrome.storage.sync.set({ 'countAlerts': (storage.countAlerts ?? 0) + 1 });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function filterSearchResults(fandomSearchResults, searchEngine, storage) {
|
||||
getData().then(sites => {
|
||||
countFiltered = 0;
|
||||
fandomSearchResults.forEach(searchResult => {
|
||||
let searchResultLink = searchResult.closest('[href]').href;
|
||||
// Check if site is in our list of wikis:
|
||||
let matchingSites = sites.filter(el => String(searchResultLink).replace(/^https?:\/\//, '').startsWith(el.origin_base_url));
|
||||
if (matchingSites.length > 0) {
|
||||
// Select match with longest base URL
|
||||
let closestMatch = "";
|
||||
matchingSites.forEach(site => {
|
||||
if (site.origin_base_url.length > closestMatch.length) {
|
||||
closestMatch = site.origin_base_url;
|
||||
}
|
||||
});
|
||||
let site = matchingSites.find(site => site.origin_base_url === closestMatch);
|
||||
if (site) {
|
||||
// Get user's settings for the wiki
|
||||
let settings = storage.siteSettings || {};
|
||||
let id = site['id'];
|
||||
let searchFilterSetting = 'true';
|
||||
if (settings.hasOwnProperty(id) && settings[id].searchFilter) {
|
||||
searchFilterSetting = settings[id].searchFilter;
|
||||
}
|
||||
if (searchFilterSetting === 'true') {
|
||||
let cssQuery = '';
|
||||
switch (searchEngine) {
|
||||
case 'google':
|
||||
if (searchResult.closest('div[data-hveid]')) {
|
||||
cssQuery = 'div[data-hveid]';
|
||||
}
|
||||
break;
|
||||
case 'bing':
|
||||
if (searchResult.closest('li.b_algo')) {
|
||||
cssQuery = 'li.b_algo';
|
||||
}
|
||||
break;
|
||||
case 'duckduckgo':
|
||||
if (searchResult.closest('div.nrn-react-div')) {
|
||||
cssQuery = 'div.nrn-react-div';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
if (cssQuery) {
|
||||
searchResult.closest(cssQuery).innerHTML = '<i>A Fandom result has been removed by Indie Wiki Buddy. Look for results from <a href="https://' + site.destination_base_url + '">' + site.destination + '</a> instead!</i>';
|
||||
countFiltered++;
|
||||
console.log(countFiltered);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
chrome.storage.sync.set({ 'countSearchFilters': (storage.countSearchFilters ?? 0) + countFiltered });
|
||||
});
|
||||
}
|
||||
|
||||
// Check if search engine results, Fandom, or a BreezeWiki host:
|
||||
function checkSite() {
|
||||
if (currentURL.hostname.match(searchEngineRegex) || currentURL.hostname.match(fandomRegex) || currentURL.hostname.match(breezeWikiRegex)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function main(mutations = null, observer = null) {
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
}
|
||||
chrome.storage.sync.get(function (storage) {
|
||||
// Check if extension is on:
|
||||
if ((storage.power ?? 'on') === 'on') {
|
||||
// Check if on Fandom or BreezeWiki
|
||||
// If on BreezeWiki, check if there is a pathname (which indicates we are looking at a wiki)
|
||||
if (currentURL.hostname.match(fandomRegex) || (currentURL.hostname.match(breezeWikiRegex) && currentURL.pathname.length > 1)) {
|
||||
// Check if notifications are enabled:
|
||||
if ((storage.notifications ?? 'on') === 'on') {
|
||||
let origin = currentURL;
|
||||
// If on a BreezeWiki site, convert to Fandom link to match with our list of wikis:
|
||||
if (currentURL.hostname.match(breezeWikiRegex)) {
|
||||
origin = String(currentURL.pathname).split('/')[1] + '.fandom.com/wiki/';
|
||||
if (currentURL.search.includes('?q=')) {
|
||||
origin = origin + currentURL.search.substring(3).split('&')[0];
|
||||
} else {
|
||||
origin = origin + currentURL.pathname.split('/')[3];
|
||||
}
|
||||
}
|
||||
getData().then(sites => {
|
||||
// Check if site is in our list of wikis:
|
||||
let matchingSites = sites.filter(el => String(origin).replace(/^https?:\/\//, '').startsWith(el.origin_base_url));
|
||||
if (matchingSites.length > 0) {
|
||||
// Select match with longest base URL
|
||||
let closestMatch = "";
|
||||
matchingSites.forEach(site => {
|
||||
if (site.origin_base_url.length > closestMatch.length) {
|
||||
closestMatch = site.origin_base_url;
|
||||
}
|
||||
});
|
||||
let site = matchingSites.find(site => site.origin_base_url === closestMatch);
|
||||
if (site) {
|
||||
// Get user's settings for the wiki
|
||||
let settings = storage.siteSettings || {};
|
||||
let id = site['id'];
|
||||
let siteSetting = 'alert';
|
||||
if (settings.hasOwnProperty(id) && settings[id].hasOwnProperty('action')) {
|
||||
siteSetting = settings[id].action;
|
||||
}
|
||||
// Notify if enabled for the wiki:
|
||||
if (siteSetting === 'alert') {
|
||||
// Get article name from the end of the URL;
|
||||
// We can't just take the last part of the path due to subpages;
|
||||
// Instead, we take everything after the wiki's base URL + content path:
|
||||
let article = String(origin).split(site['origin_base_url'] + site['origin_content_path'])[1];
|
||||
// Set up URL to redirect user to based on wiki platform:
|
||||
if (article || (!article && !url.href.split(site['origin_base_url'] + '/')[1])) {
|
||||
let newURL = '';
|
||||
if (article) {
|
||||
let searchParams = '';
|
||||
switch (site['destination_platform']) {
|
||||
case 'mediawiki':
|
||||
searchParams = '?title=Special:Search&search=' + article;
|
||||
break;
|
||||
case 'doku':
|
||||
searchParams = 'start?do=search&q=' + article;
|
||||
break;
|
||||
}
|
||||
newURL = 'https://' + site["destination_base_url"] + site["destination_content_path"] + searchParams;
|
||||
} else {
|
||||
newURL = 'https://' + site["destination_base_url"];
|
||||
}
|
||||
// Notify that another wiki is available
|
||||
displayRedirectBanner(newURL, site['destination'], storage);
|
||||
|
||||
// Unused code to notify user of alternative via browser notification:
|
||||
// let notifID = 'independent-wiki-redirector-notification-' + Math.floor(Math.random() * 1E16);
|
||||
// chrome.notifications.create(notifID, {
|
||||
// "type": "basic",
|
||||
// "iconUrl": 'images/logo-48.png',
|
||||
// "title": "An independent wiki is available!",
|
||||
// "message": "Check out " + site['destination']
|
||||
// });
|
||||
// chrome.notifications.onClicked.addListener(function () {
|
||||
// chrome.tabs.update(undefined, { url: newURL });
|
||||
// });
|
||||
// chrome.storage.sync.set({ 'countAlerts': (storage.countAlerts ?? 0) + 1 });
|
||||
// setTimeout(function () { chrome.notifications.clear(notifID); }, 6000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (currentURL.hostname.includes('www.google.')) {
|
||||
// Check if doing a Google search:
|
||||
function filterGoogle() {
|
||||
let fandomSearchResults = document.querySelectorAll("a[href*='fandom.com']>h3, h3>a[href*='fandom.com']");
|
||||
filterSearchResults(fandomSearchResults, 'google', storage);
|
||||
}
|
||||
addLocationObserver(main);
|
||||
filterGoogle();
|
||||
} else if (currentURL.hostname.includes('duckduckgo.com') && currentURL.search.includes('q=')) {
|
||||
// Check if doing a Duck Duck Go search:
|
||||
function filterDuckDuckGo() {
|
||||
let fandomSearchResults = document.querySelectorAll("h2>a[href*='fandom.com']");
|
||||
filterSearchResults(fandomSearchResults, 'duckduckgo', storage);
|
||||
}
|
||||
// Need to wait for document to be ready
|
||||
if (document.readyState === 'complete') {
|
||||
addLocationObserver(main);
|
||||
filterDuckDuckGo();
|
||||
} else {
|
||||
document.addEventListener('readystatechange', e => {
|
||||
if (document.readyState === 'complete') {
|
||||
addLocationObserver(main);
|
||||
filterDuckDuckGo();
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (currentURL.hostname.includes('www.bing.com')) {
|
||||
// Check if doing a Bing search:
|
||||
function filterBing() {
|
||||
let fandomSearchResults = document.querySelectorAll("h2>a[href*='fandom.com']");
|
||||
filterSearchResults(fandomSearchResults, 'bing', storage);
|
||||
}
|
||||
// Need to wait for document to be ready
|
||||
if (document.readyState === 'complete') {
|
||||
addLocationObserver(main);
|
||||
filterBing();
|
||||
} else {
|
||||
document.addEventListener('readystatechange', e => {
|
||||
if (document.readyState === 'complete') {
|
||||
addLocationObserver(main);
|
||||
filterBing();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (checkSite()) {
|
||||
main();
|
||||
}
|
After Width: | Height: | Size: 946 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 548 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,457 @@
|
|||
{
|
||||
"name": "Indie Wiki Buddy",
|
||||
"version": "1.0.0",
|
||||
"description": "Helping you discover quality independent wikis through alerts, redirects, and search filtering",
|
||||
"permissions": [
|
||||
"storage",
|
||||
"webNavigation",
|
||||
"notifications",
|
||||
"tabs"
|
||||
],
|
||||
"icons": {
|
||||
"16": "images/logo-16.png",
|
||||
"32": "images/logo-32.png",
|
||||
"48": "images/logo-48.png",
|
||||
"64": "images/logo-64.png",
|
||||
"128": "images/logo-128.png"
|
||||
},
|
||||
"action": {
|
||||
"default_popup": "popup.html",
|
||||
"default_icon": {
|
||||
"16": "images/logo-16.png",
|
||||
"32": "images/logo-32.png",
|
||||
"48": "images/logo-48.png",
|
||||
"64": "images/logo-64.png",
|
||||
"128": "images/logo-128.png"
|
||||
}
|
||||
},
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": [
|
||||
"data/sitesDE.json",
|
||||
"data/sitesEN.json",
|
||||
"data/sitesES.json",
|
||||
"data/sitesIT.json"
|
||||
],
|
||||
"matches": [
|
||||
"https://*.fandom.com/*",
|
||||
"https://breezewiki.com/*",
|
||||
"https://breezewiki.pussthecat.org/*",
|
||||
"https://bw.odyssey346.dev/*",
|
||||
"https://bw.vern.cc/*",
|
||||
"https://breezewiki.esmailelbob.xyz/*",
|
||||
"https://bw.artemislena.eu/*",
|
||||
"https://*.duckduckgo.com/*",
|
||||
"https://www.bing.com/*",
|
||||
"https://www.google.com/*",
|
||||
"https://www.google.ad/*",
|
||||
"https://www.google.ae/*",
|
||||
"https://www.google.com.af/*",
|
||||
"https://www.google.com.ag/*",
|
||||
"https://www.google.com.ai/*",
|
||||
"https://www.google.al/*",
|
||||
"https://www.google.am/*",
|
||||
"https://www.google.co.ao/*",
|
||||
"https://www.google.com.ar/*",
|
||||
"https://www.google.as/*",
|
||||
"https://www.google.at/*",
|
||||
"https://www.google.com.au/*",
|
||||
"https://www.google.az/*",
|
||||
"https://www.google.ba/*",
|
||||
"https://www.google.com.bd/*",
|
||||
"https://www.google.be/*",
|
||||
"https://www.google.bf/*",
|
||||
"https://www.google.bg/*",
|
||||
"https://www.google.com.bh/*",
|
||||
"https://www.google.bi/*",
|
||||
"https://www.google.bj/*",
|
||||
"https://www.google.com.bn/*",
|
||||
"https://www.google.com.bo/*",
|
||||
"https://www.google.com.br/*",
|
||||
"https://www.google.bs/*",
|
||||
"https://www.google.bt/*",
|
||||
"https://www.google.co.bw/*",
|
||||
"https://www.google.by/*",
|
||||
"https://www.google.com.bz/*",
|
||||
"https://www.google.ca/*",
|
||||
"https://www.google.cd/*",
|
||||
"https://www.google.cf/*",
|
||||
"https://www.google.cg/*",
|
||||
"https://www.google.ch/*",
|
||||
"https://www.google.ci/*",
|
||||
"https://www.google.co.ck/*",
|
||||
"https://www.google.cl/*",
|
||||
"https://www.google.cm/*",
|
||||
"https://www.google.cn/*",
|
||||
"https://www.google.com.co/*",
|
||||
"https://www.google.co.cr/*",
|
||||
"https://www.google.com.cu/*",
|
||||
"https://www.google.cv/*",
|
||||
"https://www.google.com.cy/*",
|
||||
"https://www.google.cz/*",
|
||||
"https://www.google.de/*",
|
||||
"https://www.google.dj/*",
|
||||
"https://www.google.dk/*",
|
||||
"https://www.google.dm/*",
|
||||
"https://www.google.com.do/*",
|
||||
"https://www.google.dz/*",
|
||||
"https://www.google.com.ec/*",
|
||||
"https://www.google.ee/*",
|
||||
"https://www.google.com.eg/*",
|
||||
"https://www.google.es/*",
|
||||
"https://www.google.com.et/*",
|
||||
"https://www.google.fi/*",
|
||||
"https://www.google.com.fj/*",
|
||||
"https://www.google.fm/*",
|
||||
"https://www.google.fr/*",
|
||||
"https://www.google.ga/*",
|
||||
"https://www.google.ge/*",
|
||||
"https://www.google.gg/*",
|
||||
"https://www.google.com.gh/*",
|
||||
"https://www.google.com.gi/*",
|
||||
"https://www.google.gl/*",
|
||||
"https://www.google.gm/*",
|
||||
"https://www.google.gr/*",
|
||||
"https://www.google.com.gt/*",
|
||||
"https://www.google.gy/*",
|
||||
"https://www.google.com.hk/*",
|
||||
"https://www.google.hn/*",
|
||||
"https://www.google.hr/*",
|
||||
"https://www.google.ht/*",
|
||||
"https://www.google.hu/*",
|
||||
"https://www.google.co.id/*",
|
||||
"https://www.google.ie/*",
|
||||
"https://www.google.co.il/*",
|
||||
"https://www.google.im/*",
|
||||
"https://www.google.co.in/*",
|
||||
"https://www.google.iq/*",
|
||||
"https://www.google.is/*",
|
||||
"https://www.google.it/*",
|
||||
"https://www.google.je/*",
|
||||
"https://www.google.com.jm/*",
|
||||
"https://www.google.jo/*",
|
||||
"https://www.google.co.jp/*",
|
||||
"https://www.google.co.ke/*",
|
||||
"https://www.google.com.kh/*",
|
||||
"https://www.google.ki/*",
|
||||
"https://www.google.kg/*",
|
||||
"https://www.google.co.kr/*",
|
||||
"https://www.google.com.kw/*",
|
||||
"https://www.google.kz/*",
|
||||
"https://www.google.la/*",
|
||||
"https://www.google.com.lb/*",
|
||||
"https://www.google.li/*",
|
||||
"https://www.google.lk/*",
|
||||
"https://www.google.co.ls/*",
|
||||
"https://www.google.lt/*",
|
||||
"https://www.google.lu/*",
|
||||
"https://www.google.lv/*",
|
||||
"https://www.google.com.ly/*",
|
||||
"https://www.google.co.ma/*",
|
||||
"https://www.google.md/*",
|
||||
"https://www.google.me/*",
|
||||
"https://www.google.mg/*",
|
||||
"https://www.google.mk/*",
|
||||
"https://www.google.ml/*",
|
||||
"https://www.google.com.mm/*",
|
||||
"https://www.google.mn/*",
|
||||
"https://www.google.ms/*",
|
||||
"https://www.google.com.mt/*",
|
||||
"https://www.google.mu/*",
|
||||
"https://www.google.mv/*",
|
||||
"https://www.google.mw/*",
|
||||
"https://www.google.com.mx/*",
|
||||
"https://www.google.com.my/*",
|
||||
"https://www.google.co.mz/*",
|
||||
"https://www.google.com.na/*",
|
||||
"https://www.google.com.ng/*",
|
||||
"https://www.google.com.ni/*",
|
||||
"https://www.google.ne/*",
|
||||
"https://www.google.nl/*",
|
||||
"https://www.google.no/*",
|
||||
"https://www.google.com.np/*",
|
||||
"https://www.google.nr/*",
|
||||
"https://www.google.nu/*",
|
||||
"https://www.google.co.nz/*",
|
||||
"https://www.google.com.om/*",
|
||||
"https://www.google.com.pa/*",
|
||||
"https://www.google.com.pe/*",
|
||||
"https://www.google.com.pg/*",
|
||||
"https://www.google.com.ph/*",
|
||||
"https://www.google.com.pk/*",
|
||||
"https://www.google.pl/*",
|
||||
"https://www.google.pn/*",
|
||||
"https://www.google.com.pr/*",
|
||||
"https://www.google.ps/*",
|
||||
"https://www.google.pt/*",
|
||||
"https://www.google.com.py/*",
|
||||
"https://www.google.com.qa/*",
|
||||
"https://www.google.ro/*",
|
||||
"https://www.google.ru/*",
|
||||
"https://www.google.rw/*",
|
||||
"https://www.google.com.sa/*",
|
||||
"https://www.google.com.sb/*",
|
||||
"https://www.google.sc/*",
|
||||
"https://www.google.se/*",
|
||||
"https://www.google.com.sg/*",
|
||||
"https://www.google.sh/*",
|
||||
"https://www.google.si/*",
|
||||
"https://www.google.sk/*",
|
||||
"https://www.google.com.sl/*",
|
||||
"https://www.google.sn/*",
|
||||
"https://www.google.so/*",
|
||||
"https://www.google.sm/*",
|
||||
"https://www.google.sr/*",
|
||||
"https://www.google.st/*",
|
||||
"https://www.google.com.sv/*",
|
||||
"https://www.google.td/*",
|
||||
"https://www.google.tg/*",
|
||||
"https://www.google.co.th/*",
|
||||
"https://www.google.com.tj/*",
|
||||
"https://www.google.tl/*",
|
||||
"https://www.google.tm/*",
|
||||
"https://www.google.tn/*",
|
||||
"https://www.google.to/*",
|
||||
"https://www.google.com.tr/*",
|
||||
"https://www.google.tt/*",
|
||||
"https://www.google.com.tw/*",
|
||||
"https://www.google.co.tz/*",
|
||||
"https://www.google.com.ua/*",
|
||||
"https://www.google.co.ug/*",
|
||||
"https://www.google.co.uk/*",
|
||||
"https://www.google.com.uy/*",
|
||||
"https://www.google.co.uz/*",
|
||||
"https://www.google.com.vc/*",
|
||||
"https://www.google.co.ve/*",
|
||||
"https://www.google.vg/*",
|
||||
"https://www.google.co.vi/*",
|
||||
"https://www.google.com.vn/*",
|
||||
"https://www.google.vu/*",
|
||||
"https://www.google.ws/*",
|
||||
"https://www.google.rs/*",
|
||||
"https://www.google.co.za/*",
|
||||
"https://www.google.co.zm/*",
|
||||
"https://www.google.co.zw/*",
|
||||
"https://www.google.cat/*"
|
||||
]
|
||||
}
|
||||
],
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"https://*.fandom.com/*",
|
||||
"https://breezewiki.com/*",
|
||||
"https://breezewiki.pussthecat.org/*",
|
||||
"https://bw.odyssey346.dev/*",
|
||||
"https://bw.vern.cc/*",
|
||||
"https://breezewiki.esmailelbob.xyz/*",
|
||||
"https://bw.artemislena.eu/*",
|
||||
"https://*.duckduckgo.com/*",
|
||||
"https://*.bing.com/search*",
|
||||
"https://www.google.com/search*",
|
||||
"https://www.google.ad/search*",
|
||||
"https://www.google.ae/search*",
|
||||
"https://www.google.com.af/search*",
|
||||
"https://www.google.com.ag/search*",
|
||||
"https://www.google.com.ai/search*",
|
||||
"https://www.google.al/search*",
|
||||
"https://www.google.am/search*",
|
||||
"https://www.google.co.ao/search*",
|
||||
"https://www.google.com.ar/search*",
|
||||
"https://www.google.as/search*",
|
||||
"https://www.google.at/search*",
|
||||
"https://www.google.com.au/search*",
|
||||
"https://www.google.az/search*",
|
||||
"https://www.google.ba/search*",
|
||||
"https://www.google.com.bd/search*",
|
||||
"https://www.google.be/search*",
|
||||
"https://www.google.bf/search*",
|
||||
"https://www.google.bg/search*",
|
||||
"https://www.google.com.bh/search*",
|
||||
"https://www.google.bi/search*",
|
||||
"https://www.google.bj/search*",
|
||||
"https://www.google.com.bn/search*",
|
||||
"https://www.google.com.bo/search*",
|
||||
"https://www.google.com.br/search*",
|
||||
"https://www.google.bs/search*",
|
||||
"https://www.google.bt/search*",
|
||||
"https://www.google.co.bw/search*",
|
||||
"https://www.google.by/search*",
|
||||
"https://www.google.com.bz/search*",
|
||||
"https://www.google.ca/search*",
|
||||
"https://www.google.cd/search*",
|
||||
"https://www.google.cf/search*",
|
||||
"https://www.google.cg/search*",
|
||||
"https://www.google.ch/search*",
|
||||
"https://www.google.ci/search*",
|
||||
"https://www.google.co.ck/search*",
|
||||
"https://www.google.cl/search*",
|
||||
"https://www.google.cm/search*",
|
||||
"https://www.google.cn/search*",
|
||||
"https://www.google.com.co/search*",
|
||||
"https://www.google.co.cr/search*",
|
||||
"https://www.google.com.cu/search*",
|
||||
"https://www.google.cv/search*",
|
||||
"https://www.google.com.cy/search*",
|
||||
"https://www.google.cz/search*",
|
||||
"https://www.google.de/search*",
|
||||
"https://www.google.dj/search*",
|
||||
"https://www.google.dk/search*",
|
||||
"https://www.google.dm/search*",
|
||||
"https://www.google.com.do/search*",
|
||||
"https://www.google.dz/search*",
|
||||
"https://www.google.com.ec/search*",
|
||||
"https://www.google.ee/search*",
|
||||
"https://www.google.com.eg/search*",
|
||||
"https://www.google.es/search*",
|
||||
"https://www.google.com.et/search*",
|
||||
"https://www.google.fi/search*",
|
||||
"https://www.google.com.fj/search*",
|
||||
"https://www.google.fm/search*",
|
||||
"https://www.google.fr/search*",
|
||||
"https://www.google.ga/search*",
|
||||
"https://www.google.ge/search*",
|
||||
"https://www.google.gg/search*",
|
||||
"https://www.google.com.gh/search*",
|
||||
"https://www.google.com.gi/search*",
|
||||
"https://www.google.gl/search*",
|
||||
"https://www.google.gm/search*",
|
||||
"https://www.google.gr/search*",
|
||||
"https://www.google.com.gt/search*",
|
||||
"https://www.google.gy/search*",
|
||||
"https://www.google.com.hk/search*",
|
||||
"https://www.google.hn/search*",
|
||||
"https://www.google.hr/search*",
|
||||
"https://www.google.ht/search*",
|
||||
"https://www.google.hu/search*",
|
||||
"https://www.google.co.id/search*",
|
||||
"https://www.google.ie/search*",
|
||||
"https://www.google.co.il/search*",
|
||||
"https://www.google.im/search*",
|
||||
"https://www.google.co.in/search*",
|
||||
"https://www.google.iq/search*",
|
||||
"https://www.google.is/search*",
|
||||
"https://www.google.it/search*",
|
||||
"https://www.google.je/search*",
|
||||
"https://www.google.com.jm/search*",
|
||||
"https://www.google.jo/search*",
|
||||
"https://www.google.co.jp/search*",
|
||||
"https://www.google.co.ke/search*",
|
||||
"https://www.google.com.kh/search*",
|
||||
"https://www.google.ki/search*",
|
||||
"https://www.google.kg/search*",
|
||||
"https://www.google.co.kr/search*",
|
||||
"https://www.google.com.kw/search*",
|
||||
"https://www.google.kz/search*",
|
||||
"https://www.google.la/search*",
|
||||
"https://www.google.com.lb/search*",
|
||||
"https://www.google.li/search*",
|
||||
"https://www.google.lk/search*",
|
||||
"https://www.google.co.ls/search*",
|
||||
"https://www.google.lt/search*",
|
||||
"https://www.google.lu/search*",
|
||||
"https://www.google.lv/search*",
|
||||
"https://www.google.com.ly/search*",
|
||||
"https://www.google.co.ma/search*",
|
||||
"https://www.google.md/search*",
|
||||
"https://www.google.me/search*",
|
||||
"https://www.google.mg/search*",
|
||||
"https://www.google.mk/search*",
|
||||
"https://www.google.ml/search*",
|
||||
"https://www.google.com.mm/search*",
|
||||
"https://www.google.mn/search*",
|
||||
"https://www.google.ms/search*",
|
||||
"https://www.google.com.mt/search*",
|
||||
"https://www.google.mu/search*",
|
||||
"https://www.google.mv/search*",
|
||||
"https://www.google.mw/search*",
|
||||
"https://www.google.com.mx/search*",
|
||||
"https://www.google.com.my/search*",
|
||||
"https://www.google.co.mz/search*",
|
||||
"https://www.google.com.na/search*",
|
||||
"https://www.google.com.ng/search*",
|
||||
"https://www.google.com.ni/search*",
|
||||
"https://www.google.ne/search*",
|
||||
"https://www.google.nl/search*",
|
||||
"https://www.google.no/search*",
|
||||
"https://www.google.com.np/search*",
|
||||
"https://www.google.nr/search*",
|
||||
"https://www.google.nu/search*",
|
||||
"https://www.google.co.nz/search*",
|
||||
"https://www.google.com.om/search*",
|
||||
"https://www.google.com.pa/search*",
|
||||
"https://www.google.com.pe/search*",
|
||||
"https://www.google.com.pg/search*",
|
||||
"https://www.google.com.ph/search*",
|
||||
"https://www.google.com.pk/search*",
|
||||
"https://www.google.pl/search*",
|
||||
"https://www.google.pn/search*",
|
||||
"https://www.google.com.pr/search*",
|
||||
"https://www.google.ps/search*",
|
||||
"https://www.google.pt/search*",
|
||||
"https://www.google.com.py/search*",
|
||||
"https://www.google.com.qa/search*",
|
||||
"https://www.google.ro/search*",
|
||||
"https://www.google.ru/search*",
|
||||
"https://www.google.rw/search*",
|
||||
"https://www.google.com.sa/search*",
|
||||
"https://www.google.com.sb/search*",
|
||||
"https://www.google.sc/search*",
|
||||
"https://www.google.se/search*",
|
||||
"https://www.google.com.sg/search*",
|
||||
"https://www.google.sh/search*",
|
||||
"https://www.google.si/search*",
|
||||
"https://www.google.sk/search*",
|
||||
"https://www.google.com.sl/search*",
|
||||
"https://www.google.sn/search*",
|
||||
"https://www.google.so/search*",
|
||||
"https://www.google.sm/search*",
|
||||
"https://www.google.sr/search*",
|
||||
"https://www.google.st/search*",
|
||||
"https://www.google.com.sv/search*",
|
||||
"https://www.google.td/search*",
|
||||
"https://www.google.tg/search*",
|
||||
"https://www.google.co.th/search*",
|
||||
"https://www.google.com.tj/search*",
|
||||
"https://www.google.tl/search*",
|
||||
"https://www.google.tm/search*",
|
||||
"https://www.google.tn/search*",
|
||||
"https://www.google.to/search*",
|
||||
"https://www.google.com.tr/search*",
|
||||
"https://www.google.tt/search*",
|
||||
"https://www.google.com.tw/search*",
|
||||
"https://www.google.co.tz/search*",
|
||||
"https://www.google.com.ua/search*",
|
||||
"https://www.google.co.ug/search*",
|
||||
"https://www.google.co.uk/search*",
|
||||
"https://www.google.com.uy/search*",
|
||||
"https://www.google.co.uz/search*",
|
||||
"https://www.google.com.vc/search*",
|
||||
"https://www.google.co.ve/search*",
|
||||
"https://www.google.vg/search*",
|
||||
"https://www.google.co.vi/search*",
|
||||
"https://www.google.com.vn/search*",
|
||||
"https://www.google.vu/search*",
|
||||
"https://www.google.ws/search*",
|
||||
"https://www.google.rs/search*",
|
||||
"https://www.google.co.za/search*",
|
||||
"https://www.google.co.zm/search*",
|
||||
"https://www.google.co.zw/search*",
|
||||
"https://www.google.cat/search*"
|
||||
],
|
||||
"js": [
|
||||
"content.js"
|
||||
],
|
||||
"run_at": "document_start"
|
||||
}
|
||||
],
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "{cb31ec5d-c49a-4e5a-b240-16c767444f62}"
|
||||
}
|
||||
},
|
||||
"manifest_version": 3
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Indie Wiki Buddy</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 10px;
|
||||
font-family: Helvetica, Sans-Serif;
|
||||
width: 42em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
border: none;
|
||||
color: #333;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.visuallyHidden {
|
||||
position: absolute !important;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
padding: 0 !important;
|
||||
margin: -1px !important;
|
||||
overflow: hidden !important;
|
||||
clip: rect(0, 0, 0, 0) !important;
|
||||
white-space: nowrap !important;
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: left;
|
||||
user-select: none;
|
||||
row-gap: 2px;
|
||||
}
|
||||
|
||||
.options>div {
|
||||
flex: 50%;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#controls {
|
||||
margin: 0 auto;
|
||||
width: fit-content;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.control {
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #333333;
|
||||
color: #333333;
|
||||
font-size: .95em;
|
||||
border-radius: 5px;
|
||||
padding: 3px 5px;
|
||||
margin: 3px 5px;
|
||||
}
|
||||
.control:hover {
|
||||
cursor: pointer;
|
||||
background: #3174f1;
|
||||
border: 1px solid#3174f1;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.settingToggleContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.settingToggle {
|
||||
cursor: pointer;
|
||||
width: fit-content;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
.settingToggle+div {
|
||||
display: inline-block;
|
||||
}
|
||||
.settingToggle input, .settingToggle label {
|
||||
cursor: pointer;
|
||||
}
|
||||
.settingToggle input {
|
||||
height: 0;
|
||||
width: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
appearance: none;
|
||||
}
|
||||
.settingToggle img {
|
||||
width: 30px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#toggles {
|
||||
height: 16em;
|
||||
white-space: nowrap;
|
||||
overflow-y: scroll;
|
||||
position: relative;
|
||||
}
|
||||
#toggles>div:hover {
|
||||
background-color: #e8f0fe;
|
||||
}
|
||||
#toggles input {
|
||||
cursor: pointer;
|
||||
}
|
||||
#toggles img {
|
||||
float: right;
|
||||
width: 18px;
|
||||
padding: 0px 10px;
|
||||
clear: both;
|
||||
}
|
||||
#toggles span {
|
||||
padding-left: 10px;
|
||||
}
|
||||
#togglesKey {
|
||||
padding-left: 5px;
|
||||
}
|
||||
#togglesKey > div {
|
||||
display: inline-block;
|
||||
width: 17px;
|
||||
}
|
||||
|
||||
.header,
|
||||
.footer {
|
||||
text-align: center;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
font-size: .9em;
|
||||
padding: 5px 0px;
|
||||
color: #3174f1;
|
||||
}
|
||||
|
||||
#toggles,
|
||||
#powerText,
|
||||
.settingToggleContainer,
|
||||
.footer {
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
#langSelectContainer {
|
||||
float: right;
|
||||
text-align: right;
|
||||
margin-top: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
#breezewikiHost {
|
||||
display: none;
|
||||
padding-left: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>Indie Wiki Buddy</h1>
|
||||
</div>
|
||||
<div id="langSelectContainer">
|
||||
<select name="lang" id="langSelect">
|
||||
<option value="DE">Deutch</option>
|
||||
<option value="EN" selected>English</option>
|
||||
<option value="ES">Español</option>
|
||||
<option value="IT">Italiano</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="options">
|
||||
<div class="settingToggleContainer">
|
||||
<div id="power" class="settingToggle">
|
||||
<input id="powerButton" type="checkbox" />
|
||||
<label for="powerButton">
|
||||
<img id="powerImage" src="" alt="">
|
||||
<span id="powerText"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settingToggleContainer">
|
||||
<div id="notifications" class="settingToggle">
|
||||
<input id="notificationsButton" type="checkbox" />
|
||||
<label for="notificationsButton">
|
||||
<img id="notificationsImage" src="" alt="">
|
||||
<span id="notificationsText"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settingToggleContainer">
|
||||
<div id="breezewiki" class="settingToggle">
|
||||
<input id="breezewikiButton" type="checkbox" />
|
||||
<label for="breezewikiButton">
|
||||
<img id="breezewikiImage" src="" alt="">
|
||||
<span id="breezewikiText"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
(<a href="https://breezewiki.com/" target="_blank">learn more</a>)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settingToggleContainer">
|
||||
<div id="breezewikiHost" class="settingToggle">
|
||||
<label for="breezewikiHostSelect">BreezeWiki host: </label>
|
||||
<select name="breezewikiHost" id="breezewikiHostSelect">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div id="controls">
|
||||
<button id="setAllDisabled" class="control"><img src="images/toggle-disabled.png" width="10" alt=""> Disable all</button>
|
||||
<button id="setAllRedirect" class="control"><img src="images/toggle-redirect.png" width="10" alt=""> Set all to redirect</button>
|
||||
<button id="setAllAlert" class="control"><img src="images/toggle-alert.png" width="10" alt=""> Set all to notify</button>
|
||||
<br/>
|
||||
<button id="setAllSearchFilter" class="control"><img src="images/toggle-search-filter.png" width="10" alt=""> Filter search for all</button>
|
||||
<button id="setNoneSearchFilter" class="control"><img src="images/toggle-search-filter.png" width="10" alt=""> Filter search for none</button>
|
||||
</div>
|
||||
<br />
|
||||
<div id="togglesKey">
|
||||
<div><img src="images/toggle-disabled.png" width="15" alt="Disable" title="Disable"></div>
|
||||
<div><img src="images/toggle-redirect.png" width="15" alt="Automatically redirect to indie wiki" title="Automatically redirect to indie wiki"></div>
|
||||
<div><img src="images/toggle-alert.png" width="15" alt="Notify of indie wiki with banner" title="Notify of indie wiki with banner"></div>
|
||||
<div><img src="images/toggle-search-filter.png" width="15" alt="Filter results from search engines" title="Filter results from search engines"></div>
|
||||
</div>
|
||||
<div id="toggles">
|
||||
</div>
|
||||
<hr />
|
||||
<div class="footer">
|
||||
You have been notified of indie wikis <span id="countAlerts"></span> times and redirected <span id="countRedirects"></span> times. Search results have been filtered <span id="countSearchFilters"></span> times.
|
||||
<br />
|
||||
<a href="https://getindie.wiki/" target="_blank">Info & Help</a> | <a href="https://form.getindie.wiki/" target="_blank">Submit a Wiki</a> | <a href="https://github.com/KevinPayravi/indie-wiki-buddy" target="_blank">Source Code</a>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript" src="popup.js"></script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,425 @@
|
|||
const LANGS = ["DE", "EN", "ES", "IT"];
|
||||
var sites = [];
|
||||
|
||||
// Create object prototypes for getting and setting attributes:
|
||||
Object.prototype.get = function(prop) {
|
||||
this[prop] = this[prop] || {};
|
||||
return this[prop];
|
||||
};
|
||||
Object.prototype.set = function(prop, value) {
|
||||
this[prop] = value;
|
||||
}
|
||||
|
||||
// Clear wiki toggles
|
||||
// Used when switching languages
|
||||
function resetOptions() {
|
||||
var toggleContainer = document.getElementById('toggles');
|
||||
toggleContainer.innerHTML = "";
|
||||
|
||||
// Clone "select all" buttons to reset listeners
|
||||
document.getElementById('setAllRedirect').cloneNode(true);
|
||||
document.getElementById('setAllAlert').cloneNode(true);
|
||||
document.getElementById('setAllDisabled').cloneNode(true);
|
||||
document.getElementById('setAllSearchFilter').cloneNode(true);
|
||||
document.getElementById('setNoneSearchFilter').cloneNode(true);
|
||||
}
|
||||
|
||||
// Get wiki data from data folder
|
||||
async function getData() {
|
||||
var sites = [];
|
||||
let promises = [];
|
||||
for (let i = 0; i < LANGS.length; i++) {
|
||||
promises.push(fetch(chrome.runtime.getURL('data/sites' + LANGS[i] + '.json'))
|
||||
.then((resp) => resp.json())
|
||||
.then(function (jsonData) {
|
||||
jsonData.forEach((site) => site.language = LANGS[i]);
|
||||
sites = sites.concat(jsonData);
|
||||
}));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
return sites;
|
||||
}
|
||||
|
||||
// Populate popup settings and toggles
|
||||
async function loadOptions(lang) {
|
||||
sites = await getData();
|
||||
|
||||
chrome.storage.sync.get({ 'siteSettings': {} }, function (response) {
|
||||
let siteSettings = response.siteSettings;
|
||||
|
||||
// Load BreezeWiki options:
|
||||
chrome.storage.sync.get(['breezewikiHostOptions', 'breezewikiHostFetchTimestamp', 'breezewikiHost'], function (item) {
|
||||
let hostOptions = item.breezewikiHostOptions;
|
||||
let hostFetchTimestamp = item.breezewikiHostFetchTimestamp;
|
||||
let host = item.breezewikiHost;
|
||||
// Fetch and cache list of BreezeWiki hosts if first time,
|
||||
// or if it has been 24 hrs since last refresh
|
||||
if (!host || !hostOptions || !hostFetchTimestamp || (Date.now() - 86400000 > hostFetchTimestamp)) {
|
||||
fetch('http://bw.getindie.wiki/instances.json')
|
||||
.then((response) => response.json())
|
||||
.then((breezewikiHosts) => {
|
||||
// If host isn't set, or currently selected host is no longer available, select random host:
|
||||
if (!host || !breezewikiHosts.some(item => item.instance === host)) {
|
||||
host = breezewikiHosts[Math.floor(Math.random() * breezewikiHosts.length)].instance;
|
||||
}
|
||||
// Populate dropdown selection of hosts
|
||||
const breezewikiHostSelect = document.getElementById('breezewikiHostSelect');
|
||||
for (var i = 0; i < breezewikiHosts.length; i++) {
|
||||
let option = document.createElement('option');
|
||||
option.value = breezewikiHosts[i].instance;
|
||||
option.innerText = breezewikiHosts[i].instance.replace('https://', '');
|
||||
breezewikiHostSelect.appendChild(option);
|
||||
if (option.value === host) {
|
||||
breezewikiHostSelect.value = host;
|
||||
}
|
||||
}
|
||||
// Store BreezeWiki host details
|
||||
chrome.storage.sync.set({ 'breezewikiHost': host });
|
||||
chrome.storage.sync.set({ 'breezewikiHostOptions': breezewikiHosts });
|
||||
chrome.storage.sync.set({ 'breezewikiHostFetchTimestamp': Date.now() });
|
||||
});
|
||||
} else {
|
||||
// If currently selected host is no longer available, select random host:
|
||||
if (!hostOptions.some(item => item.instance === host)) {
|
||||
host = hostOptions[Math.floor(Math.random() * hostOptions.length)].instance;
|
||||
}
|
||||
// Populate dropdown selection of hosts
|
||||
const breezewikiHostSelect = document.getElementById('breezewikiHostSelect');
|
||||
for (var i = 0; i < hostOptions.length; i++) {
|
||||
let option = document.createElement('option');
|
||||
option.value = hostOptions[i].instance;
|
||||
option.innerText = hostOptions[i].instance.replace('https://', '');
|
||||
breezewikiHostSelect.appendChild(option);
|
||||
if (option.value === host) {
|
||||
breezewikiHostSelect.value = host;
|
||||
}
|
||||
}
|
||||
// Store BreezeWiki host details
|
||||
chrome.storage.sync.set({ 'breezewikiHost': host });
|
||||
}
|
||||
});
|
||||
|
||||
// Populate individual wiki settings:
|
||||
var toggleContainer = document.getElementById('toggles');
|
||||
for (var i = 0; i < sites.length; i++) {
|
||||
if (sites[i].language === lang) {
|
||||
var key = sites[i].id;
|
||||
|
||||
// Create radio for disabled:
|
||||
let labelDisabled = document.createElement("label");
|
||||
let inputDisabled = document.createElement("input");
|
||||
inputDisabled.classList = 'disable';
|
||||
inputDisabled.type = "radio";
|
||||
inputDisabled.name = key;
|
||||
inputDisabled.title = 'Disable actions for ' + sites[i].origin;
|
||||
inputDisabled.id = key + '-redirect';
|
||||
|
||||
// Create radio for redirect:
|
||||
let labelRedirect = document.createElement("label");
|
||||
let inputRedirect = document.createElement("input");
|
||||
inputRedirect.classList = 'redirect';
|
||||
inputRedirect.type = "radio";
|
||||
inputRedirect.name = key;
|
||||
inputRedirect.title = 'Automatically redirect from ' + sites[i].origin + ' to ' + sites[i].destination;
|
||||
inputRedirect.id = key + '-redirect';
|
||||
|
||||
// Create radio for alert:
|
||||
let labelAlert = document.createElement("label");
|
||||
let inputAlert = document.createElement("input");
|
||||
inputAlert.classList = 'alert';
|
||||
inputAlert.type = "radio";
|
||||
inputAlert.name = key;
|
||||
inputAlert.title = 'Notify with banner when visiting ' + sites[i].origin;
|
||||
inputAlert.id = key + '-alert';
|
||||
|
||||
// Create checkbox for search filtering:
|
||||
let labelFilter = document.createElement("label");
|
||||
let inputFilter = document.createElement("input");
|
||||
inputFilter.classList = 'filter';
|
||||
inputFilter.type = 'checkbox';
|
||||
inputFilter.name = key;
|
||||
inputFilter.title = 'Filter from search results on Google, Bing, and DuckDuckGo';
|
||||
inputFilter.id = key + '-filter';
|
||||
|
||||
// Check radio button based on user's settings (default alert):
|
||||
if (siteSettings[key] && siteSettings[key].action === 'disabled') {
|
||||
inputDisabled.checked = true;
|
||||
} else if (siteSettings[key] && siteSettings[key].action === 'redirect') {
|
||||
inputRedirect.checked = true;
|
||||
} else {
|
||||
inputAlert.checked = true;
|
||||
}
|
||||
|
||||
// Check search filter checkbox based on user's settings (default filter):
|
||||
if (siteSettings[key] && siteSettings[key].searchFilter === 'false') {
|
||||
inputFilter.checked = false;
|
||||
} else {
|
||||
inputFilter.checked = true;
|
||||
}
|
||||
|
||||
// Add listeners for when user clicks control:
|
||||
inputRedirect.addEventListener('click', function (input) {
|
||||
chrome.storage.sync.get({ 'siteSettings': {} }, function (response) {
|
||||
var key = input.target.name;
|
||||
response.siteSettings.get(key).set('action', 'redirect');
|
||||
chrome.storage.sync.set({ 'siteSettings': response.siteSettings });
|
||||
});
|
||||
});
|
||||
inputAlert.addEventListener('click', function (input) {
|
||||
chrome.storage.sync.get({ 'siteSettings': {} }, function (response) {
|
||||
var key = input.target.name;
|
||||
response.siteSettings.get(key).set('action', 'alert');
|
||||
chrome.storage.sync.set({ 'siteSettings': response.siteSettings });
|
||||
});
|
||||
});
|
||||
inputDisabled.addEventListener('click', function (input) {
|
||||
chrome.storage.sync.get({ 'siteSettings': {} }[key], function (response) {
|
||||
var key = input.target.name;
|
||||
response.siteSettings.get(key).set('action', 'disabled');
|
||||
chrome.storage.sync.set({ 'siteSettings': response.siteSettings });
|
||||
});
|
||||
});
|
||||
inputFilter.addEventListener('click', function (input) {
|
||||
chrome.storage.sync.get({ 'siteSettings': {} }[key], function (response) {
|
||||
var key = input.target.name;
|
||||
if (response.siteSettings[key].searchFilter === 'true') {
|
||||
response.siteSettings.get(key).set('searchFilter', 'false');
|
||||
} else {
|
||||
response.siteSettings.get(key).set('searchFilter', 'true');
|
||||
}
|
||||
chrome.storage.sync.set({ 'siteSettings': response.siteSettings });
|
||||
});
|
||||
});
|
||||
|
||||
// Output disable radio button:
|
||||
let inputDisabledText = document.createElement('span');
|
||||
inputDisabledText.classList.add('visuallyHidden');
|
||||
inputDisabledText.innerHTML = 'Disable action for ' + sites[i].origin;
|
||||
labelDisabled.appendChild(inputDisabled);
|
||||
labelDisabled.appendChild(inputDisabledText);
|
||||
|
||||
// Output redirect radio button:
|
||||
let inputRedirectText = document.createElement('span');
|
||||
inputRedirectText.classList.add('visuallyHidden');
|
||||
inputRedirectText.innerHTML = 'Automatically redirect ' + sites[i].origin;
|
||||
labelRedirect.appendChild(inputRedirect);
|
||||
labelRedirect.appendChild(inputRedirectText);
|
||||
|
||||
// Output alert radio button:
|
||||
let inputAlertText = document.createElement('span');
|
||||
inputAlertText.classList.add('visuallyHidden');
|
||||
inputAlertText.innerHTML = 'Automatically alert for' + sites[i].origin;
|
||||
labelAlert.appendChild(inputAlert);
|
||||
labelAlert.appendChild(inputAlertText);
|
||||
|
||||
// Output search filter checkbox:
|
||||
let inputFilterText = document.createElement('span');
|
||||
inputFilterText.classList.add('visuallyHidden');
|
||||
inputFilterText.innerHTML = 'Filter ' + sites[i].origin + ' from search engine results';
|
||||
labelFilter.appendChild(inputFilter);
|
||||
labelFilter.appendChild(inputFilterText);
|
||||
|
||||
// Output icon
|
||||
let iconLink = document.createElement("a");
|
||||
iconLink.href = 'https://' + sites[i].destination_base_url;
|
||||
iconLink.title = sites[i].destination;
|
||||
iconLink.target = '_blank';
|
||||
let icon = document.createElement("img");
|
||||
icon.src = 'favicons/' + lang.toLowerCase() + '/' + sites[i].destination_icon;
|
||||
icon.alt = sites[i].destination;
|
||||
iconLink.appendChild(icon);
|
||||
|
||||
// Output text:
|
||||
let text = document.createElement('span');
|
||||
text.innerHTML = sites[i].origin + ' » ' + sites[i].destination;
|
||||
let siteContainer = document.createElement("div");
|
||||
|
||||
siteContainer.appendChild(labelDisabled);
|
||||
siteContainer.appendChild(labelRedirect);
|
||||
siteContainer.appendChild(labelAlert);
|
||||
siteContainer.appendChild(labelFilter);
|
||||
siteContainer.appendChild(iconLink);
|
||||
siteContainer.appendChild(text);
|
||||
|
||||
toggleContainer.appendChild(siteContainer);
|
||||
}
|
||||
}
|
||||
|
||||
// Add "select all" button event listeners:
|
||||
var setAllRedirect = document.getElementById('setAllRedirect');
|
||||
setAllRedirect.addEventListener('click', function () {
|
||||
var toggles = document.querySelectorAll('#toggles input.redirect');
|
||||
for (var i = 0; i < toggles.length; i++) {
|
||||
toggles[i].checked = true;
|
||||
siteSettings.get(toggles[i].name).set('action', 'redirect');
|
||||
}
|
||||
chrome.storage.sync.set({ 'siteSettings': siteSettings });
|
||||
});
|
||||
|
||||
var setAllAlert = document.getElementById('setAllAlert');
|
||||
setAllAlert.addEventListener('click', function () {
|
||||
var toggles = document.querySelectorAll('#toggles input.alert');
|
||||
for (var i = 0; i < toggles.length; i++) {
|
||||
toggles[i].checked = true;
|
||||
siteSettings.get(toggles[i].name).set('action', 'alert');
|
||||
}
|
||||
chrome.storage.sync.set({ 'siteSettings': siteSettings });
|
||||
});
|
||||
|
||||
var setAllDisabled = document.getElementById('setAllDisabled');
|
||||
setAllDisabled.addEventListener('click', function () {
|
||||
var toggles = document.querySelectorAll('#toggles input.disable');
|
||||
for (var i = 0; i < toggles.length; i++) {
|
||||
toggles[i].checked = true;
|
||||
siteSettings.get(toggles[i].name).set('action', 'disabled');
|
||||
}
|
||||
chrome.storage.sync.set({ 'siteSettings': siteSettings });
|
||||
});
|
||||
|
||||
var setAllSearchFilter = document.getElementById('setAllSearchFilter');
|
||||
setAllSearchFilter.addEventListener('click', function () {
|
||||
var toggles = document.querySelectorAll('#toggles input.filter');
|
||||
for (var i = 0; i < toggles.length; i++) {
|
||||
toggles[i].checked = true;
|
||||
siteSettings.get(toggles[i].name).set('searchFilter', 'true');
|
||||
}
|
||||
chrome.storage.sync.set({ 'siteSettings': siteSettings });
|
||||
});
|
||||
|
||||
var setNoneSearchFilter = document.getElementById('setNoneSearchFilter');
|
||||
setNoneSearchFilter.addEventListener('click', function () {
|
||||
var toggles = document.querySelectorAll('#toggles input.filter');
|
||||
for (var i = 0; i < toggles.length; i++) {
|
||||
toggles[i].checked = false;
|
||||
siteSettings.get(toggles[i].name).set('searchFilter', 'false');
|
||||
}
|
||||
chrome.storage.sync.set({ 'siteSettings': siteSettings });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Set power setting
|
||||
function setPower(setting) {
|
||||
chrome.storage.sync.set({ 'power': setting });
|
||||
var powerImage = document.getElementById('powerImage');
|
||||
powerImage.src = 'images/power-' + setting + '.png';
|
||||
var powerText = document.getElementById('powerText');
|
||||
powerText.innerHTML = 'Extension is ' + setting;
|
||||
}
|
||||
|
||||
// Set notifications setting
|
||||
function setNotifications(setting) {
|
||||
chrome.storage.sync.set({ 'notifications': setting });
|
||||
var notificationsImage = document.getElementById('notificationsImage');
|
||||
notificationsImage.src = 'images/bell-' + setting + '.png';
|
||||
var notificationsText = document.getElementById('notificationsText');
|
||||
notificationsText.innerHTML = 'Notify-on-redirect is ' + setting;
|
||||
}
|
||||
|
||||
// Set BreezeWiki settings
|
||||
function setBreezeWiki(setting) {
|
||||
chrome.storage.sync.set({ 'breezewiki': setting });
|
||||
var breezewikiImage = document.getElementById('breezewikiImage');
|
||||
breezewikiImage.src = 'images/check-' + setting + '.png';
|
||||
var breezewikiText = document.getElementById('breezewikiText');
|
||||
breezewikiText.innerHTML = 'BreezeWiki is ' + setting;
|
||||
var breezewikiHost = document.getElementById('breezewikiHost');
|
||||
if (setting === 'on') {
|
||||
breezewikiHost.style.display = 'block';
|
||||
chrome.storage.sync.get({ 'breezewikiHost': null }, function (host) {
|
||||
if (!host.breezewikiHost) {
|
||||
fetch('http://bw.getindie.wiki/instances.json')
|
||||
.then((response) => response.json())
|
||||
.then((breezewikiHosts) => {
|
||||
host.breezewikiHost = breezewikiHosts[Math.floor(Math.random() * breezewikiHosts.length)].instance;
|
||||
chrome.storage.sync.set({ 'breezewikiHost': host.breezewikiHost });
|
||||
chrome.storage.sync.set({ 'breezewikiHostOptions': breezewikiHosts });
|
||||
chrome.storage.sync.set({ 'breezewikiHostFetchTimestamp': Date.now() });
|
||||
document.getElementById('breezewikiHostSelect').value = host.breezewikiHost;
|
||||
});
|
||||
} else {
|
||||
document.getElementById('breezewikiHostSelect').value = host.breezewikiHost;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
breezewikiHost.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Main function that runs on-load
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Get user's last set language
|
||||
chrome.storage.sync.get({ 'lang': 'EN' }, function (item) {
|
||||
langSelect.value = item.lang;
|
||||
chrome.storage.sync.set({ 'lang': item.lang });
|
||||
loadOptions(item.lang);
|
||||
});
|
||||
// Add event listener for language select
|
||||
var langSelect = document.getElementById("langSelect");
|
||||
langSelect.addEventListener('change', function () {
|
||||
chrome.storage.sync.set({ 'lang': langSelect.value });
|
||||
resetOptions();
|
||||
loadOptions(langSelect.value);
|
||||
});
|
||||
|
||||
// Set power, notification, and BreezeWiki setting toggle values:
|
||||
chrome.storage.sync.get({ 'power': 'on' }, function (item) {
|
||||
setPower(item.power);
|
||||
});
|
||||
chrome.storage.sync.get({ 'notifications': 'on' }, function (item) {
|
||||
setNotifications(item.notifications);
|
||||
});
|
||||
chrome.storage.sync.get({ 'breezewiki': 'off' }, function (item) {
|
||||
setBreezeWiki(item.breezewiki);
|
||||
});
|
||||
|
||||
// Add event listeners for power, notification, and BreezeWiki setting toggles
|
||||
document.getElementById('powerButton').addEventListener('change', function () {
|
||||
chrome.storage.sync.get({ 'power': 'on' }, function (item) {
|
||||
if (item.power === 'on') {
|
||||
setPower('off');
|
||||
} else {
|
||||
setPower('on');
|
||||
}
|
||||
});
|
||||
});
|
||||
document.getElementById('notificationsButton').addEventListener('change', function () {
|
||||
chrome.storage.sync.get({ 'notifications': 'on' }, function (item) {
|
||||
if (item.notifications === 'on') {
|
||||
setNotifications('off');
|
||||
} else {
|
||||
setNotifications('on');
|
||||
}
|
||||
});
|
||||
});
|
||||
document.getElementById('breezewikiButton').addEventListener('change', function () {
|
||||
chrome.storage.sync.get({ 'breezewiki': 'off' }, function (item) {
|
||||
if (item.breezewiki === 'on') {
|
||||
setBreezeWiki('off');
|
||||
} else {
|
||||
setBreezeWiki('on');
|
||||
}
|
||||
});
|
||||
});
|
||||
var breezewikiHostSelect = document.getElementById("breezewikiHostSelect");
|
||||
breezewikiHostSelect.addEventListener('change', function () {
|
||||
chrome.storage.sync.set({ 'breezewikiHost': breezewikiHostSelect.value });
|
||||
});
|
||||
|
||||
// Get and display stat counts
|
||||
chrome.storage.sync.get({ 'countAlerts': 0 }, function (item) {
|
||||
var key = Object.keys(item)[0];
|
||||
chrome.storage.sync.set({ 'countAlerts': item[key] });
|
||||
document.getElementById('countAlerts').innerHTML = item[key];
|
||||
});
|
||||
chrome.storage.sync.get({ 'countRedirects': 0 }, function (item) {
|
||||
var key = Object.keys(item)[0];
|
||||
chrome.storage.sync.set({ 'countRedirects': item[key] });
|
||||
document.getElementById('countRedirects').innerHTML = item[key];
|
||||
});
|
||||
chrome.storage.sync.get({ 'countSearchFilters': 0 }, function (item) {
|
||||
var key = Object.keys(item)[0];
|
||||
chrome.storage.sync.set({ 'countSearchFilters': item[key] });
|
||||
document.getElementById('countSearchFilters').innerHTML = item[key];
|
||||
});
|
||||
});
|