Support for different color schemes

This commit is contained in:
shinigami-eyes 2019-07-17 23:35:00 +02:00
parent e616f23e4c
commit 116395766e
13 changed files with 264 additions and 24 deletions

View File

@ -3,5 +3,6 @@
"extension/background.js": true, "extension/background.js": true,
"extension/content.js": true, "extension/content.js": true,
"extension/help.js": true, "extension/help.js": true,
"extension/options.js": true,
} }
} }

View File

@ -258,8 +258,9 @@ var overrides: LabelMap = null;
var accepted = false; var accepted = false;
var installationId: string = null; var installationId: string = null;
var theme: string = '';
browser.storage.local.get(['overrides', 'accepted', 'installationId'], v => { browser.storage.local.get(['overrides', 'accepted', 'installationId', 'theme'], v => {
if (!v.installationId) { if (!v.installationId) {
installationId = (Math.random() + '.' + Math.random() + '.' + Math.random()).replace(/\./g, ''); installationId = (Math.random() + '.' + Math.random() + '.' + Math.random()).replace(/\./g, '');
browser.storage.local.set({ installationId: installationId }); browser.storage.local.set({ installationId: installationId });
@ -269,6 +270,7 @@ browser.storage.local.get(['overrides', 'accepted', 'installationId'], v => {
accepted = v.accepted accepted = v.accepted
overrides = v.overrides || {} overrides = v.overrides || {}
theme = v.theme;
const migration = overrides[MIGRATION] || 0; const migration = overrides[MIGRATION] || 0;
if (migration < CURRENT_VERSION) { if (migration < CURRENT_VERSION) {
@ -312,13 +314,26 @@ async function loadBloomFilter(name: LabelKind) {
browser.runtime.onMessage.addListener<ShinigamiEyesMessage, ShinigamiEyesMessage | LabelMap>((message, sender, sendResponse) => { browser.runtime.onMessage.addListener<ShinigamiEyesMessage, ShinigamiEyesMessage | LabelMap>((message, sender, sendResponse) => {
if (message.setTheme) {
theme = message.setTheme;
browser.storage.local.set({ theme: message.setTheme });
chrome.tabs.query({}, function (tabs) {
for (var i = 0; i < tabs.length; ++i) {
try {
browser.tabs.sendMessage(tabs[i].id, <ShinigamiEyesCommand>{ updateAllLabels: true });
} catch (e) { }
}
});
}
if (message.acceptClicked !== undefined) { if (message.acceptClicked !== undefined) {
accepted = message.acceptClicked; accepted = message.acceptClicked;
browser.storage.local.set({ accepted: accepted }); browser.storage.local.set({ accepted: accepted });
browser.tabs.remove(sender.tab.id);
if (accepted && uncommittedResponse) if (accepted && uncommittedResponse)
saveLabel(uncommittedResponse) saveLabel(uncommittedResponse)
uncommittedResponse = null; uncommittedResponse = null;
}
if (message.closeCallingTab) {
browser.tabs.remove(sender.tab.id);
return; return;
} }
const response: LabelMap = {}; const response: LabelMap = {};
@ -340,6 +355,7 @@ browser.runtime.onMessage.addListener<ShinigamiEyesMessage, ShinigamiEyesMessage
if (bloomFilter.test(id)) response[id] = bloomFilter.name; if (bloomFilter.test(id)) response[id] = bloomFilter.name;
} }
} }
response[':theme'] = <any>theme;
sendResponse(response); sendResponse(response);
}); });
@ -373,6 +389,8 @@ function createContextMenu(text: string, id: ContextMenuCommand) {
createContextMenu('Mark as anti-trans', 'mark-transphobic'); createContextMenu('Mark as anti-trans', 'mark-transphobic');
createContextMenu('Mark as t-friendly', 'mark-t-friendly'); createContextMenu('Mark as t-friendly', 'mark-t-friendly');
createContextMenu('Clear', 'mark-none'); createContextMenu('Clear', 'mark-none');
browser.contextMenus.create({ type: 'separator' });
createContextMenu('Settings', 'options');
createContextMenu('Help', 'help'); createContextMenu('Help', 'help');
var uncommittedResponse: ShinigamiEyesSubmission = null; var uncommittedResponse: ShinigamiEyesSubmission = null;
@ -440,12 +458,21 @@ function openHelp() {
} }
function openOptions() {
browser.tabs.create({
url: browser.extension.getURL('options.html')
})
}
browser.contextMenus.onClicked.addListener(function (info, tab) { browser.contextMenus.onClicked.addListener(function (info, tab) {
if (info.menuItemId == 'help') { if (info.menuItemId == 'help') {
openHelp(); openHelp();
return; return;
} }
if (info.menuItemId == 'options') {
openOptions();
return;
}
const tabId = tab.id; const tabId = tab.id;
const frameId = info.frameId; const frameId = info.frameId;

View File

@ -1,5 +1,25 @@
.assigned-label-transphobic, a.assigned-label-transphobic { color: #991515 !important; } body {
.assigned-label-t-friendly, a.assigned-label-t-friendly { color: #77B91E !important; } --ShinigamiEyesTFriendly: #77B91E;
--ShinigamiEyesTransphobic: #991515;
}
.shinigami-eyes-theme-green-red-max {
--ShinigamiEyesTFriendly: #00FF00;
--ShinigamiEyesTransphobic: #FF0000;
}
.shinigami-eyes-theme-purple-yellow {
--ShinigamiEyesTFriendly: rgb(153, 0, 255);
--ShinigamiEyesTransphobic: rgb(179, 152, 0);
}
.shinigami-eyes-theme-cyan-orange {
--ShinigamiEyesTFriendly: rgb(98, 161, 197);
--ShinigamiEyesTransphobic: #FB6A4A;
}
.assigned-label-transphobic, a.assigned-label-transphobic { color: var(--ShinigamiEyesTransphobic) !important; }
.assigned-label-t-friendly, a.assigned-label-t-friendly { color: var(--ShinigamiEyesTFriendly) !important; }
.has-assigned-label * { color: inherit !important; } .has-assigned-label * { color: inherit !important; }
.shinigami-eyes-debug-snippet-highlight { .shinigami-eyes-debug-snippet-highlight {

View File

@ -26,13 +26,13 @@ function fixupSiteStyles() {
`); `);
} else if (domainIs(hostname, 'tumblr.com')) { } else if (domainIs(hostname, 'tumblr.com')) {
addStyleSheet(` addStyleSheet(`
.assigned-label-transphobic { outline: 2px solid #991515 !important; } .assigned-label-transphobic { outline: 2px solid var(--ShinigamiEyesTransphobic) !important; }
.assigned-label-t-friendly { outline: 1px solid #77B91E !important; } .assigned-label-t-friendly { outline: 1px solid var(--ShinigamiEyesTFriendly) !important; }
`); `);
} else if (hostname.indexOf('wiki') != -1) { } else if (hostname.indexOf('wiki') != -1) {
addStyleSheet(` addStyleSheet(`
.assigned-label-transphobic { outline: 1px solid #991515 !important; } .assigned-label-transphobic { outline: 1px solid var(--ShinigamiEyesTransphobic) !important; }
.assigned-label-t-friendly { outline: 1px solid #77B91E !important; } .assigned-label-t-friendly { outline: 1px solid var(--ShinigamiEyesTFriendly) !important; }
`); `);
} else if (hostname == 'twitter.com') { } else if (hostname == 'twitter.com') {
myself = getIdentifier(<HTMLAnchorElement>document.querySelector('.DashUserDropdown-userInfo a')); myself = getIdentifier(<HTMLAnchorElement>document.querySelector('.DashUserDropdown-userInfo a'));
@ -167,6 +167,7 @@ function updateAllLabels(refresh?: boolean) {
} }
var knownLabels: LabelMap = {}; var knownLabels: LabelMap = {};
var currentlyAppliedTheme = '_none_';
var labelsToSolve: LabelToSolve[] = []; var labelsToSolve: LabelToSolve[] = [];
function solvePendingLabels() { function solvePendingLabels() {
@ -175,8 +176,14 @@ function solvePendingLabels() {
var tosolve = labelsToSolve; var tosolve = labelsToSolve;
labelsToSolve = []; labelsToSolve = [];
browser.runtime.sendMessage<ShinigamiEyesCommand, LabelMap>({ ids: uniqueIdentifiers, myself: <string>myself }, (response: LabelMap) => { browser.runtime.sendMessage<ShinigamiEyesCommand, LabelMap>({ ids: uniqueIdentifiers, myself: <string>myself }, (response: LabelMap) => {
const theme = response[':theme'];
if (theme != currentlyAppliedTheme) {
if (currentlyAppliedTheme) document.body.classList.remove('shinigami-eyes-theme-' + currentlyAppliedTheme);
if (theme) document.body.classList.add('shinigami-eyes-theme-' + theme);
currentlyAppliedTheme = theme;
}
for (const item of tosolve) { for (const item of tosolve) {
var label = response[item.identifier]; const label = response[item.identifier];
knownLabels[item.identifier] = label || ''; knownLabels[item.identifier] = label || '';
applyLabel(item.element, item.identifier); applyLabel(item.element, item.identifier);
} }

View File

@ -30,10 +30,12 @@ interface ShinigamiEyesCommand {
myself?: string myself?: string
ids?: string[] ids?: string[]
updateAllLabels?: boolean updateAllLabels?: boolean
closeCallingTab?: boolean
setTheme?: string
} }
type LabelMap = { [identifier: string]: LabelKind }; type LabelMap = { [identifier: string]: LabelKind };
interface ShinigamiEyesMessage extends ShinigamiEyesSubmission, ShinigamiEyesCommand { interface ShinigamiEyesMessage extends ShinigamiEyesSubmission, ShinigamiEyesCommand {
} }
type ContextMenuCommand = 'mark-t-friendly' | 'mark-transphobic' | 'mark-none' | 'help'; type ContextMenuCommand = 'mark-t-friendly' | 'mark-transphobic' | 'mark-none' | 'help' | 'options';

View File

@ -7,9 +7,10 @@ body {
padding: 0; padding: 0;
} }
.assigned-label-unknown {
.assigned-label-transphobic { color: #991515 !important; } color: rgb(56, 88, 152); /* Facebook default link color */
.assigned-label-t-friendly { color: #77B91E !important; } cursor: help;
}
h1 { h1 {
font-size: 40pt; font-size: 40pt;
@ -52,9 +53,8 @@ section {
.section-faq { .section-faq {
background-color: rgb(213, 183, 255); background-color: rgb(213, 183, 255);
} }
.section-guidelines { .section-guidelines, .section-options {
background-color: white; background-color: white;
/*background-color: rgb(190, 245, 151);*/
} }
.section-footer { .section-footer {
@ -123,4 +123,24 @@ section {
font-size: 10pt; font-size: 10pt;
} }
.website-checkbox {
display: block;
user-select: none;
}
.website-checkbox i {
color: gray;
}
#theme-settings label {
user-select: none;
font-weight: bold;
display: block;
}
#save-button {
font-weight: bold;
background-color: rgb(108, 212, 76);
}
label, button {
cursor: pointer;
}

View File

@ -4,6 +4,7 @@
<head> <head>
<title>Shinigami Eyes</title> <title>Shinigami Eyes</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link href="content.css" rel="stylesheet">
<link href="help.css" rel="stylesheet"> <link href="help.css" rel="stylesheet">
<meta charset="utf-8"> <meta charset="utf-8">
<style> <style>

View File

@ -1,8 +1,8 @@
var browser: Browser = browser || chrome; var browser: Browser = browser || chrome;
document.getElementById('cancelButton').addEventListener('click', () => { document.getElementById('cancelButton').addEventListener('click', () => {
browser.runtime.sendMessage({ acceptClicked: false }, () => { }); browser.runtime.sendMessage(<ShinigamiEyesCommand>{ acceptClicked: false, closeCallingTab: true }, () => { });
}) })
document.getElementById('acceptButton').addEventListener('click', () => { document.getElementById('acceptButton').addEventListener('click', () => {
browser.runtime.sendMessage({ acceptClicked: true }, () => { }); browser.runtime.sendMessage(<ShinigamiEyesCommand>{ acceptClicked: true, closeCallingTab: true }, () => { });
}) })

View File

@ -63,7 +63,7 @@
] ]
}, },
"options_ui": { "options_ui": {
"page": "help.html", "page": "options.html",
"open_in_tab": true "open_in_tab": true
}, },
"permissions": [ "permissions": [

97
extension/options.html Normal file
View File

@ -0,0 +1,97 @@
<!doctype html>
<html>
<head>
<title>Settings - Shinigami Eyes</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="help.css" rel="stylesheet">
<link href="content.css" rel="stylesheet">
<meta charset="utf-8">
<style>
button {
margin-top: 10px;
padding: 10px 15px;
font-size: 12pt;
}
.section-top {
background-color: rgb(213, 183, 255);
}
.section-top h2 {
margin: 5px !important;
}
.section-confirmation {
padding-bottom: 70px;
padding-top: 40px;
}
.footer {
margin-top: 80px;
font-size: 10pt;
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>
<body>
<div class="page-content">
<section class="section-top">
<div class="section-inner">
<h2>Shinigami Eyes settings</h2>
</div>
</section>
<section class="section-options">
<div class="section-inner">
<h3>Colors</h3>
<div id="theme-settings">
</div>
<!--
<h3>Websites</h3>
Color users and pages on the following websites:
<br><br>
<label class="website-checkbox"><input type="checkbox" data-site="disqus.com">Disqus <i>(embedded
comments)</i></label>
<label class="website-checkbox"><input type="checkbox" data-site="facebook.com">Facebook</label>
<label class="website-checkbox"><input type="checkbox" data-site="medium.com">Medium</label>
<label class="website-checkbox"><input type="checkbox" data-site="rationalwiki.org">RationalWiki
<i>(topics)</i></label>
<label class="website-checkbox"><input type="checkbox" data-site="reddit.com">Reddit</i></label>
<label class="website-checkbox"><input type="checkbox" data-site="search-engines">Google, Bing,
DuckDuckGo <i>(search results)</i></label>
<label class="website-checkbox"><input type="checkbox" data-site="tumblr.com">Tumblr</label>
<label class="website-checkbox"><input type="checkbox" data-site="twitter.com">Twitter</label>
<label class="website-checkbox"><input type="checkbox" data-site="wikipedia.org">Wikipedia
<i>(topics)</i></label>
<label class="website-checkbox"><input type="checkbox" data-site="youtube.com">YouTube</label>
-->
<h3>Guidelines</h3>
Go to <a href="help.html" target="_blank">Guidelines</a> for an overview of what kind of content should be marked one
way or the other.
<br><br>
<button id="save-button">Save</button>
<button id="cancel-button">Cancel</button>
<br><br><br>
</div>
</section>
<section class="section-footer">
Don't forget to follow us on <a href="https://twitter.com/ShinigamiEyesT">Twitter</a> or <a
href="https://www.facebook.com/ShinigamiEyesT">Facebook</a>!
</section>
</div>
<script src="options.js"></script>
</body>
</html>

27
extension/options.js Normal file
View File

@ -0,0 +1,27 @@
var browser = browser || chrome;
browser.storage.local.get(['theme'], obj => {
var theme = obj.theme || 'green-red';
var themeSettingsContainer = document.getElementById('theme-settings');
[
'green-red',
'purple-yellow',
'cyan-orange',
].map(x => {
themeSettingsContainer.insertAdjacentHTML('beforeend', `
<label class="shinigami-eyes-theme shinigami-eyes-theme-${x}">
<input type="radio" name="selected-theme" ${x == theme ? 'checked' : ''} data-theme="${x}">
<span class="assigned-label-t-friendly">T-Friendly</span>,
<span class="assigned-label-transphobic">Anti-trans</span>,
<span class="assigned-label-unknown" title="Using Facebook as an example for unknown links.">Unknown (fb)</span>
</label>
`);
});
});
document.getElementById('save-button').addEventListener('click', async () => {
var theme = [...document.querySelectorAll('.shinigami-eyes-theme input')]
.filter(x => x.checked)[0].dataset.theme;
browser.runtime.sendMessage({ closeCallingTab: true, setTheme: theme }, () => { });
});
document.getElementById('cancel-button').addEventListener('click', async () => {
browser.runtime.sendMessage({ closeCallingTab: true }, () => { });
});

36
extension/options.ts Normal file
View File

@ -0,0 +1,36 @@
var browser: Browser = browser || chrome;
browser.storage.local.get(['theme'], obj => {
var theme: string = obj.theme || 'green-red';
var themeSettingsContainer = document.getElementById('theme-settings');
[
'green-red',
'purple-yellow',
'cyan-orange',
].map(x => {
themeSettingsContainer.insertAdjacentHTML('beforeend', `
<label class="shinigami-eyes-theme shinigami-eyes-theme-${x}">
<input type="radio" name="selected-theme" ${x == theme ? 'checked' : ''} data-theme="${x}">
<span class="assigned-label-t-friendly">T-Friendly</span>,
<span class="assigned-label-transphobic">Anti-trans</span>,
<span class="assigned-label-unknown" title="Using Facebook as an example for unknown links.">Unknown (fb)</span>
</label>
`);
});
});
document.getElementById('save-button').addEventListener('click', async () => {
var theme = (<HTMLInputElement>
[...document.querySelectorAll('.shinigami-eyes-theme input')]
.filter(x => (<HTMLInputElement>x).checked)[0]
).dataset.theme;
browser.runtime.sendMessage(<ShinigamiEyesCommand>{ closeCallingTab: true, setTheme: theme }, () => { });
});
document.getElementById('cancel-button').addEventListener('click', async () => {
browser.runtime.sendMessage(<ShinigamiEyesCommand>{ closeCallingTab: true }, () => { });
});

View File

@ -18,16 +18,18 @@ declare type Browser = {
create(options: { create(options: {
url: string url: string
}): void }): void
query(query: {}, callback: (tabs: { id: number }[]) => void): void;
} }
extension: { extension: {
getURL(relativeUrl: string): string getURL(relativeUrl: string): string
} }
contextMenus: { contextMenus: {
create(options: { create(options: {
id: string id?: string
title: string title?: string
contexts: 'link'[] contexts?: 'link'[]
targetUrlPatterns: string[] targetUrlPatterns?: string[]
type?: 'normal' | 'separator'
}): void }): void
onClicked: { onClicked: {
addListener(listener: (info: { addListener(listener: (info: {
@ -41,12 +43,12 @@ declare type Browser = {
} }
} }
type MessageSender = { type MessageSender = {
tab?: {id: number}; tab?: { id: number };
frameId?: number; frameId?: number;
id?: string; id?: string;
url?: string; url?: string;
tlsChannelId?: string; tlsChannelId?: string;
}; };
declare type BrowserStorage = { declare type BrowserStorage = {
get(names: string[], callback: (obj: any) => void): void get(names: string[], callback: (obj: any) => void): void
set(obj: { [name: string]: any }): void; set(obj: { [name: string]: any }): void;