safer-indie-wiki-buddy/scripts/content-banners.js

313 lines
15 KiB
JavaScript

const breezewikiRegex = /breezewiki\.com$|antifandom\.com$|bw\.artemislena\.eu$|breezewiki\.catsarch\.com$|breezewiki\.esmailelbob\.xyz$|breezewiki\.frontendfriendly\.xyz$|bw\.hamstro\.dev$|breeze\.hostux\.net$|breezewiki\.hyperreal\.coffee$|breeze\.mint\.lgbt$|breezewiki\.nadeko\.net$|nerd\.whatever\.social$|breeze\.nohost\.network$|z\.opnxng\.com$|bw\.projectsegfau\.lt$|breezewiki\.pussthecat\.org$|bw\.vern\.cc$|breeze\.whateveritworks\.org$|breezewiki\.woodland\.cafe$/;
const currentURL = new URL(document.location);
function outputBannerContainer() {
if (!document.getElementById('indie-wiki-banner-container')) {
const container = document.createElement('div');
container.id = 'indie-wiki-banner-container';
let containerExit = document.createElement('div');
containerExit.classList.add('indie-wiki-banner-exit');
container.appendChild(containerExit);
containerExit.textContent = '✕';
containerExit.onclick = function () { this.parentElement.remove(); };
document.body.insertAdjacentElement('beforeBegin', container);
}
}
function processBreezeWikiBanner(storage) {
// Output BreezeWiki banner, if enabled:
if (storage.breezewiki === 'banner' && currentURL.toString().includes('.fandom.com/wiki/')) {
// Extract article from URL
const subdomain = currentURL.hostname.split(".")[0];
const article = currentURL.toString().split('fandom.com/wiki/')[1].replaceAll('%20', '_');
breezewikiHost = '';
if (!(storage.breezewikiHost ?? null)) {
fetch('https://bw.getindie.wiki/instances.json')
.then((response) => {
if (response.ok) {
return response.json();
}
throw new Error('Indie Wiki Buddy failed to get BreezeWiki data.');
}).then((breezewikiHosts) => {
breezewikiHosts = breezewikiHosts.filter(host =>
extensionAPI.runtime.getManifest().version.localeCompare(host.iwb_version,
undefined,
{ numeric: true, sensitivity: 'base' }
) >= 0
);
// Check if BreezeWiki's main site is available
let breezewikiMain = breezewikiHosts.filter(host => host.instance === 'https://breezewiki.com');
if (breezewikiMain.length > 0) {
extensionAPI.storage.sync.set({ 'breezewikiHost': breezewikiMain[0].instance });
} else {
// If BreezeWiki.com is not available, set to a random mirror
try {
extensionAPI.storage.sync.set({ 'breezewikiHost': breezewikiHosts[Math.floor(Math.random() * breezewikiHosts.length)].instance });
} catch (e) {
console.log('Indie Wiki Buddy failed to get BreezeWiki data: ' + e);
}
}
extensionAPI.storage.sync.set({ 'breezewikiHostOptions': breezewikiHosts });
extensionAPI.storage.sync.set({ 'breezewikiHostFetchTimestamp': Date.now() });
breezewikiHost = host;
}).catch((e) => {
console.log('Indie Wiki Buddy failed to get BreezeWiki data: ' + e);
extensionAPI.storage.sync.set({ 'breezewikiHost': 'https://breezewiki.com' });
});
} else {
if (storage.breezewikiHost === 'CUSTOM') {
breezewikiHost = storage.breezewikiCustomHost || 'https://breezewiki.com';
} else {
breezewikiHost = storage.breezewikiHost;
}
}
displayBreezewikiBanner(breezewikiHost + '/' + subdomain + '/wiki/' + article);
}
}
function displayBreezewikiBanner(newUrl) {
// Output banner
let banner = document.createElement('div');
banner.id = 'indie-wiki-banner-bw';
banner.classList.add('indie-wiki-banner');
// Output main banner text
let bannerText = document.createElement('span');
let bannerWikiLink = document.createElement('a');
bannerWikiLink.classList.add('indie-wiki-banner-link');
bannerWikiLink.href = newUrl;
bannerWikiLink.textContent = extensionAPI.i18n.getMessage('bannerBreezeWiki');
bannerText.appendChild(bannerWikiLink);
banner.appendChild(bannerText);
// Function to insert banner into DOM before body element
function addBannerToDOM() {
// Check if document is in a ready state
if (document.readyState === 'interactive' || document.readyState === 'complete') {
// Add banner container if not already in doc
outputBannerContainer();
// Ensure banner isn't already outputted
if (!document.querySelector(':root > #indie-wiki-banner-bw')) {
document.getElementById('indie-wiki-banner-container').appendChild(banner);
}
// Remove readystatechange listener
document.removeEventListener('readystatechange', addBannerToDOM);
}
}
document.addEventListener('readystatechange', addBannerToDOM);
addBannerToDOM();
}
function displayRedirectBanner(newUrl, id, destinationName, destinationLanguage, host, tags, storage) {
// Output banner
let banner = document.createElement('div');
banner.id = 'indie-wiki-banner-redirect';
banner.classList.add('indie-wiki-banner');
// Output control links container
let bannerControls = document.createElement('div');
bannerControls.classList.add('indie-wiki-banner-controls');
banner.appendChild(bannerControls);
// Output "restore banner" link
let bannerRestoreLink = document.createElement('div');
bannerRestoreLink.classList.add('indie-wiki-banner-restore');
bannerRestoreLink.classList.add('indie-wiki-banner-link');
bannerRestoreLink.classList.add('indie-wiki-banner-link-small');
bannerRestoreLink.classList.add('indie-wiki-banner-hidden');
bannerRestoreLink.textContent = '⎌ ' + extensionAPI.i18n.getMessage('bannerRestore');
bannerControls.appendChild(bannerRestoreLink);
bannerRestoreLink.onclick = function (e) {
extensionAPI.storage.sync.get({ 'wikiSettings': {} }, async (response) => {
let wikiSettings = await commonFunctionDecompressJSON(response.wikiSettings);
wikiSettings[id] = 'alert';
extensionAPI.storage.sync.set({ 'wikiSettings': await commonFunctionCompressJSON(wikiSettings) });
e.target.textContent = '✓ ' + extensionAPI.i18n.getMessage('bannerRestoreDone');
e.target.classList.add('indie-wiki-banner-disabled');
bannerControls.querySelector('.indie-wiki-banner-redirect').textContent = '↪ ' + extensionAPI.i18n.getMessage('bannerRedirect');
bannerControls.querySelector('.indie-wiki-banner-redirect').classList.remove('indie-wiki-banner-disabled');
bannerControls.querySelector('.indie-wiki-banner-disable').textContent = '✕ ' + extensionAPI.i18n.getMessage('bannerDisable');
bannerControls.querySelector('.indie-wiki-banner-disable').classList.remove('indie-wiki-banner-hidden');
bannerControls.querySelector('.indie-wiki-banner-disable').classList.remove('indie-wiki-banner-disabled');
});
}
// Output "disable banner" link
let bannerDisableLink = document.createElement('div');
bannerDisableLink.classList.add('indie-wiki-banner-disable');
bannerDisableLink.classList.add('indie-wiki-banner-link');
bannerDisableLink.classList.add('indie-wiki-banner-link-small');
bannerDisableLink.textContent = '✕ ' + extensionAPI.i18n.getMessage('bannerDisable');
bannerControls.appendChild(bannerDisableLink);
bannerDisableLink.onclick = function (e) {
extensionAPI.storage.sync.get({ 'wikiSettings': {} }, async (response) => {
let wikiSettings = await commonFunctionDecompressJSON(response.wikiSettings);
wikiSettings[id] = 'disabled';
extensionAPI.storage.sync.set({ 'wikiSettings': await commonFunctionCompressJSON(wikiSettings) });
e.target.textContent = '✓ ' + extensionAPI.i18n.getMessage('bannerDisableDone');
e.target.classList.add('indie-wiki-banner-disabled');
bannerControls.querySelector('.indie-wiki-banner-restore').textContent = '⎌ ' + extensionAPI.i18n.getMessage('bannerRestore');
bannerControls.querySelector('.indie-wiki-banner-restore').classList.remove('indie-wiki-banner-hidden');
bannerControls.querySelector('.indie-wiki-banner-restore').classList.remove('indie-wiki-banner-disabled');
});
}
// Output "auto redirect" link
let bannerRedirectLink = document.createElement('div');
bannerRedirectLink.classList.add('indie-wiki-banner-redirect');
bannerRedirectLink.classList.add('indie-wiki-banner-link');
bannerRedirectLink.classList.add('indie-wiki-banner-link-small');
bannerRedirectLink.textContent = '↪ ' + extensionAPI.i18n.getMessage('bannerRedirect');
bannerControls.appendChild(bannerRedirectLink);
bannerRedirectLink.onclick = function (e) {
extensionAPI.storage.sync.get({ 'wikiSettings': {} }, async (response) => {
let wikiSettings = await commonFunctionDecompressJSON(response.wikiSettings);
wikiSettings[id] = 'redirect';
extensionAPI.storage.sync.set({ 'wikiSettings': await commonFunctionCompressJSON(wikiSettings) });
e.target.textContent = '✓ ' + extensionAPI.i18n.getMessage('bannerRedirectDone');
e.target.classList.add('indie-wiki-banner-disabled');
bannerControls.querySelector('.indie-wiki-banner-disable').classList.add('indie-wiki-banner-hidden');
bannerControls.querySelector('.indie-wiki-banner-restore').textContent = '⎌ ' + extensionAPI.i18n.getMessage('bannerRestore');
bannerControls.querySelector('.indie-wiki-banner-restore').classList.remove('indie-wiki-banner-hidden');
bannerControls.querySelector('.indie-wiki-banner-restore').classList.remove('indie-wiki-banner-disabled');
});
}
// Output main banner text
let bannerText = document.createElement('span');
bannerText.classList.add('indie-wiki-banner-big-text');
banner.appendChild(bannerText);
// Build descriptors
let wikiDescriptor = extensionAPI.i18n.getMessage('bannerDescriptorIndependent');
let hostDescriptor = '';
if (host) {
hostDescriptor = extensionAPI.i18n.getMessage('bannerHost', host);
if (tags.includes('official')) {
wikiDescriptor = extensionAPI.i18n.getMessage('bannerDescriptorOfficial');
} else {
wikiDescriptor = extensionAPI.i18n.getMessage('bannerDescriptorWiki');
}
} else if (tags.includes('official')) {
wikiDescriptor = extensionAPI.i18n.getMessage('bannerDescriptorIndependentOfficial');
}
if (destinationLanguage === 'EN' && location.href.match(/fandom\.com\/[a-z]{2}\/wiki\//)) {
bannerText.textContent = extensionAPI.i18n.getMessage('bannerText', [
wikiDescriptor,
hostDescriptor,
extensionAPI.i18n.getMessage('bannerLanguageEnglish')
]);
} else {
bannerText.textContent = extensionAPI.i18n.getMessage('bannerText', [wikiDescriptor, hostDescriptor, '']);
}
let bannerWikiLink = document.createElement('a');
bannerWikiLink.classList.add('indie-wiki-banner-link');
bannerText.appendChild(bannerWikiLink);
bannerWikiLink.href = newUrl;
bannerWikiLink.textContent = extensionAPI.i18n.getMessage('bannerVisit', [destinationName]) + ' →';
// Function to insert banner into DOM before body element
function addBannerToDOM() {
// Check if document is in a ready state
if (document.readyState === 'interactive' || document.readyState === 'complete') {
// Add banner container if not already in doc
outputBannerContainer();
// Ensure banner isn't already outputted
if (!document.querySelector(':root > #indie-wiki-banner-redirect')) {
document.getElementById('indie-wiki-banner-container').appendChild(banner);
// Increment banner count
if (storage.breezewiki === 'on') {
if (currentURL.hostname.match(breezewikiRegex) || (storage.breezewikiHost === 'CUSTOM' && storage.breezewikiCustomHost?.includes(currentURL.hostname))) {
extensionAPI.storage.sync.set({ 'countAlerts': (storage.countAlerts ?? 0) + 1 });
}
} else {
extensionAPI.storage.sync.set({ 'countAlerts': (storage.countAlerts ?? 0) + 1 });
}
// Hide duplicative indie wiki notice on BreezeWiki instances
if (currentURL.hostname.match(breezewikiRegex)) {
const bwIndieNotice = document.querySelector('aside.niwa__notice');
if (bwIndieNotice) {
bwIndieNotice.style.display = 'none';
}
}
}
// Remove readystatechange listener
document.removeEventListener('readystatechange', addBannerToDOM);
}
}
document.addEventListener('readystatechange', addBannerToDOM);
addBannerToDOM();
}
function main() {
extensionAPI.runtime.sendMessage({ action: 'getStorage' }, (storage) => {
// Check if extension is on:
if ((storage.power ?? 'on') === 'on') {
// Check if there is a pathname, to ensure we're looking at an article
if (currentURL.pathname.length > 1) {
processBreezeWikiBanner(storage);
let origin = currentURL.toString();
// If on a BreezeWiki site, convert to Fandom link to match with our list of wikis:
if (currentURL.hostname.match(breezewikiRegex) || (storage.breezewikiHost === 'CUSTOM' && storage.breezewikiCustomHost?.includes(currentURL.hostname))) {
origin = String(currentURL.pathname).split('/')[1] + '.fandom.com/wiki/';
if (currentURL.search.includes('?q=')) {
origin = 'https://' + origin + currentURL.search.substring(3);
} else {
origin = 'https://' + origin + currentURL.pathname.split('/')[3];
}
}
commonFunctionGetSiteDataByOrigin().then(async sites => {
let crossLanguageSetting = storage.crossLanguage || 'off';
let matchingSite = await commonFunctionFindMatchingSite(origin, crossLanguageSetting);
if (matchingSite) {
// Get user's settings for the wiki
let id = matchingSite['id'];
let siteSetting = 'alert';
let wikiSettings = await commonFunctionDecompressJSON(storage.wikiSettings || {});
if (wikiSettings[id]) {
siteSetting = wikiSettings[id];
} else if (storage.defaultWikiAction) {
siteSetting = storage.defaultWikiAction;
}
// Notify if enabled for the wiki:
if (siteSetting === 'alert') {
let newURL = commonFunctionGetNewURL(origin, matchingSite);
// When head elem is loaded, notify that another wiki is available
const docObserver = new MutationObserver((mutations, mutationInstance) => {
const headElement = document.querySelector('head');
if (headElement) {
try {
displayRedirectBanner(newURL, matchingSite['id'], matchingSite['destination'], matchingSite['language'], matchingSite['destination_host'], matchingSite['tags'], storage);
} finally {
mutationInstance.disconnect();
}
}
});
docObserver.observe(document, {
childList: true,
subtree: true
});
}
}
});
}
}
});
}
main();