Fix more type errors, refactor a few things

This commit is contained in:
shinigami-eyes 2019-06-29 19:47:05 +02:00
parent db717cfe15
commit da80996a8c
5 changed files with 263 additions and 283 deletions

View File

@ -3,7 +3,7 @@
const PENDING_SUBMISSIONS = ':PENDING_SUBMISSIONS' const PENDING_SUBMISSIONS = ':PENDING_SUBMISSIONS'
const MIGRATION = ':MIGRATION' const MIGRATION = ':MIGRATION'
const CURRENT_VERSION = 100018; const CURRENT_VERSION = 100019;
// If a user labels one of these URLs, they're making a mistake. Ignore the label. // If a user labels one of these URLs, they're making a mistake. Ignore the label.
// This list includes: // This list includes:
@ -11,7 +11,7 @@ const CURRENT_VERSION = 100018;
// * System pages of supported social networks // * System pages of supported social networks
// * Archival and link shortening sites. // * Archival and link shortening sites.
// * Reddit bots. // * Reddit bots.
var badIdentifiersArray = [ const badIdentifiersArray = [
'archive.is', 'archive.is',
'archive.org', 'archive.org',
'assets.tumblr.com', 'assets.tumblr.com',
@ -232,12 +232,12 @@ var badIdentifiersArray = [
'youtube.com/redirect', 'youtube.com/redirect',
'youtube.com/watch', 'youtube.com/watch',
]; ];
var badIdentifiers : {[id: string]: true} = {}; const badIdentifiers : {[id: string]: true} = {};
badIdentifiersArray.forEach(x => badIdentifiers[x] = true); badIdentifiersArray.forEach(x => badIdentifiers[x] = true);
var lastSubmissionError = null; var lastSubmissionError : string = null;
var needsInfiniteResubmissionWorkaround = [ const needsInfiniteResubmissionWorkaround = [
'046775268347','094745034139','059025030493','016970595453','016488055088','028573603939', '046775268347','094745034139','059025030493','016970595453','016488055088','028573603939',
'047702135398','035965787127','069722626647','044482561296','068530257405','071378971311', '047702135398','035965787127','069722626647','044482561296','068530257405','071378971311',
'050784255720','074169481269','001621982155','014636303566','016313013148','051923868290', '050784255720','074169481269','001621982155','014636303566','016313013148','051923868290',
@ -246,10 +246,10 @@ var needsInfiniteResubmissionWorkaround = [
'040689448048','048816243838','018152001078','059285890303','073205501344','096068619182' '040689448048','048816243838','018152001078','059285890303','073205501344','096068619182'
] ]
var overrides = null; var overrides : LabelMap = null;
var accepted = false; var accepted = false;
var installationId = null; var installationId : string = null;
browser.storage.local.get(['overrides', 'accepted', 'installationId'], v => { browser.storage.local.get(['overrides', 'accepted', 'installationId'], v => {
if (!v.installationId) { if (!v.installationId) {
@ -262,17 +262,17 @@ browser.storage.local.get(['overrides', 'accepted', 'installationId'], v => {
accepted = v.accepted accepted = v.accepted
overrides = v.overrides || {} overrides = v.overrides || {}
var migration = overrides[MIGRATION] || 0; const migration = overrides[MIGRATION] || 0;
if (migration < CURRENT_VERSION){ if (migration < CURRENT_VERSION){
for(var key of Object.getOwnPropertyNames(overrides)){ for (const key of Object.getOwnPropertyNames(overrides)){
if (key.startsWith(':')) continue; if (key.startsWith(':')) continue;
if (key.startsWith('facebook.com/a.')){ if (key.startsWith('facebook.com/a.')){
delete overrides[key]; delete overrides[key];
continue; continue;
} }
if (key != key.toLowerCase()){ if (key != key.toLowerCase()){
var v = overrides[key]; let v = overrides[key];
delete overrides[key]; delete overrides[key];
overrides[key.toLowerCase()] = v; overrides[key.toLowerCase()] = v;
} }
@ -281,30 +281,29 @@ browser.storage.local.get(['overrides', 'accepted', 'installationId'], v => {
badIdentifiersArray.forEach(x => delete overrides[x]); badIdentifiersArray.forEach(x => delete overrides[x]);
if (needsInfiniteResubmissionWorkaround.indexOf(installationId.substring(0, 12)) != -1) if (needsInfiniteResubmissionWorkaround.indexOf(installationId.substring(0, 12)) != -1)
overrides[PENDING_SUBMISSIONS] = []; overrides[PENDING_SUBMISSIONS] = <any>[];
overrides[MIGRATION] = CURRENT_VERSION; overrides[MIGRATION] = <any>CURRENT_VERSION;
browser.storage.local.set({ overrides: overrides }); browser.storage.local.set({ overrides: overrides });
} }
}) })
const bloomFilters : BloomFilter[] = []; const bloomFilters : BloomFilter[] = [];
function loadBloomFilter(name: string) { async function loadBloomFilter(name: LabelKind) {
var url = browser.extension.getURL('data/' + name + '.dat'); const url = browser.extension.getURL('data/' + name + '.dat');
fetch(url).then(response => { const response = await fetch(url);
response.arrayBuffer().then(arrayBuffer => { const arrayBuffer = await response.arrayBuffer();
var array = new Uint32Array(arrayBuffer);
var b = new BloomFilter(array, 20); const array = new Uint32Array(arrayBuffer);
const b = new BloomFilter(array, 20);
b.name = name; b.name = name;
bloomFilters.push(b); bloomFilters.push(b);
});
});
} }
browser.runtime.onMessage.addListener((message, sender, sendResponse) => { browser.runtime.onMessage.addListener<ShinigamiEyesMessage, ShinigamiEyesMessage | LabelMap>((message, sender, sendResponse) => {
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 });
@ -314,22 +313,22 @@ browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
uncommittedResponse = null; uncommittedResponse = null;
return; return;
} }
var response = {}; const response : LabelMap = {};
var transphobic = message.myself && bloomFilters.filter(x => x.name == 'transphobic')[0].test(message.myself); const transphobic = message.myself && bloomFilters.filter(x => x.name == 'transphobic')[0].test(message.myself);
for (var id of message.ids) { for (const id of message.ids) {
if (overrides[id] !== undefined) { if (overrides[id] !== undefined) {
response[id] = overrides[id]; response[id] = overrides[id];
continue; continue;
} }
if (transphobic) { if (transphobic) {
if (id == message.myself) continue; if (id == message.myself) continue;
var sum = 0; let sum = 0;
for (var i = 0; i < id.length; i++) { for (let i = 0; i < id.length; i++) {
sum += id.charCodeAt(i); sum += id.charCodeAt(i);
} }
if (sum % 8 != 0) continue; if (sum % 8 != 0) continue;
} }
for (var bloomFilter of bloomFilters) { for (const bloomFilter of bloomFilters) {
if (bloomFilter.test(id)) response[id] = bloomFilter.name; if (bloomFilter.test(id)) response[id] = bloomFilter.name;
} }
} }
@ -368,11 +367,11 @@ createContextMenu('Mark as t-friendly', 'mark-t-friendly');
createContextMenu('Clear', 'mark-none'); createContextMenu('Clear', 'mark-none');
createContextMenu('Help', 'help'); createContextMenu('Help', 'help');
var uncommittedResponse = null; var uncommittedResponse : ShinigamiEyesSubmission = null;
async function submitPendingRatings() { async function submitPendingRatings() {
var submitted = overrides[PENDING_SUBMISSIONS].map(x => x); const submitted = getPendingSubmissions().map(x => x);
var requestBody = { const requestBody = {
installationId: installationId, installationId: installationId,
lastError: lastSubmissionError, lastError: lastSubmissionError,
entries: submitted entries: submitted
@ -380,17 +379,17 @@ async function submitPendingRatings() {
lastSubmissionError = null; lastSubmissionError = null;
console.log('Sending request'); console.log('Sending request');
try { try {
var response = await fetch('https://k5kk18774h.execute-api.us-east-1.amazonaws.com/default/shinigamiEyesSubmission', { const response = await fetch('https://k5kk18774h.execute-api.us-east-1.amazonaws.com/default/shinigamiEyesSubmission', {
body: JSON.stringify(requestBody), body: JSON.stringify(requestBody),
method: 'POST', method: 'POST',
credentials: 'omit', credentials: 'omit',
}); });
if (response.status != 200) throw ('HTTP status: ' + response.status) if (response.status != 200) throw ('HTTP status: ' + response.status)
var result = await response.text(); const result = await response.text();
if (result != 'SUCCESS') throw 'Bad response: ' + ('' + result).substring(0, 20); if (result != 'SUCCESS') throw 'Bad response: ' + ('' + result).substring(0, 20);
overrides[PENDING_SUBMISSIONS] = overrides[PENDING_SUBMISSIONS].filter(x => submitted.indexOf(x) == -1); overrides[PENDING_SUBMISSIONS] = <any>getPendingSubmissions().filter(x => submitted.indexOf(x) == -1);
browser.storage.local.set({ overrides: overrides }); browser.storage.local.set({ overrides: overrides });
} catch(e) { } catch(e) {
lastSubmissionError = '' + e lastSubmissionError = '' + e
@ -398,12 +397,16 @@ async function submitPendingRatings() {
} }
function getPendingSubmissions() : ShinigamiEyesSubmission[]{
return <any>overrides[PENDING_SUBMISSIONS];
}
function saveLabel(response) {
function saveLabel(response: ShinigamiEyesSubmission) {
if (accepted) { if (accepted) {
if (!overrides[PENDING_SUBMISSIONS]) { if (!getPendingSubmissions()) {
overrides[PENDING_SUBMISSIONS] = Object.getOwnPropertyNames(overrides) overrides[PENDING_SUBMISSIONS] = <any>Object.getOwnPropertyNames(overrides)
.map(x => { return { identifier: x, label: overrides[x] } }); .map<ShinigamiEyesSubmission>(x => { return { identifier: x, label: overrides[x] } });
} }
overrides[response.identifier] = response.mark; overrides[response.identifier] = response.mark;
if (response.secondaryIdentifier) if (response.secondaryIdentifier)
@ -411,7 +414,7 @@ function saveLabel(response) {
browser.storage.local.set({ overrides: overrides }); browser.storage.local.set({ overrides: overrides });
response.version = CURRENT_VERSION; response.version = CURRENT_VERSION;
response.submissionId = (Math.random() + '').replace('.', ''); response.submissionId = (Math.random() + '').replace('.', '');
overrides[PENDING_SUBMISSIONS].push(response); getPendingSubmissions().push(response);
submitPendingRatings(); submitPendingRatings();
//console.log(response); //console.log(response);
browser.tabs.sendMessage(response.tabId, { updateAllLabels: true }); browser.tabs.sendMessage(response.tabId, { updateAllLabels: true });
@ -436,18 +439,18 @@ browser.contextMenus.onClicked.addListener(function (info, tab) {
return; return;
} }
var tabId = tab.id; const tabId = tab.id;
var frameId = info.frameId; const frameId = info.frameId;
var label = <LabelKind>info.menuItemId.substring('mark-'.length); var label = <LabelKind>info.menuItemId.substring('mark-'.length);
if (label == 'none') label = ''; if (label == 'none') label = '';
browser.tabs.sendMessage<ShinigamiSubmission, ShinigamiSubmission>(tabId, { browser.tabs.sendMessage<ShinigamiEyesSubmission, ShinigamiEyesSubmission>(tabId, {
mark: label, mark: label,
url: info.linkUrl, url: info.linkUrl,
tabId: tabId, tabId: tabId,
frameId: frameId, frameId: frameId,
// elementId: info.targetElementId, // elementId: info.targetElementId,
debug: overrides.debug debug: <any>overrides.debug
}, { frameId: frameId }, response => { }, { frameId: frameId }, response => {
if (!response.identifier) return; if (!response.identifier) return;
if (response.mark){ if (response.mark){

View File

@ -8,30 +8,14 @@ if (hostname.endsWith('.reddit.com')) hostname = 'reddit.com';
if (hostname.endsWith('.facebook.com')) hostname = 'facebook.com'; if (hostname.endsWith('.facebook.com')) hostname = 'facebook.com';
if (hostname.endsWith('.youtube.com')) hostname = 'youtube.com'; if (hostname.endsWith('.youtube.com')) hostname = 'youtube.com';
var myself : string = null;
var myself = null;
function fixupSiteStyles() { function fixupSiteStyles() {
if (hostname == 'reddit.com') {
myself = document.querySelector('#header-bottom-right .user a');
if (!myself) {
var m : any = document.querySelector('#USER_DROPDOWN_ID');
if (m) {
m = [...m.querySelectorAll('*')].filter(x => x.childNodes.length == 1 && x.firstChild.nodeType == 3).map(x => x.textContent)[0]
if (m) myself = 'reddit.com/user/' + m;
}
}
}
if (hostname == 'facebook.com') { if (hostname == 'facebook.com') {
var m : any = document.querySelector("[id^='profile_pic_header_']") let m = document.querySelector("[id^='profile_pic_header_']")
if (m) myself = 'facebook.com/' + captureRegex(m.id, /header_(\d+)/); if (m) myself = 'facebook.com/' + captureRegex(m.id, /header_(\d+)/);
} } else if (hostname == 'medium.com') {
if (hostname == 'medium.com') { addStyleSheet(`
var style = document.createElement('style');
style.textContent = `
a.show-thread-link, a.ThreadedConversation-moreRepliesLink { a.show-thread-link, a.ThreadedConversation-moreRepliesLink {
color: inherit !important; color: inherit !important;
} }
@ -39,34 +23,20 @@ function fixupSiteStyles() {
.stream-item a:hover .fullname, .stream-item a:hover .fullname,
.stream-item a:active .fullname .stream-item a:active .fullname
{color:inherit;} {color:inherit;}
`);
`; } else if (domainIs(hostname, 'tumblr.com')) {
document.head.appendChild(style); addStyleSheet(`
}
if (isHostedOn(hostname, 'tumblr.com')) {
var style = document.createElement('style');
style.textContent = `
.assigned-label-transphobic { outline: 2px solid #991515 !important; } .assigned-label-transphobic { outline: 2px solid #991515 !important; }
.assigned-label-t-friendly { outline: 1px solid #77B91E !important; } .assigned-label-t-friendly { outline: 1px solid #77B91E !important; }
`; `);
document.head.appendChild(style); } else if (hostname.indexOf('wiki') != -1){
} addStyleSheet(`
if(hostname.indexOf('wiki') != -1){
var style = document.createElement('style');
style.textContent = `
.assigned-label-transphobic { outline: 1px solid #991515 !important; } .assigned-label-transphobic { outline: 1px solid #991515 !important; }
.assigned-label-t-friendly { outline: 1px solid #77B91E !important; } .assigned-label-t-friendly { outline: 1px solid #77B91E !important; }
`);
`; } else if (hostname == 'twitter.com') {
document.head.appendChild(style); myself = getIdentifier(<HTMLAnchorElement>document.querySelector('.DashUserDropdown-userInfo a'));
} addStyleSheet(`
if (hostname == 'twitter.com') {
myself = document.querySelector('.DashUserDropdown-userInfo a');
var style = document.createElement('style');
style.textContent = `
.pretty-link b, .pretty-link s { .pretty-link b, .pretty-link s {
color: inherit !important; color: inherit !important;
} }
@ -78,43 +48,48 @@ function fixupSiteStyles() {
.stream-item a:hover .fullname, .stream-item a:hover .fullname,
.stream-item a:active .fullname .stream-item a:active .fullname
{color:inherit;} {color:inherit;}
`);
`;
document.head.appendChild(style);
} else if (hostname == 'reddit.com') { } else if (hostname == 'reddit.com') {
var style = document.createElement('style'); myself = getIdentifier(<HTMLAnchorElement>document.querySelector('#header-bottom-right .user a'));
style.textContent = ` if (!myself) {
.author { color: #369 !important;} let m = document.querySelector('#USER_DROPDOWN_ID');
`; if (m) {
document.head.appendChild(style); let username = [...m.querySelectorAll('*')].filter(x => x.childNodes.length == 1 && x.firstChild.nodeType == 3).map(x => x.textContent)[0]
if (username) myself = 'reddit.com/user/' + username;
} }
} }
addStyleSheet(`
.author { color: #369 !important;}
`);
}
}
function addStyleSheet(css: string){
const style = document.createElement('style');
style.textContent = css;
document.head.appendChild(style);
}
function maybeDisableCustomCss() { function maybeDisableCustomCss() {
var shouldDisable = null; var shouldDisable: (s: {ownerNode: HTMLElement}) => boolean = null;
if (hostname == 'twitter.com') shouldDisable = x => x.ownerNode && x.ownerNode.id && x.ownerNode.id.startsWith('user-style'); if (hostname == 'twitter.com') shouldDisable = x => x.ownerNode && x.ownerNode.id && x.ownerNode.id.startsWith('user-style');
else if (hostname == 'medium.com') shouldDisable = x => x.ownerNode && x.ownerNode.className && x.ownerNode.className == 'js-collectionStyle'; else if (hostname == 'medium.com') shouldDisable = x => x.ownerNode && x.ownerNode.className && x.ownerNode.className == 'js-collectionStyle';
else if (hostname == 'disqus.com') shouldDisable = x => x.ownerNode && x.ownerNode.id && x.ownerNode.id.startsWith('css_'); else if (hostname == 'disqus.com') shouldDisable = x => x.ownerNode && x.ownerNode.id && x.ownerNode.id.startsWith('css_');
if (shouldDisable) if (shouldDisable)
[...document.styleSheets].filter(shouldDisable).forEach(x => x.disabled = true); [...document.styleSheets].filter(<any>shouldDisable).forEach(x => x.disabled = true);
} }
function init() { function init() {
fixupSiteStyles(); fixupSiteStyles();
if (isHostedOn(hostname, 'youtube.com')) { if (domainIs(hostname, 'youtube.com')) {
setInterval(updateYouTubeChannelHeader, 300); setInterval(updateYouTubeChannelHeader, 300);
setInterval(updateAllLabels, 6000); setInterval(updateAllLabels, 6000);
} }
if (myself && (myself.href || myself.startsWith('http:') || myself.startsWith('https:')))
myself = getIdentifier(myself);
console.log('Self: ' + myself) console.log('Self: ' + myself)
maybeDisableCustomCss(); maybeDisableCustomCss();
updateAllLabels(); updateAllLabels();
@ -135,7 +110,6 @@ function init() {
} }
} }
solvePendingLabels(); solvePendingLabels();
}); });
observer.observe(document.body, { observer.observe(document.body, {
@ -143,15 +117,14 @@ function init() {
subtree: true subtree: true
}); });
document.addEventListener('contextmenu', evt => { document.addEventListener('contextmenu', evt => {
lastRightClickedElement = evt.target; lastRightClickedElement = <HTMLElement>evt.target;
}, true); }, true);
} }
var lastRightClickedElement = null; var lastRightClickedElement : HTMLElement = null;
var lastAppliedYouTubeUrl = null; var lastAppliedYouTubeUrl : string = null;
var lastAppliedYouTubeTitle = null; var lastAppliedYouTubeTitle : string = null;
function updateYouTubeChannelHeader() { function updateYouTubeChannelHeader() {
var url = window.location.href; var url = window.location.href;
@ -187,24 +160,21 @@ function updateYouTubeChannelHeader() {
function updateAllLabels(refresh?: boolean) { function updateAllLabels(refresh?: boolean) {
if (refresh) knownLabels = {}; if (refresh) knownLabels = {};
var links = document.links; for (const a of document.getElementsByTagName('a')) {
for (var i = 0; i < links.length; i++) {
var a = <HTMLAnchorElement>links[i];
initLink(a); initLink(a);
} }
solvePendingLabels(); solvePendingLabels();
} }
var knownLabels: LabelMap = {};
var knownLabels = {}; var labelsToSolve : LabelToSolve[] = [];
var labelsToSolve = [];
function solvePendingLabels() { function solvePendingLabels() {
if (!labelsToSolve.length) return; if (!labelsToSolve.length) return;
var uniqueIdentifiers = Array.from(new Set(labelsToSolve.map(x => x.identifier))); var uniqueIdentifiers = Array.from(new Set(labelsToSolve.map(x => x.identifier)));
var tosolve = labelsToSolve; var tosolve = labelsToSolve;
labelsToSolve = []; labelsToSolve = [];
browser.runtime.sendMessage({ ids: uniqueIdentifiers, myself: myself }, response => { browser.runtime.sendMessage<ShinigamiEyesCommand, LabelMap>({ ids: uniqueIdentifiers, myself: <string>myself }, (response: LabelMap) => {
for (const item of tosolve) { for (const item of tosolve) {
var label = response[item.identifier]; var label = response[item.identifier];
knownLabels[item.identifier] = label || ''; knownLabels[item.identifier] = label || '';
@ -213,8 +183,7 @@ function solvePendingLabels() {
}); });
} }
function applyLabel(a, identifier) { function applyLabel(a: HTMLAnchorElement, identifier: string) {
if (a.assignedCssLabel) { if (a.assignedCssLabel) {
a.classList.remove('assigned-label-' + a.assignedCssLabel); a.classList.remove('assigned-label-' + a.assignedCssLabel);
a.classList.remove('has-assigned-label'); a.classList.remove('has-assigned-label');
@ -246,38 +215,26 @@ function initLink(a: HTMLAnchorElement) {
applyLabel(a, identifier); applyLabel(a, identifier);
} }
function isHostedOn(/** @type {string}*/fullHost, /** @type {string}*/baseHost) { function domainIs(host: string, baseDomain: string) {
if (baseHost.length > fullHost.length) return false; if (baseDomain.length > host.length) return false;
if (baseHost.length == fullHost.length) return baseHost == fullHost; if (baseDomain.length == host.length) return baseDomain == host;
var k = fullHost.charCodeAt(fullHost.length - baseHost.length - 1); var k = host.charCodeAt(host.length - baseDomain.length - 1);
if (k == 0x2E) return fullHost.endsWith(baseHost); if (k == 0x2E /* . */) return host.endsWith(baseDomain);
else return false; else return false;
} }
function getQuery(search: string) : any { function getPartialPath(path: string, num: number) {
if (!search) return {};
var s = {};
if (search.startsWith('?')) search = search.substring(1);
for (var pair of search.split('&')) {
var z = pair.split('=');
if (z.length != 2) continue;
s[decodeURIComponent(z[0]).replace(/\+/g, ' ')] = decodeURIComponent(z[1].replace(/\+/g, ' '));
}
return s;
}
function takeFirstPathComponents(path: string, num: number) {
var m = path.split('/') var m = path.split('/')
m = m.slice(1, 1 + num); m = m.slice(1, 1 + num);
if (m.length && !m[m.length - 1]) m.length--; if (m.length && !m[m.length - 1]) m.length--;
if (m.length != num) return '!!' if (m.length != num) return '!!'
return '/' + m.join('/'); return '/' + m.join('/');
} }
function takeNthPathComponent(path: string, nth: number) { function getPathPart(path: string, index: number) {
return path.split('/')[nth + 1] || null; return path.split('/')[index + 1] || null;
} }
function captureRegex(str, regex) { function captureRegex(str: string, regex: RegExp) {
if (!str) return null; if (!str) return null;
var match = str.match(regex); var match = str.match(regex);
if (match && match[1]) return match[1]; if (match && match[1]) return match[1];
@ -307,30 +264,29 @@ function getCurrentFacebookPageId() {
return null; return null;
} }
function getIdentifier(urlstr) { function getIdentifier(link: string | HTMLAnchorElement) {
try { try {
var k = getIdentifierInternal(urlstr); var k = link instanceof Node ? getIdentifierFromElementImpl(link) : getIdentifierFromURLImpl(tryParseURL(link));
if (!k || k.indexOf('!') != -1) return null; if (!k || k.indexOf('!') != -1) return null;
return k.toLowerCase(); return k.toLowerCase();
} catch (e) { } catch (e) {
console.warn("Unable to get identifier for " + urlstr); console.warn("Unable to get identifier for " + link);
return null; return null;
} }
} }
function getIdentifierInternal(urlstr) { function getIdentifierFromElementImpl(element: HTMLAnchorElement): string {
if (!urlstr) return null; if (!element) return null;
const dataset = element.dataset;
if (hostname == 'reddit.com') { if (hostname == 'reddit.com') {
const parent = urlstr.parentElement; const parent = element.parentElement;
if (parent && parent.classList.contains('domain') && urlstr.textContent.startsWith('self.')) return null; if (parent && parent.classList.contains('domain') && element.textContent.startsWith('self.')) return null;
} } else if (hostname == 'disqus.com') {
if (hostname == 'disqus.com') { if (element.classList && element.classList.contains('time-ago')) return null;
if (urlstr.classList && urlstr.classList.contains('time-ago')) return null; } else if (hostname == 'facebook.com') {
} const parent = element.parentElement;
if (hostname == 'facebook.com' && urlstr.tagName) {
const parent = urlstr.parentElement;
if (parent && (parent.tagName == 'H1' || parent.id == 'fb-timeline-cover-name')) { if (parent && (parent.tagName == 'H1' || parent.id == 'fb-timeline-cover-name')) {
const id = getCurrentFacebookPageId(); const id = getCurrentFacebookPageId();
//console.log('Current fb page: ' + id) //console.log('Current fb page: ' + id)
@ -339,17 +295,17 @@ function getIdentifierInternal(urlstr) {
} }
// comment timestamp // comment timestamp
if (urlstr.firstChild && urlstr.firstChild.tagName == 'ABBR' && urlstr.lastChild == urlstr.firstChild) return null; if (element.firstChild && (<HTMLElement>element.firstChild).tagName == 'ABBR' && element.lastChild == element.firstChild) return null;
// post 'see more' // post 'see more'
if (urlstr.classList.contains('see_more_link')) return null; if (element.classList.contains('see_more_link')) return null;
// post 'continue reading' // post 'continue reading'
if (parent && parent.classList.contains('text_exposed_link')) return null; if (parent && parent.classList.contains('text_exposed_link')) return null;
if (urlstr.dataset) { if (dataset) {
const hovercard = urlstr.dataset.hovercard; const hovercard = dataset.hovercard;
if (hovercard) { if (hovercard) {
const id = captureRegex(hovercard, /id=(\d+)/); const id = captureRegex(hovercard, /id=(\d+)/);
if (id) if (id)
@ -357,18 +313,18 @@ function getIdentifierInternal(urlstr) {
} }
// post Comments link // post Comments link
if (urlstr.dataset.testid == 'UFI2CommentsCount/root') return null; if (dataset.testid == 'UFI2CommentsCount/root') return null;
// post Comments link // post Comments link
if (urlstr.dataset.commentPreludeRef) return null; if (dataset.commentPreludeRef) return null;
// page left sidebar // page left sidebar
if (urlstr.dataset.endpoint) return null; if (dataset.endpoint) return null;
// profile tabs // profile tabs
if (urlstr.dataset.tabKey) return null; if (dataset.tabKey) return null;
const gt = urlstr.dataset.gt; const gt = dataset.gt;
if (gt) { if (gt) {
const gtParsed = JSON.parse(gt); const gtParsed = JSON.parse(gt);
if (gtParsed.engagement && gtParsed.engagement.eng_tid) { if (gtParsed.engagement && gtParsed.engagement.eng_tid) {
@ -377,9 +333,9 @@ function getIdentifierInternal(urlstr) {
} }
// comment interaction buttons // comment interaction buttons
if (urlstr.dataset.sigil) return null; if (dataset.sigil) return null;
let p = <HTMLElement>urlstr; let p = <HTMLElement>element;
while (p) { while (p) {
const bt = p.dataset.bt; const bt = p.dataset.bt;
if (bt) { if (bt) {
@ -390,109 +346,98 @@ function getIdentifierInternal(urlstr) {
} }
} }
} }
if (urlstr.dataset && urlstr.dataset.expandedUrl) urlstr = urlstr.dataset.expandedUrl; if (dataset && dataset.expandedUrl) return getIdentifierFromURLImpl(tryParseURL(dataset.expandedUrl));
if (urlstr.href !== undefined) urlstr = urlstr.href; const href = element.href;
if(href && !href.endsWith('#')) return getIdentifierFromURLImpl(tryParseURL(href));
return null;
}
function tryParseURL(urlstr: string){
if (!urlstr) return null; if (!urlstr) return null;
if (urlstr.endsWith('#')) return null;
let url;
try { try {
url = new URL(urlstr); const url = new URL(urlstr);
if (url.protocol != 'http:' && url.protocol != 'https:') return null;
return url;
} catch(e) { } catch(e) {
return null; return null;
} }
if (url.protocol != 'http:' && url.protocol != 'https:') return null; }
function getIdentifierFromURLImpl(url: URL): string{
if(!url) return null;
// nested urls
if (url.href.indexOf('http', 1) != -1) {
if (url.pathname.startsWith('/intl/')) return null; // facebook language switch links
// const values = url.searchParams.values()
// HACK: values(...) is not iterable on facebook (babel polyfill?)
const values = url.search.split('&').map(x => {
const eq = x.indexOf('=');
return eq == -1 ? '' : decodeURIComponent(x.substr(eq + 1));
});
for (const value of values) {
if (value.startsWith('http:') || value.startsWith('https:')) {
return getIdentifierFromURLImpl(tryParseURL(value));
}
}
const newurl = tryParseURL(url.href.substring(url.href.indexOf('http', 1)));
if(newurl) return getIdentifierFromURLImpl(newurl);
}
// fb group member badge // fb group member badge
if (url.pathname.includes('/badge_member_list/')) return null; if (url.pathname.includes('/badge_member_list/')) return null;
if (url.href.indexOf('http', 1) != -1) {
const s = getQuery(url.search);
urlstr = null;
for (const key in s) {
if (s.hasOwnProperty(key)) {
const element = s[key];
if (element.startsWith('http:') || element.startsWith('https')) {
urlstr = element;
break;
}
}
}
if (urlstr == null) {
urlstr = url.href.substring(url.href.indexOf('http', 1))
}
try {
url = new URL(urlstr);
} catch (e) { }
}
let host = url.hostname; let host = url.hostname;
if (isHostedOn(host, 'web.archive.org')) { if (domainIs(host, 'web.archive.org')) {
const match = captureRegex(url.href, /\/web\/\w+\/(.*)/); const match = captureRegex(url.href, /\/web\/\w+\/(.*)/);
if (!match) return null; if (!match) return null;
return getIdentifierInternal('http://' + match); return getIdentifierFromURLImpl(tryParseURL('http://' + match));
} }
if (url.search && url.search.includes('http')) {
if (url.pathname.startsWith('/intl/')) return null; // facebook language switch links
for (const q of url.searchParams) {
if (q[1].startsWith('http')) return getIdentifierInternal(q[1]);
}
}
/*
if(host == 't.umblr.com'){
return getIdentifierInternal(url.searchParams.get('z'));
}
*/
if (host.startsWith('www.')) host = host.substring(4); if (host.startsWith('www.')) host = host.substring(4);
if (isHostedOn(host, 'facebook.com')) { if (domainIs(host, 'facebook.com')) {
const s = getQuery(url.search); const fbId = url.searchParams.get('id');
const p = url.pathname.replace('/pg/', '/'); const p = url.pathname.replace('/pg/', '/');
return 'facebook.com/' + (s.id || takeFirstPathComponents(p, p.startsWith('/groups/') ? 2 : 1).substring(1)); return 'facebook.com/' + (fbId || getPartialPath(p, p.startsWith('/groups/') ? 2 : 1).substring(1));
} } else if (domainIs(host, 'reddit.com')) {
if (isHostedOn(host, 'reddit.com')) {
const pathname = url.pathname.replace('/u/', '/user/'); const pathname = url.pathname.replace('/u/', '/user/');
if (!pathname.startsWith('/user/') && !pathname.startsWith('/r/')) return null; if (!pathname.startsWith('/user/') && !pathname.startsWith('/r/')) return null;
if(pathname.includes('/comments/') && hostname == 'reddit.com') return null; if(pathname.includes('/comments/') && hostname == 'reddit.com') return null;
return 'reddit.com' + takeFirstPathComponents(pathname, 2); return 'reddit.com' + getPartialPath(pathname, 2);
} } else if (domainIs(host, 'twitter.com')) {
if (isHostedOn(host, 'twitter.com')) { return 'twitter.com' + getPartialPath(url.pathname, 1);
return 'twitter.com' + takeFirstPathComponents(url.pathname, 1); } else if (domainIs(host, 'youtube.com')) {
}
if (isHostedOn(host, 'youtube.com')) {
const pathname = url.pathname.replace('/c/', '/user/'); const pathname = url.pathname.replace('/c/', '/user/');
if (!pathname.startsWith('/user/') && !pathname.startsWith('/channel/')) return null; if (!pathname.startsWith('/user/') && !pathname.startsWith('/channel/')) return null;
return 'youtube.com' + takeFirstPathComponents(pathname, 2); return 'youtube.com' + getPartialPath(pathname, 2);
} } else if (domainIs(host, 'disqus.com') && url.pathname.startsWith('/by/')) {
if (isHostedOn(host, 'disqus.com') && url.pathname.startsWith('/by/')) { return 'disqus.com' + getPartialPath(url.pathname, 2);
return 'disqus.com' + takeFirstPathComponents(url.pathname, 2); } else if (domainIs(host, 'medium.com')) {
} return 'medium.com' + getPartialPath(url.pathname.replace('/t/', '/'), 1);
if (isHostedOn(host, 'medium.com')) { } else if (domainIs(host, 'tumblr.com')) {
return 'medium.com' + takeFirstPathComponents(url.pathname.replace('/t/', '/'), 1);
}
if (isHostedOn(host, 'tumblr.com')) {
if (url.pathname.startsWith('/register/follow/')) { if (url.pathname.startsWith('/register/follow/')) {
const name = takeNthPathComponent(url.pathname, 2); const name = getPathPart(url.pathname, 2);
return name ? name + '.tumblr.com' : null; return name ? name + '.tumblr.com' : null;
} }
if (host != 'www.tumblr.com' && host != 'assets.tumblr.com' && host.indexOf('.media.') == -1) { if (host != 'www.tumblr.com' && host != 'assets.tumblr.com' && host.indexOf('.media.') == -1) {
if (!url.pathname.startsWith('/tagged/')) return url.host; if (!url.pathname.startsWith('/tagged/')) return url.host;
} }
return null; return null;
} } else if (domainIs(host, 'wikipedia.org') || domainIs(host, 'rationalwiki.org')) {
if (isHostedOn(host, 'wikipedia.org') || isHostedOn(host, 'rationalwiki.org')) {
if (url.hash || url.pathname.includes(':')) return null; if (url.hash || url.pathname.includes(':')) return null;
if (url.pathname.startsWith('/wiki/')) return 'wikipedia.org' + takeFirstPathComponents(url.pathname, 2); if (url.pathname.startsWith('/wiki/')) return 'wikipedia.org' + getPartialPath(url.pathname, 2);
else return null; else return null;
} } else if (host.indexOf('.blogspot.') != -1) {
if (host.indexOf('.blogspot.') != -1) {
const m = captureRegex(host, /([a-zA-Z0-9\-]*)\.blogspot/); const m = captureRegex(host, /([a-zA-Z0-9\-]*)\.blogspot/);
if (m) return m + '.blogspot.com'; if (m) return m + '.blogspot.com';
else return null;
} else {
if (host.startsWith('m.')) host = host.substr(2);
return host;
} }
let id = host;
if (id.startsWith('www.')) id = id.substr(4);
if (id.startsWith('m.')) id = id.substr(2);
return id;
} }
@ -500,7 +445,7 @@ init();
var lastGeneratedLinkId = 0; var lastGeneratedLinkId = 0;
function getSnippet(node){ function getSnippet(node: HTMLElement){
while (node) { while (node) {
var classList = node.classList; var classList = node.classList;
if (hostname == 'facebook.com' && node.dataset && node.dataset.ftr) return node; if (hostname == 'facebook.com' && node.dataset && node.dataset.ftr) return node;
@ -517,7 +462,7 @@ function getSnippet(node){
} }
browser.runtime.onMessage.addListener((message, sender, sendResponse) => { browser.runtime.onMessage.addListener<ShinigamiEyesMessage, ShinigamiEyesSubmission>((message, sender, sendResponse) => {
if (message.updateAllLabels) { if (message.updateAllLabels) {
updateAllLabels(true); updateAllLabels(true);
@ -528,13 +473,13 @@ browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
var target = lastRightClickedElement; // message.elementId ? browser.menus.getTargetElement(message.elementId) : null; var target = lastRightClickedElement; // message.elementId ? browser.menus.getTargetElement(message.elementId) : null;
while(target){ while(target){
if(target.href) break; if((<HTMLAnchorElement>target).href) break;
target = target.parentElement; target = target.parentElement;
} }
if (target && target.href != message.url) target = null; if (target && (<HTMLAnchorElement>target).href != message.url) target = null;
var identifier = target ? getIdentifier(target) : getIdentifier(message.url); var identifier = target ? getIdentifier(<HTMLAnchorElement>target) : getIdentifier(message.url);
if (!identifier) return; if (!identifier) return;
message.identifier = identifier; message.identifier = identifier;
@ -545,7 +490,7 @@ browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
message.linkId = ++lastGeneratedLinkId; message.linkId = ++lastGeneratedLinkId;
if (target) if (target)
target.setAttribute('shinigami-eyes-link-id', lastGeneratedLinkId); target.setAttribute('shinigami-eyes-link-id', '' + lastGeneratedLinkId);
message.snippet = snippet ? snippet.outerHTML : null; message.snippet = snippet ? snippet.outerHTML : null;
var debugClass = 'shinigami-eyes-debug-snippet-highlight'; var debugClass = 'shinigami-eyes-debug-snippet-highlight';

View File

@ -1,16 +1,39 @@
declare class BloomFilter { declare class BloomFilter {
constructor(data: Uint32Array, k: number); constructor(data: Uint32Array, k: number);
test(key: string): boolean; test(key: string): boolean;
name: string; name: LabelKind;
}
interface HTMLElement {
assignedCssLabel?: string
}
interface LabelToSolve {
element: HTMLAnchorElement
identifier: string
} }
type LabelKind = 't-friendly' | 'transphobic' | 'none' | ''; type LabelKind = 't-friendly' | 'transphobic' | 'none' | '';
type ShinigamiSubmission = { interface ShinigamiEyesSubmission {
mark: LabelKind mark?: LabelKind
url: string url?: string
tabId: number tabId?: number
frameId: number frameId?: number
debug: number debug?: number
identifier?: string identifier?: string
secondaryIdentifier?: string secondaryIdentifier?: string
version?: number
submissionId?: string
contextPage?: string
linkId?: number
snippet?: string
} }
interface ShinigamiEyesCommand {
acceptClicked?: boolean
myself?: string
ids?: string[]
updateAllLabels?: boolean
}
type LabelMap = {[identifier: string]: LabelKind};
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';

View File

@ -1,5 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es2017" "target": "es2017",
"noImplicitAny": true,
"noImplicitReturns": true,
} }
} }

View File

@ -1,9 +1,9 @@
declare type Browser = { declare type Browser = {
runtime: { runtime: {
sendMessage<TRequest, TResponse>(request: TRequest, response: (response: TResponse) => void); sendMessage<TRequest, TResponse>(request: TRequest, response: (response: TResponse) => void): void;
onMessage: { onMessage: {
addListener(listener: (message, any, sendResponse) => void) addListener<TRequest, TResponse>(listener: (message: TRequest, sender: MessageSender, sendResponse: (response: TResponse) => void) => void): void
} }
} }
@ -11,13 +11,13 @@ declare type Browser = {
local: BrowserStorage local: BrowserStorage
} }
tabs: { tabs: {
remove(id: number) remove(id: number): void
sendMessage<TRequest, TResponse>(tabId: number, request: TRequest, options?: { sendMessage<TRequest, TResponse>(tabId: number, request: TRequest, options?: {
frameId: number frameId: number
}, callback?: (response: TResponse) => void) }, callback?: (response: TResponse) => void): void
create(options: { create(options: {
url: string url: string
}) }): void
} }
extension: { extension: {
getURL(relativeUrl: string): string getURL(relativeUrl: string): string
@ -36,13 +36,20 @@ declare type Browser = {
linkUrl: string linkUrl: string
}, tab: { }, tab: {
id: number id: number
}) => void) }) => void): void
} }
} }
} }
type MessageSender = {
tab?: {id: number};
frameId?: number;
id?: string;
url?: string;
tlsChannelId?: string;
};
declare type BrowserStorage = { declare type BrowserStorage = {
get(names: string[], callback: (obj: any) => void) get(names: string[], callback: (obj: any) => void): void
set(obj: { [name: string]: any }); set(obj: { [name: string]: any }): void;
} }
declare var browser: Browser; declare var browser: Browser;
declare var chrome: Browser; declare var chrome: Browser;