Skip to content
This repository has been archived by the owner on Nov 21, 2022. It is now read-only.

0.1alpha initial commit #79

Merged
merged 20 commits into from
Jan 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8ae4037
Updated setup of tests, minor updates to code, added text_white optio…
ribicn-softerrific Nov 21, 2019
eff2665
Update issue templates
malteserteresa Dec 2, 2019
307cb38
Delete feature_request.md
malteserteresa Dec 2, 2019
fc242a2
Update feature-implementation.md
malteserteresa Dec 2, 2019
caa58cb
Create FUNDING.yml
malteserteresa Dec 5, 2019
acdfaa7
Update FUNDING.yml
malteserteresa Dec 5, 2019
a0d5f18
Taking out selenium tests so we can merge the rest of the PR
Dec 7, 2019
60908ee
Merge pull request #75 from opt-out-tools/ribicn-softerrific-update_t…
Dec 9, 2019
6d34ebb
#66 - Adding report `is misogynistic` and `isn't misogynistic` buttons
ribicn-softerrific Dec 11, 2019
457620c
bug-fix-memory-leak
ribicn-softerrific Dec 11, 2019
2c01c0d
resolving task 4 and 5 for #66
ribicn-softerrific Dec 11, 2019
569903f
Updated Eslint settings and added separate settings file for tests
ribicn-softerrific Dec 12, 2019
968ce83
removed excess console.log
ribicn-softerrific Dec 12, 2019
9f39953
Merge remote-tracking branch 'origin/#78_bug_fix_memory_leak_&_unclea…
ribicn-softerrific Dec 12, 2019
7829033
Merge pull request #78 from ribicn-softerrific/#78_bug_fix_memory_lea…
Dec 17, 2019
828154f
- Merged Memory bug Fix from master
ribicn-softerrific Dec 18, 2019
b285995
- 0.1alpha Initial commit
ribicn-softerrific Dec 18, 2019
78388a5
- added disabling of buttons after the click
ribicn-softerrific Dec 19, 2019
3d8df15
Merge remote-tracking branch 'origin/#66_Alpha' into #66_Alpha
ribicn-softerrific Dec 19, 2019
5f8855f
Merge branch 'master' into #66_Alpha
ribicn-softerrific Dec 19, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,28 @@ env:
browser: true
es6: true
webextensions: true
jest: true
node: true
extends:
- airbnb-base
- standard
globals:
Atomics: readonly
SharedArrayBuffer: readonly
browser: readonly
parserOptions:
ecmaVersion: 2018
sourceType: module
rules: {}

rules:
no-console: off
indent:
- error
- 2
- {SwitchCase: 1}
linebreak-style:
- error
- unix
quotes:
- error
- single
semi:
- error
- always
201 changes: 151 additions & 50 deletions extension/content/opt-out-ext.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
let selector;
let option = 'text_crossed';
let slider = '1';

function updateOption(result) {
option = result.optOut.selector;
slider = result.optOut.slider;
}

function onError(error) {
console.log(`Error: ${error}`);
}
browser.storage.sync.get('optOut').then(updateOption, onError);

const bodyColor = window.getComputedStyle(document.body, null).getPropertyValue('background-color');
document.documentElement.style
.setProperty('--color', bodyColor);

const root = document.getElementById('doc') || document.getElementById('react-root');

Expand All @@ -22,87 +14,160 @@ if (document.querySelector('body').classList.contains('logged-out')) {
console.log('online');
selector = '[data-testid="tweet"]';
}
/**
* @description Updates `option` and `slider` depending on the given result
* @param result
*/
const updateOption = (result) => {
option = result.optOut.selector;
slider = result.optOut.slider;
};

/**
* @description Function handles errors.
* @param error
*/
const onError = (error) => {
console.error(`Error: ${error}`);
};

/**
* @description Depending on `option` sets classes to tweet nodes
*/
const styleTweet = (element, selectedOption, sliderValue) => {
element.classList.remove('opt-out-tw', 'opt-out-tc', 'opt-out-trem');
if (sliderValue === '1') {
switch (selectedOption) {
case 'text_white':
element.classList.add('opt-out-tw');
break;
case 'text_crossed':
element.classList.add('opt-out-tc');
break;
case 'text_removed':
element.classList.add('opt-out-trem');
break;
}
}
element.nextElementSibling.style.display = (sliderValue === '1') ? 'flex' : 'none';
};

/*
Depending on `option` sets classes to tweet nodes
/**
* @description Should inject check Buttons to post
* @param node
*/
const styleTweet = function (element, selectedOption, sliderValue) {
if ((selectedOption === 'text_white') && (sliderValue === '1')) element.classList.add('opt-out-tw');
else element.classList.remove('opt-out-tw');
if ((selectedOption === 'text_crossed') && (sliderValue === '1')) element.classList.add('opt-out-tc');
else element.classList.remove('opt-out-tc');
if ((selectedOption === 'text_removed') && (sliderValue === '1')) element.classList.add('opt-out-trem');
else element.classList.remove('opt-out-trem');
const injectReportMisogynisticButtons = (node) => {
const buttons = document.createElement('div');
buttons.classList.add('report-button-container');
const button1 = document.createElement('button');
button1.appendChild(document.createTextNode('Is misogynistic'));
button1.classList.add('report-button', 'report-button_is');
const button2 = document.createElement('button');
button2.appendChild(document.createTextNode('Isn\'t misogynistic'));
button2.classList.add('report-button', 'report-button_isnt');
buttons.appendChild(button1);
buttons.appendChild(button2);
node.parentNode.insertBefore(buttons, node.nextSibling);
};

/*
function which calls server for given node, and depending on the response,
applies pre-defined action
/**
* @description function which calls server for given node, and depending on the response,
* applies pre-defined action
* @param node
*/
const checkText = function (node) {
const checkText = (node) => {
node.classList.add('processing');
console.log('Sending Request');
const link = 'https://api.optoutools.com/predict';
const xhr = new XMLHttpRequest();
const tweetTextNode = node.querySelector(
`${selector} > div ~ div > div ~ div`
);
xhr.open('POST', link, true);
xhr.setRequestHeader('Content-type', 'application/json;charset=UTF-8');
xhr.withCredentials = true;
xhr.onreadystatechange = function (e) {
xhr.onreadystatechange = (e) => {
if (xhr.readyState !== 4) {
return;
}
if (xhr.status === 200) {
console.log(
'Response received as ',
JSON.parse(xhr.response).predictions[0],
JSON.parse(xhr.response).predictions[0]
);
injectReportMisogynisticButtons(tweetTextNode);
if (JSON.parse(xhr.response).predictions[0]) {
node.classList.add('processed-true');
const tweetText = node.querySelector(
`${selector} > div ~ div > div ~ div`,
);
styleTweet(tweetText, option, slider);
styleTweet(tweetTextNode, option, slider);
} else {
node.classList.add('processed-false');
}
} else {
console.error(e);
// console.error(e);
console.log('Failed response', xhr);
}
};
xhr.send(
JSON.stringify({
texts: [node.innerText],
}),
texts: [tweetTextNode.innerText]
})
);
};

/*
* Predefines action and changes it depending on user action
/**
* @description function which sends tweet text to
* @param tweetNode
* @param isMisogynistic
*/
browser.runtime.onMessage.addListener((message) => {
if ((option !== message.selector) || (slider !== message.slider)) {
option = message.selector;
slider = message.slider;
const posts = document.querySelectorAll('.processed-true');
posts.forEach((post) => {
const tweetText = post.querySelector(
`${selector} > div ~ div > div ~ div`,
); // selecting text inside tweet
styleTweet(tweetText, option, slider);
});
}
});
const reportMisogyny = (tweetNode, isMisogynistic) => {
const tweetText = tweetNode.querySelector(
`${selector} > div ~ div > div ~ div`
).innerText;
const tweetId = tweetNode.querySelector(
`${selector} > div ~ div > div > div > a`
).href.split('/').filter(e => e).slice(-1)[0];
const link = 'https://api.optoutools.com/mislabeled_tweet';
const xhr = new XMLHttpRequest();
xhr.open('POST', link, true);
xhr.setRequestHeader('Content-type', 'application/json;charset=UTF-8');
xhr.withCredentials = true;
xhr.onreadystatechange = (e) => {
if (xhr.readyState !== 4) {
return;
}
if (xhr.status === 200) {
// What to do when tweet is reported, disable buttons? replace with message?
} else {
console.log('Failed response', xhr);
}
};
xhr.send(
JSON.stringify({
text: tweetText,
id: tweetId,
model_version: isMisogynistic
})
);
};

const processTweets = function () {
/**
* @description get every tweet and process unprocessed ones.
*/
const processTweets = () => {
const posts = document.querySelectorAll(selector); // selecting tweet object
posts.forEach((post) => {
if (post.classList.contains('processed-true')) return;
if (post.classList.contains('processed-false')) return;
if (post.classList.contains('processing')) return;
checkText(post);
});
};

const checkTweetList = function (mutationsList) {
/**
* @description for every change in DOM run processTweets
* @param mutationsList
*/
const checkTweetList = (mutationsList) => {
mutationsList.forEach((mutation) => {
if (mutation.type === 'childList') {
processTweets();
Expand All @@ -111,4 +176,40 @@ const checkTweetList = function (mutationsList) {
};

const checkTweetListObserver = new MutationObserver(checkTweetList);

// MAIN FUNCTION

browser.storage.sync.get('optOut').then(updateOption, onError);
/**
* Adds listener which on new message received from popup goes over tweets and applies new style
*/
browser.runtime.onMessage.addListener((message) => {
if ((option !== message.selector) || (slider !== message.slider)) {
option = message.selector;
slider = message.slider;
const posts = document.querySelectorAll('.processed-true');
posts.forEach((post) => {
const tweetText = post.querySelector(
`${selector} > div ~ div > div ~ div`
); // selecting text inside tweet
styleTweet(tweetText, option, slider);
});
}
});

/**
* Adds listener which listens for click from 'report_button' and triggers corresponding action
*/
document.addEventListener('click', function (event) {
if (!event.target.matches('.report-button')) return;
event.preventDefault();
const tweetNode = event.target.parentNode.parentNode.parentNode;
const isMisogynistic = (event.target.matches('.report-button_is')) ? 1 : 0;
reportMisogyny(tweetNode, isMisogynistic);
for (const button of event.target.parentNode.children) {
button.style.cursor = 'not-allowed';
button.disabled = true;
}
}, false);

checkTweetListObserver.observe(root, { childList: true, subtree: true });
30 changes: 29 additions & 1 deletion extension/content/opt-out.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
:root {
--color: rgb(255, 255, 255);
}
.opt-out-tw {
color: white;
color: var(--color, white);
}
.opt-out-tw a {
color: var(--color, white);
}

.opt-out-tc {
Expand All @@ -9,3 +15,25 @@
.opt-out-trem {
display: none;
}

.report-button-container {
display: flex;
justify-content: space-around;
}

.report-button {
width: 180px;
height: 40px;
padding-left: 37px;
border-radius: 5px;
}

.report-button_is {
background: 5px center no-repeat url(../popup/assets/angry.svg);
background-size: auto 80%;
}

.report-button_isnt {
background: 5px center no-repeat url(../popup/assets/happy.svg);
background-size: auto 80%;
}
5 changes: 3 additions & 2 deletions extension/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"webRequestBlocking",
"activeTab",
"storage",
"https://api.optoutools.com/predict"
"https://api.optoutools.com/predict",
"https://api.optoutools.com/mislabeled_tweet"
],
"applications": {
"gecko": {
Expand All @@ -20,7 +21,7 @@
"browser_action": {
"default_icon": "icons/icon-48.png",
"default_title": "Opt-Out-Ext",
"default_popup": "popup/set_view_mod.html"
"default_popup": "popup/popup.html"
},
"icons": {
"48": "icons/icon-48.png",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ h2 {

#slider {
width: 100%;
background: #d3d3d3;
background: #d3d3d3;
height: 10px;
border-radius: 5px;
margin-bottom: 24px;
}

#slider::-moz-range-thumb {
width: 50px;
width: 50px;
height: 50px;
cursor: pointer;
border: none;
Expand All @@ -37,7 +37,7 @@ h2 {
}

#slider::-webkit-slider-thumb {
width: 50px;
width: 50px;
height: 50px;
cursor: pointer;
border: none;
Expand Down
10 changes: 10 additions & 0 deletions extension/popup/functions/onError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @description Display the popup's error message, and hide the normal UI.
*
* @param error - contains error message
*/
export default function (error) {
document.querySelector('#popup-content').classList.add('hidden');
document.querySelector('#error-content').classList.remove('hidden');
console.error(`Failed to execute opt-out content script: ${error.message}`);
}
Loading