diff --git a/browser-extension/plugin/package-lock.json b/browser-extension/plugin/package-lock.json
index 5dd5a5da..15136f03 100644
--- a/browser-extension/plugin/package-lock.json
+++ b/browser-extension/plugin/package-lock.json
@@ -11,6 +11,7 @@
"dependencies": {
"axios": "1.6.2",
"concurrently": "8.2.2",
+ "dexie": "^4.0.11",
"dom-to-image": "2.6.0",
"dom-to-image-improved": "2.8.0",
"dom-to-image-more": "3.2.0",
@@ -5092,6 +5093,11 @@
"integrity": "sha512-nEzHZteIUZfGCZtTiS1fRpC8UZmsfD1SiyPvaUNvS13dvKf666OAm8YTi0+Ca3n1nLEyu49Cy4+dPWpaHFJk9g==",
"dev": true
},
+ "node_modules/dexie": {
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.0.11.tgz",
+ "integrity": "sha512-SOKO002EqlvBYYKQSew3iymBoN2EQ4BDw/3yprjh7kAfFzjBYkaMNa/pZvcA7HSWlcKSQb9XhPe3wKyQ0x4A8A=="
+ },
"node_modules/diff-sequences": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
diff --git a/browser-extension/plugin/package.json b/browser-extension/plugin/package.json
index 34b78467..2a98f232 100644
--- a/browser-extension/plugin/package.json
+++ b/browser-extension/plugin/package.json
@@ -43,6 +43,7 @@
"dependencies": {
"axios": "1.6.2",
"concurrently": "8.2.2",
+ "dexie": "^4.0.11",
"dom-to-image": "2.6.0",
"dom-to-image-improved": "2.8.0",
"dom-to-image-more": "3.2.0",
diff --git a/browser-extension/plugin/src/api/public-slurs.js b/browser-extension/plugin/src/api/public-slurs.js
new file mode 100644
index 00000000..659508fc
--- /dev/null
+++ b/browser-extension/plugin/src/api/public-slurs.js
@@ -0,0 +1,24 @@
+import axios from 'axios';
+import config from '../config';
+
+const { API_URL } = config;
+
+export async function getPublicSlurs() {
+ try {
+ const res = await axios.get(`${API_URL}/api/dataset/slur/1`);
+
+ return res.data.slurs;
+ } catch (error) {
+ throw error;
+ }
+}
+
+export async function getPublicSlursMetadata() {
+ try {
+ const res = await axios.get(`${API_URL}/api/dataset/slurmetadata/1`);
+
+ return res.data.slurs_metadata;
+ } catch (error) {
+ throw error;
+ }
+}
\ No newline at end of file
diff --git a/browser-extension/plugin/src/background.js b/browser-extension/plugin/src/background.js
index 2885e1c6..c48e095b 100644
--- a/browser-extension/plugin/src/background.js
+++ b/browser-extension/plugin/src/background.js
@@ -65,4 +65,4 @@ userBrowserContextMenus.onClicked.addListener((info, tab) => {
default:
console('unexpected action');
}
-});
+});
\ No newline at end of file
diff --git a/browser-extension/plugin/src/chrome.js b/browser-extension/plugin/src/chrome.js
index 0fd5808f..724207a1 100644
--- a/browser-extension/plugin/src/chrome.js
+++ b/browser-extension/plugin/src/chrome.js
@@ -70,34 +70,45 @@ const set = (key, value) => {
});
};
-function sendMessage(type) {
- if (type == 'updateData') {
- userBrowserTabs.query(
- { active: true, currentWindow: true },
- function (tabs) {
- userBrowserTabs.sendMessage(
- tabs[0].id,
- { type: 'updateData' },
- function (response) {
- console.log(response);
- }
- );
- }
- );
- }
+function sendMessage(type, data = null) {
+ return new Promise((resolve, reject) => {
+ const message = { type };
+ if (data) {
+ message.data = data;
+ }
+
+ if (
+ type === 'updateData' ||
+ type === 'fetchPersonalSlurs' ||
+ type === 'syncApprovedCrowdsourcedSlurs'
+ ) {
+ userBrowserTabs.query(
+ { active: true, currentWindow: true },
+ function (tabs) {
+ userBrowserTabs.sendMessage(
+ tabs[0].id,
+ message,
+ function (response) {
+ resolve(response);
+ }
+ );
+ }
+ );
+ } else {
+ reject(new Error('Unsupported message type'));
+ }
+ });
}
function addListener(type, func, response) {
- chrome.runtime.onMessage.addListener(async function (
- message,
- sender,
- sendResponse
- ) {
- if (message.type === type) {
- func();
- sendResponse(response);
+ chrome.runtime.onMessage.addListener(
+ async function (message, sender, sendResponse) {
+ if (message.type === type) {
+ func();
+ sendResponse(response);
+ }
}
- });
+ );
}
export default {
diff --git a/browser-extension/plugin/src/content-script.js b/browser-extension/plugin/src/content-script.js
index cab02a1d..4739704c 100644
--- a/browser-extension/plugin/src/content-script.js
+++ b/browser-extension/plugin/src/content-script.js
@@ -5,10 +5,19 @@ import transform_v2 from './transform-v2';
import { log } from './logger';
import repository from './repository';
const { getUserData, getPreferenceData, setPreferenceData } = repository;
-import { updateSlurList } from './slur-replace';
import transformGeneral from './transform-general';
import Api from './ui-components/pages/Api';
+import {
+ initializeSlurs,
+ getSlursBySource,
+ addSlur,
+ deleteSlur,
+ slurExists,
+ bulkAddSlurs,
+ convertSlurMetadataFromDBtoJSON
+} from './slur-store';
import { createCrowdsourceSlur } from './api/crowdsource-slurs';
+import { getPublicSlurs } from './api/public-slurs';
const { createSlurAndCategory } = Api;
@@ -79,85 +88,141 @@ function processPage(newUrl) {
* eg : When a user clicks on a tweet on their home timeline, they
* go from the home page to the user status page.
*/
-chrome.runtime.onMessage.addListener(async function (request) {
- if (request.type === 'updateData') {
- console.log('data changed. time to update slurs');
- const preference = await getPreferenceData();
- console.log(preference);
- if (preference.slurList != undefined) {
- updateSlurList(preference.slurList);
- processPage(location.href);
- }
- return true;
- }
- if (request.message === 'URL_CHANGED') {
- const newUrl = request.url;
- log('Url Changed', newUrl);
- processPage(location.href);
- return true;
- }
- if (request.type === 'SLUR_ADDED') {
- const slur = request.slur;
- log('slur added from bg', slur);
- const pref = await getPreferenceData();
- let slurList;
-
- const user = await getUserData();
- // console.log('USER in content-script', user);
- const crowdsourceData = {
- label: slur,
- };
-
- // Adding Slur to Prefrences
- if (!pref || !pref.slurList) {
- slurList = slur;
- } else {
- slurList = pref.slurList;
- if (!slurList || slurList === '') {
- slurList = slur;
- } else {
- slurList += `,${slur}`;
+chrome.runtime.onMessage.addListener(
+ async function (request, sender, sendResponse) {
+ if (request.type === 'updateData') {
+ try {
+ const newSlurs = request.data;
+ console.log('New slurs received:', newSlurs);
+ // fetch exisiting slurs
+ const existingSlurs = (await getSlursBySource('personal')).map(
+ (slur) => slur.word
+ );
+ // Add new slurs to the database
+ for (const slur of newSlurs) {
+ if (!existingSlurs.includes(slur)) {
+ await addSlur(slur, 'personal');
+ }
+ }
+ // Remove slurs from the database that no longer exist in the new list
+ for (const slur of existingSlurs) {
+ if (!newSlurs.includes(slur)) {
+ await deleteSlur(slur, 'personal');
+ }
+ }
+ processPage(location.href);
+ } catch (error) {
+ console.error('Error during updating slur list:', error);
}
+ return true;
}
- try {
- await setPreferenceData({ ...pref, slurList });
- } catch (error) {
- console.error('error updating pref data', error);
+ if (request.type === 'fetchPersonalSlurs') {
+ try {
+ const personalSlurs = await getSlursBySource('personal');
+ const slurArr = personalSlurs.map((slur) => slur.word);
+ console.log('Sending slurs back to pref:', slurArr);
+ return slurArr;
+ } catch (error) {
+ console.error(
+ 'Error fetching personal slurs in content script:',
+ error
+ );
+ // sendResponse({ success: false, error: error.message });
+ }
}
+ if (request.type === 'syncApprovedCrowdsourcedSlurs') {
+ const source = 'public_crowdsourced_slurs';
+ try {
+ const publicSlurs = await getPublicSlurs();
+ const publicSlursArray = publicSlurs.map((slur) => slur.label);
+ // console.log(publicSlursArray);
- //Crowdsourcing Slur
- try {
- // await createSlurAndCategory(user.accessToken, crowdsourceData);
- await createCrowdsourceSlur(crowdsourceData, user.token)
- console.log('finsihed POST req');
- window.alert(`Slur word "${slur}" added to Uli`);
- } catch (error) {
- console.log(error);
+ const filteredSlurs = [];
+ for (const slur of publicSlursArray) {
+ const exists = await slurExists(slur, source);
+ if (!exists) {
+ filteredSlurs.push(slur);
+ }
+ }
+ // If there are slurs to add, bulk add them to the database
+ if (filteredSlurs.length > 0) {
+ await bulkAddSlurs(filteredSlurs, source);
+ } else {
+ console.log('No new slurs to add.');
+ }
+ } catch (error) {
+ console.error('Error fetch public crowsrouced slurs');
+ }
}
+ if (request.message === 'URL_CHANGED') {
+ const newUrl = request.url;
+ log('Url Changed', newUrl);
+ processPage(location.href);
+ return true;
+ }
+ if (request.type === 'SLUR_ADDED') {
+ const slur = request.slur;
+ log('slur added from bg', slur);
+ let slurList;
- return true;
- }
+ const user = await getUserData();
+ // console.log('USER in content-script', user);
+ const crowdsourceData = {
+ label: slur
+ };
+
+ // Adding Slur to IndexedDB
+ try {
+ const exists = await slurExists(slur, 'personal');
+
+ if (!exists) {
+ await addSlur(slur, 'personal');
+ log('Slur added to IndexedDB:', slur);
+ } else {
+ log('Slur already exists in IndexedDB, skipping:', slur);
+ }
+ } catch (error) {
+ console.error('Error handling SLUR_ADDED request:', error);
+ }
+
+ //Crowdsourcing Slur
+ try {
+ // await createSlurAndCategory(user.accessToken, crowdsourceData);
+ await createCrowdsourceSlur(crowdsourceData, user.token);
+ console.log('finsihed POST req');
+ window.alert(`Slur word "${slur}" added to Uli`);
+ } catch (error) {
+ console.log(error);
+ }
+
+ return true;
+ }
- if (request.type === 'ULI_ENABLE_SLUR_REPLACEMENT') {
- console.log('Toggle change event received', request.payload);
- if (!request.payload) {
- clearInterval(mainLoadedChecker);
+ if (request.type === 'ULI_ENABLE_SLUR_REPLACEMENT') {
+ console.log('Toggle change event received', request.payload);
+ if (!request.payload) {
+ clearInterval(mainLoadedChecker);
+ }
}
}
-});
+);
window.addEventListener(
'load',
async () => {
console.log('content loaded');
const pref = await getPreferenceData();
- const { enableSlurReplacement , enableSlurMetadata } = pref;
+ const { enableSlurReplacement, enableSlurMetadata } = pref;
+
+ // Initialize Slurs on content load
+ await initializeSlurs();
+
if (enableSlurMetadata) {
let body = document.getElementsByTagName('body');
let first_body = body[0];
- transformGeneral.processNewlyAddedNodesGeneral2(first_body);
- }
- else if (enableSlurReplacement) {
+ const jsonData = await convertSlurMetadataFromDBtoJSON();
+ transformGeneral.processNewlyAddedNodesGeneral2(first_body, jsonData);
+ } else if (enableSlurReplacement) {
processPage(location.href);
}
},
diff --git a/browser-extension/plugin/src/slur-replace.js b/browser-extension/plugin/src/slur-replace.js
index 45dc17aa..9b420704 100644
--- a/browser-extension/plugin/src/slur-replace.js
+++ b/browser-extension/plugin/src/slur-replace.js
@@ -1,5 +1,4 @@
-import repository from './repository';
-const { getPreferenceData } = repository;
+import { getAllSlurs } from './slur-store';
const PUNCTUATIONS = [' ', '.', ',', ';', '#', '"'];
@@ -18,53 +17,53 @@ function generateMask(word, offset, string) {
}
}
-let slurList =
- 'जिहादी|छक्का|छिनाल|रंडी|रण्डी|रांड|रंडीखाना|रण्डी रोना|लुल्ली|गांड|गा#|कुतिया|कुत्ती|बत्तमीज़|कुल्टा|हरामजादी|साली|चो#|चुदाई|ma ki chui|मा के भोसड़े|भोस्डीके|भोछडी वाला |लोड़ू|बहन चोद|मादरचोद|लानती|छुतीये|चूतिये |चूत|लौड़ा|लौड़े|चरित्रहीन |लिब्राण्डू|नंगी पुंगी|पागल औरत |बाज़ारू औरत|बलात्कार|बदसूरत|मुजरा|जाहिल औरत|औरत-ए-जाहिल|भोसड़ीwala|चंडाल चौकड़ी|म्लेच्छा|सूअर|सूअर की औलाद|दोगली|🏹🏹|पनौती|हरामी|गधी|बुरखा धत्त|बुल्ली |कलमुंही |पिछवाड़ा|काम वाली बाई|पैर की जूती|नाल|गंदी नाली|हगना|सुल्ली|हिज़रापंती|naachne waali|तवाइफ़|सौ टका टंच माल|किन्नर|गद्दार|चमचा|चमची|आतंकवादी|मुलिया|Katwa|चाटुकार|बहन की लोड़ी|चुस्लिम|चुस्लामि|चुसल्मान|चूस|भीमटा|भीमटी|बैल बुद्धि|हलाला|भद्दी औरत|भांड औरत|भाड़े का टट्टू|दो कौड़ी की औरत|घटिया औरत|बेहूदा औरत|चालू औरत|झूठी औरत|मर क्यों नहीं जाती|नल्ली|भूतनी के|चूत के बाल|मादरजात|भड़वा|चूची|टट्टी|गटर पैदाइश|मुँह मैं ले|मूत|नाजायज़|कटा लुंड|काला टेंट|जूता खायेगी|बुरखे वाली|काली कलूटी|काले तवे|मोटी भैंस|देहातन|देहाती औरत|गणिका|हबशी|ओला हु उबर|ABLANARI|AblaNari|ablanari|chakka|jihidis|jihadis|jihadi|Jihidis|Jihadis|jihadi|zehadi|jehadan|jihadinon|Chakko|chakki|chaka|Chinal|Randi|ramdi|Randie|randya|randikhana|r&d-khana|randi ke beej|Lulli|Gasti|Meetha|Halwa|Gud|Gaandu|Gaand|Gandiaal|Dheela Lun@|lodu|kutiya|kutti|Chudail|Badchalan|Battameez|kulta|haramjadi|dyan|saali|sali|chod|chodu bhagat|chudai|chooda|chuda|Bhdsk|2BHK|Bhosi ke|bsdk|bhonsdi ke|bhosad|bhosdiwale|maa ka bhosra|Lodu|bhenchod|Madarchod|Maderchod|mcp|mc|Lanti|chutiye|chutiya|Chut|hutiye|chutie|chutia|chut ke dhakkan|chut marli|chutan|<3da|Lavde|Gandu|Rakhail|librandu|chal phut|nangi poongi|pagal aurat|bazaru|bazari aurat|ola hi uber hai|balatkar|Ugly|Mujra|mujra|jaahil aurat|Mulli|hilana|hilaogi|Mlechcha|Suar|suar ki aulad|doghli|Panauti|panooti|harami|gadhi|रनडwa|🅱️ulli|kalmuhi|pichwada|jhadu|bai|kaam wali bai|pair ki jutti|naali|hagna|tukde tukde gang|Sulli|नाचने वाली|Tawaif|sau taka tunch maal|Skirt waali bai|Dhimmi hood|Dhimmihood|izzlam|gaddar|chamcha|chamchi|aatankwadi|Mulliya|Uncut|chatukar|Bahan Ke loudi|Kachra|Chuslim|chuslami|Chusalmans|chus|Bhimta|bheem-meem walas|bail budhi|Budhdhi|हलाला|bhadi aurat|bhanndh aurat|bhadi ka tattu|2 Kaudi ki aurat|Gatiya|Ghatiya aurat|behuda aurat|chalu aurat|jhuti aurat|Kaali aurat|Kaali bhaand|marr kyun nahi jaati|nalli|dimaag se paidal|bhootni|bhootni ke|choot ke baal|madarjaat|bhadva|bhadvi|bhandve|chuchi|tatti|maa ka boba chusu|mooh|munh mein le|mutth|najayaz paidaish|najayaz aulaad|Gutter ki paidaish|kata Lund|kala tent|joota khayegi|burkhe waali|ladki kahin ka|victim card|Aurat card|kali kalutti|Kale tawe|naali saaf kar|moti bhains|sukkhi haddi|Pataka|choodiyan pehen lo|abba ka naam|Ganika|gaand phadna|chewtypa|atrocuty_act|RandiKutiya|sulli|Rice bags|ola u uber|lovejihad|dull-it|toxic aunty|Presstitutes|libtard|bimbo|slims|Black Pepper|faggot|Sissy|whore|chrislamocommies|piddilover|Dynast Sycophants|Deshdrohi Chinese|Pak agents|Chinese Corona|Chinks|chinky|Feminazi|Mulli|R@ndi|halala|Half M|Scumreds|scumbags|burnol|anti national tukde|pheminist|dented-painted|Muzlim|Buzlim|Izzlam|pissfull|Simp|Bitch| Ms |sekoolar|sickular|sc0undrel|R@pe|R@p3|Characterless woman|Drama Queen|Ferrorists|Cunt|Slut|pussy|ugly|stupid|promiscuous|crazy|fat|fag|homo|hoe|motherfucker|sisterfucker|bastard|b@st@rd|bint|dyke|gash|muslimette|muttah|scag|gender nigger|assfucker|boobs|boobies|Melons|lesbain|moslem|nasty|redlight|nymph|piss|pimp|poop|pube|puke|retarded|slave|sissy|ola uh uber|pu55i|pu55y|mothafuck|mothafucka|mothafuckaz|mothafucked|mothafucker|mothafuckin|mothafucking |mothafuckings|motherfuck|motherfucked|motherfucker|motherfuckin|motherfucking|motherfuckings|lesbain|lesbayn|lesbian|lesbin|lesbo|nastyslut|nastywhore|nastybitch|nastyho|#முட்டாஉபி|#பெரியாராவது_மயிராவது|#பாலியல்_ஜல்சா_கட்சி|பொம்பள பொருக்கி|#ங்கோத்தா|கோத்தா|#கோத்தா|#கொம்மா|தாயோளி|தேவ்டியா பையா|தேவ்டியா|#பொட்டை|#சாமான்|சூத்து|லெஸ்பியன்|ஊம்பு|புண்ட|#திருட்டு_பள்ளன்|ஐட்டம்|அயிட்டம்|சாமான்|கூதி|ஆட்டக்காரி|வேசை|வேச|பொதுச் சொத்து|ஊர் மேய்றது|நடத்தை கெட்டது|பொட்டை|க்ரோஸ்ஸி|தாயோளி|குஜ்ஜிலீஸ்|மாங்கா|கோழி|முலை|பறத்தாயோலி|ஓக்க|தேவடியா மவன்|தேவடியா பசங்களா|புண்டை|புண்ட|பொட்டை நாய்|வாயில பூல விடுவேன்|தேவிடியா புண்`ட|புண்டை சைடு|உங்கம்மாவை ஓக்க|தேவிடியாளுக்கு பொறந்தவன்|சூத்தடி|ஒன்பது|பொன்ஸ்|ஆப்ப மாமி|கம்பு துண்டு|கல்லு|ஆம்புள கள்ளன்|அலி|அரவாணி|பின்துவாரி|பொடியன் மாஸ்டர்|டிகி|குரும்ப|அத்தை|December 23, 2021|#ஓத்த|Sunflowerண்டை|Sunflowerண்டை|லூசு கூ|#OSISORU|#thevdiyaa|#thevdiya|#gommala|#Pundamavane|#pundai|#otha|Koodhi|pottai|Potta Alith|Aththai|athai|loosu|fuck|cunt';
-
-slurList = slurList.split('|');
-slurList = slurList.sort((a,b) => b.length - a.length);
-slurList = slurList.join('|');
-let expression = new RegExp(`(?:${slurList})`, 'gi');
-
+// Initialize the expression
+let expression;
+let expressionStatic;
// These are words that are not replaced if part of 'slurList'
let missedSlurListStatic = 'லூசு|கூFire';
-missedSlurListStatic = missedSlurListStatic.split('|');
-missedSlurListStatic = missedSlurListStatic.sort((a,b) => b.length - a.length);
-missedSlurListStatic = missedSlurListStatic.join('|');
-let expressionStatic = new RegExp(`(?:${missedSlurListStatic})`, 'gi');
-
// These are words that are not replaced if part of 'slurList' and contain escape character
let missedEscapedSlurListStatic = 'choo$iya';
-(async () => {
- const preference = await getPreferenceData();
- console.log(preference);
- if (preference.slurList != undefined) {
- updateSlurList(preference.slurList);
+// Function to initialize/update the expression's
+async function initializeExpressions() {
+ try {
+ // Fetch all words
+ const allSlurWords = await getAllSlurs();
+ const slurList = allSlurWords.map((wordObj) => wordObj.word);
+ console.log("Slur words fetched from DB", slurList.length);
+
+ // Sort and join slur list
+ const sortedSlurList = slurList.sort((a, b) => b.length - a.length).join('|');
+ expression = new RegExp(`(?:${sortedSlurList})`, 'gi');
+
+ const sortedMissedList = missedSlurListStatic.split('|').sort((a, b) => b.length - a.length).join('|');
+ expressionStatic = new RegExp(`(?:${sortedMissedList})`, 'gi');
+
+ console.log('Expressions initialized with slurs.');
+ } catch (error) {
+ console.error('Error initializing expressions:', error);
}
+}
+
+// Initialize expressions on module load
+(async () => {
+ await initializeExpressions();
})();
export function replaceSlur(sentence) {
+ // Ensure expressions are initialized
+ if (!expression || !expressionStatic) {
+ throw new Error('Expressions not initialized. Call initializeExpressions first.');
+ }
+
sentence = sentence.replace(expression, generateMask);
sentence = sentence.replace(expressionStatic, generateMask);
sentence = sentence.replace(missedEscapedSlurListStatic, generateMask);
+
return sentence;
}
-export function updateSlurList(newSlurs) {
- const list = newSlurs.split(',').join('|');
- slurList = slurList + '|' + list;
-
- slurList = slurList.split('|');
- slurList = slurList.sort((a,b) => b.length - a.length);
- slurList = slurList.join('|');
- expression = new RegExp(`(?:${slurList})`, 'gi');
- missedSlurListStatic = missedSlurListStatic.split('|');
- missedSlurListStatic = missedSlurListStatic.sort((a,b) => b.length - a.length);
- missedSlurListStatic = missedSlurListStatic.join('|');
- expressionStatic = new RegExp(`(?:${missedSlurListStatic})`, 'gi');
- }
-
function testSlurReplace() {
// inputs space-separated slurList to get masked output
diff --git a/browser-extension/plugin/src/slur-store.js b/browser-extension/plugin/src/slur-store.js
new file mode 100644
index 00000000..caf352c5
--- /dev/null
+++ b/browser-extension/plugin/src/slur-store.js
@@ -0,0 +1,208 @@
+import Dexie from 'dexie';
+import mainSlurList from './slurlist-main';
+import { getPublicSlursMetadata } from './api/public-slurs';
+
+const db = new Dexie('SlurWordsDatabase');
+
+// Define database schema
+db.version(1).stores({
+ words: '++id, word, source',
+ words_metadata: '++id, label, level_of_severity, meaning, categories, language, timestamp'
+});
+
+// Function to add a word to the database
+export async function addSlur(word, source) {
+ try {
+ const id = await db.words.add({
+ word: word,
+ timestamp: new Date().toISOString(),
+ source: source
+ });
+ return id;
+ } catch (error) {
+ console.error(`Error adding word to database: ${error}`);
+ throw error;
+ }
+}
+
+// Function to get all words
+export async function getAllSlurs() {
+ try {
+ const words = await db.words.toArray();
+ return words;
+ } catch (error) {
+ console.error(`Error getting all words from database: ${error}`);
+ throw error;
+ }
+}
+
+// Function to get all words by source
+export async function getSlursBySource(source) {
+ try {
+ if (!source || typeof source !== 'string') {
+ throw new Error('Source must be a valid string');
+ }
+ const words = await db.words.where('source').equals(source).toArray();
+ return words;
+ } catch (error) {
+ console.error(`Error getting words by source "${source}":`, error);
+ throw error;
+ }
+}
+
+// Function to bulk add words to the database
+export async function bulkAddSlurs(wordsArray, source) {
+ if (!Array.isArray(wordsArray) || typeof source !== 'string') {
+ throw new Error('Invalid input: wordsArray must be an array and source must be a string');
+ }
+
+ // Prepare word objects with source and timestamp
+ const wordObjects = wordsArray.map((word) => ({
+ word: word,
+ timestamp: new Date().toISOString(),
+ source: source
+ }));
+
+ try {
+ await db.words.bulkAdd(wordObjects);
+ console.log(`${wordObjects.length} words added from source: ${source}`);
+ } catch (error) {
+ console.error(`Error adding words from source "${source}":`, error);
+ throw error;
+ }
+}
+
+// Function to delete a single slur
+export async function deleteSlur(word, source) {
+ try {
+ const slurToDelete = await db.words
+ .where('source')
+ .equals(source)
+ .and((slur) => slur.word === word)
+ .first(); // Fetch only the first matching slur
+
+ if (slurToDelete) {
+ await db.words.delete(slurToDelete.id);
+ console.log(`Deleted slur "${word}" from source "${source}".`);
+ } else {
+ console.log(`Slur "${word}" not found for source "${source}".`);
+ }
+ } catch (error) {
+ console.error(`Error deleting slur "${word}" from source "${source}":`, error);
+ }
+}
+
+// Function to check if a slur exists in the database
+export async function slurExists(word, source) {
+ try {
+ const count = await db.words
+ .where('source')
+ .equals(source)
+ .filter((slur) => slur.word === word)
+ .count();
+ return count > 0; // Returns true if the slur exists, else false
+ } catch (error) {
+ console.error(`Error checking if slur exists: ${error}`);
+ throw error;
+ }
+}
+
+// Function to bulk add slur metadata to the database
+export async function bulkAddSlurMetadata(metadataArray) {
+ if (!Array.isArray(metadataArray)) {
+ throw new Error('Invalid input: metadataArray must be an array');
+ }
+
+ // Prepare metadata objects for the database
+ const timestamp = new Date().toISOString();
+ const metadataObjects = metadataArray.map((metadata) => ({
+ label: metadata.label,
+ level_of_severity: metadata.level_of_severity,
+ meaning: metadata.meaning,
+ categories: metadata.categories,
+ language: metadata.language,
+ timestamp: timestamp,
+ }));
+
+ try {
+ await db.words_metadata.bulkAdd(metadataObjects);
+ console.log(`${metadataObjects.length} slur metadata added.`);
+ } catch (error) {
+ console.error('Error adding slur metadata:', error);
+ throw error;
+ }
+}
+
+// Function to fetch all slur metadata from the database
+export async function getAllSlurMetadata() {
+ try {
+ const slurMetadata = await db.words_metadata.toArray();
+ return slurMetadata;
+ } catch (error) {
+ console.error('Error fetching slur metadata:', error);
+ throw error;
+ }
+}
+
+export async function convertSlurMetadataFromDBtoJSON() {
+ try {
+ const slurMetadata = await getAllSlurMetadata();
+
+ // Format the data into the desired structure
+ let jsonData = [];
+ jsonData = slurMetadata.map(slur => {
+ return {
+ [slur.label]: {
+ "Level of Severity": slur.level_of_severity,
+ "Casual": slur.casual ? "Yes" : "No",
+ "Appropriated": slur.appropriated ? "Yes" : "No",
+ "If, Appropriated, Is it by Community or Others?": slur.appropriation_context || "",
+ "What Makes it Problematic?": slur.meaning || "",
+ "Categories": slur.categories
+ }
+ };
+ });
+
+ console.log("Formatted jsonData:", jsonData);
+ return jsonData;
+ } catch (error) {
+ console.error('Error fetching or formatting slur metadata:', error);
+ }
+}
+
+export async function initializeSlurs() {
+ console.log('Initializing Indexed database');
+
+ try {
+ // Check if any words with source "hard_coded" already exist
+ const hardCodedWordCount = await db.words
+ .where('source')
+ .equals('hard_coded')
+ .count();
+
+ if (hardCodedWordCount > 0) {
+ console.log('Hard-coded slurs already exist in the database. Skipping initialization.');
+ return;
+ }
+
+ const mainSlurListArray = mainSlurList.split('|');
+ // Index hard-coded slurs into the database
+ if (mainSlurListArray.length > 0) {
+ await bulkAddSlurs(mainSlurListArray, 'hard_coded');
+ console.log(`Indexed ${mainSlurListArray.length} hard-coded slurs into the database.`);
+ } else {
+ console.log('No slurs found in the JSON file.');
+ }
+
+ // Fetch and store public slurs metadata
+ try {
+ const publicSlursMetadata = await getPublicSlursMetadata();
+ // console.log('Public Slurs Metadata:', publicSlursMetadata);
+ await bulkAddSlurMetadata(publicSlursMetadata);
+ } catch (error) {
+ console.error('Error fetching and adding public slurs metadata:', error);
+ }
+ } catch (error) {
+ console.error('Error during database initialization:', error);
+ }
+}
diff --git a/browser-extension/plugin/src/slurlist-main.js b/browser-extension/plugin/src/slurlist-main.js
new file mode 100644
index 00000000..252698ba
--- /dev/null
+++ b/browser-extension/plugin/src/slurlist-main.js
@@ -0,0 +1,4 @@
+const mainSlurList =
+ 'जिहादी|छक्का|छिनाल|रंडी|रण्डी|रांड|रंडीखाना|रण्डी रोना|लुल्ली|गांड|गा#|कुतिया|कुत्ती|बत्तमीज़|कुल्टा|हरामजादी|साली|चो#|चुदाई|ma ki chui|मा के भोसड़े|भोस्डीके|भोछडी वाला |लोड़ू|बहन चोद|मादरचोद|लानती|छुतीये|चूतिये |चूत|लौड़ा|लौड़े|चरित्रहीन |लिब्राण्डू|नंगी पुंगी|पागल औरत |बाज़ारू औरत|बलात्कार|बदसूरत|मुजरा|जाहिल औरत|औरत-ए-जाहिल|भोसड़ीwala|चंडाल चौकड़ी|म्लेच्छा|सूअर|सूअर की औलाद|दोगली|🏹🏹|पनौती|हरामी|गधी|बुरखा धत्त|बुल्ली |कलमुंही |पिछवाड़ा|काम वाली बाई|पैर की जूती|नाल|गंदी नाली|हगना|सुल्ली|हिज़रापंती|naachne waali|तवाइफ़|सौ टका टंच माल|किन्नर|गद्दार|चमचा|चमची|आतंकवादी|मुलिया|Katwa|चाटुकार|बहन की लोड़ी|चुस्लिम|चुस्लामि|चुसल्मान|चूस|भीमटा|भीमटी|बैल बुद्धि|हलाला|भद्दी औरत|भांड औरत|भाड़े का टट्टू|दो कौड़ी की औरत|घटिया औरत|बेहूदा औरत|चालू औरत|झूठी औरत|मर क्यों नहीं जाती|नल्ली|भूतनी के|चूत के बाल|मादरजात|भड़वा|चूची|टट्टी|गटर पैदाइश|मुँह मैं ले|मूत|नाजायज़|कटा लुंड|काला टेंट|जूता खायेगी|बुरखे वाली|काली कलूटी|काले तवे|मोटी भैंस|देहातन|देहाती औरत|गणिका|हबशी|ओला हु उबर|ABLANARI|AblaNari|ablanari|chakka|jihidis|jihadis|jihadi|Jihidis|Jihadis|jihadi|zehadi|jehadan|jihadinon|Chakko|chakki|chaka|Chinal|Randi|ramdi|Randie|randya|randikhana|r&d-khana|randi ke beej|Lulli|Gasti|Meetha|Halwa|Gud|Gaandu|Gaand|Gandiaal|Dheela Lun@|lodu|kutiya|kutti|Chudail|Badchalan|Battameez|kulta|haramjadi|dyan|saali|sali|chod|chodu bhagat|chudai|chooda|chuda|Bhdsk|2BHK|Bhosi ke|bsdk|bhonsdi ke|bhosad|bhosdiwale|maa ka bhosra|Lodu|bhenchod|Madarchod|Maderchod|mcp|mc|Lanti|chutiye|chutiya|Chut|hutiye|chutie|chutia|chut ke dhakkan|chut marli|chutan|<3da|Lavde|Gandu|Rakhail|librandu|chal phut|nangi poongi|pagal aurat|bazaru|bazari aurat|ola hi uber hai|balatkar|Ugly|Mujra|mujra|jaahil aurat|Mulli|hilana|hilaogi|Mlechcha|Suar|suar ki aulad|doghli|Panauti|panooti|harami|gadhi|रनडwa|🅱️ulli|kalmuhi|pichwada|jhadu|bai|kaam wali bai|pair ki jutti|naali|hagna|tukde tukde gang|Sulli|नाचने वाली|Tawaif|sau taka tunch maal|Skirt waali bai|Dhimmi hood|Dhimmihood|izzlam|gaddar|chamcha|chamchi|aatankwadi|Mulliya|Uncut|chatukar|Bahan Ke loudi|Kachra|Chuslim|chuslami|Chusalmans|chus|Bhimta|bheem-meem walas|bail budhi|Budhdhi|हलाला|bhadi aurat|bhanndh aurat|bhadi ka tattu|2 Kaudi ki aurat|Gatiya|Ghatiya aurat|behuda aurat|chalu aurat|jhuti aurat|Kaali aurat|Kaali bhaand|marr kyun nahi jaati|nalli|dimaag se paidal|bhootni|bhootni ke|choot ke baal|madarjaat|bhadva|bhadvi|bhandve|chuchi|tatti|maa ka boba chusu|mooh|munh mein le|mutth|najayaz paidaish|najayaz aulaad|Gutter ki paidaish|kata Lund|kala tent|joota khayegi|burkhe waali|ladki kahin ka|victim card|Aurat card|kali kalutti|Kale tawe|naali saaf kar|moti bhains|sukkhi haddi|Pataka|choodiyan pehen lo|abba ka naam|Ganika|gaand phadna|chewtypa|atrocuty_act|RandiKutiya|sulli|Rice bags|ola u uber|lovejihad|dull-it|toxic aunty|Presstitutes|libtard|bimbo|slims|Black Pepper|faggot|Sissy|whore|chrislamocommies|piddilover|Dynast Sycophants|Deshdrohi Chinese|Pak agents|Chinese Corona|Chinks|chinky|Feminazi|Mulli|R@ndi|halala|Half M|Scumreds|scumbags|burnol|anti national tukde|pheminist|dented-painted|Muzlim|Buzlim|Izzlam|pissfull|Simp|Bitch| Ms |sekoolar|sickular|sc0undrel|R@pe|R@p3|Characterless woman|Drama Queen|Ferrorists|Cunt|Slut|pussy|ugly|stupid|promiscuous|crazy|fat|fag|homo|hoe|motherfucker|sisterfucker|bastard|b@st@rd|bint|dyke|gash|muslimette|muttah|scag|gender nigger|assfucker|boobs|boobies|Melons|lesbain|moslem|nasty|redlight|nymph|piss|pimp|poop|pube|puke|retarded|slave|sissy|ola uh uber|pu55i|pu55y|mothafuck|mothafucka|mothafuckaz|mothafucked|mothafucker|mothafuckin|mothafucking |mothafuckings|motherfuck|motherfucked|motherfucker|motherfuckin|motherfucking|motherfuckings|lesbain|lesbayn|lesbian|lesbin|lesbo|nastyslut|nastywhore|nastybitch|nastyho|#முட்டாஉபி|#பெரியாராவது_மயிராவது|#பாலியல்_ஜல்சா_கட்சி|பொம்பள பொருக்கி|#ங்கோத்தா|கோத்தா|#கோத்தா|#கொம்மா|தாயோளி|தேவ்டியா பையா|தேவ்டியா|#பொட்டை|#சாமான்|சூத்து|லெஸ்பியன்|ஊம்பு|புண்ட|#திருட்டு_பள்ளன்|ஐட்டம்|அயிட்டம்|சாமான்|கூதி|ஆட்டக்காரி|வேசை|வேச|பொதுச் சொத்து|ஊர் மேய்றது|நடத்தை கெட்டது|பொட்டை|க்ரோஸ்ஸி|தாயோளி|குஜ்ஜிலீஸ்|மாங்கா|கோழி|முலை|பறத்தாயோலி|ஓக்க|தேவடியா மவன்|தேவடியா பசங்களா|புண்டை|புண்ட|பொட்டை நாய்|வாயில பூல விடுவேன்|தேவிடியா புண்`ட|புண்டை சைடு|உங்கம்மாவை ஓக்க|தேவிடியாளுக்கு பொறந்தவன்|சூத்தடி|ஒன்பது|பொன்ஸ்|ஆப்ப மாமி|கம்பு துண்டு|கல்லு|ஆம்புள கள்ளன்|அலி|அரவாணி|பின்துவாரி|பொடியன் மாஸ்டர்|டிகி|குரும்ப|அத்தை|December 23, 2021|#ஓத்த|Sunflowerண்டை|Sunflowerண்டை|லூசு கூ|#OSISORU|#thevdiyaa|#thevdiya|#gommala|#Pundamavane|#pundai|#otha|Koodhi|pottai|Potta Alith|Aththai|athai|loosu|fuck|cunt';
+
+export default mainSlurList;
diff --git a/browser-extension/plugin/src/transform-general.js b/browser-extension/plugin/src/transform-general.js
index 731637e3..a7c5178b 100644
--- a/browser-extension/plugin/src/transform-general.js
+++ b/browser-extension/plugin/src/transform-general.js
@@ -2,7 +2,6 @@ import { replaceSlur } from './slur-replace';
import { log } from './logger';
import repository from './repository';
const { getPreferenceData } = repository;
-const jsonData = require('../../api-server/assets/slur_metadata.json')
// Traverse dom nodes to find leaf node that are text nodes and process
function bft(node) {
@@ -50,18 +49,19 @@ function setCaretPosition(element, offset) {
sel.addRange(range);
}
-const processNewlyAddedNodesGeneral2 = function (firstBody) {
- let targetWords = [] ;
+const processNewlyAddedNodesGeneral2 = function (firstBody, jsonData) {
+ let targetWords = [];
jsonData.forEach(slur => {
const slurWord = Object.keys(slur)[0];
- targetWords.push(slurWord) ;
+ targetWords.push(slurWord);
targetWords.push(slurWord.charAt(0).toUpperCase() + slurWord.slice(1));
- })
- let uliStore = []
- getAllTextNodes(firstBody, uliStore)
- abc = locateSlur(uliStore, targetWords)
- addMetaData(targetWords)
-}
+ });
+
+ let uliStore = [];
+ getAllTextNodes(firstBody, uliStore);
+ abc = locateSlur(uliStore, targetWords);
+ addMetaData(targetWords, jsonData);
+};
const processNewlyAddedNodesGeneral = function (firstBody) {
log('processing new nodes');
@@ -150,7 +150,7 @@ function locateSlur(uliStore, targetWords) {
const className = `icon-container-${targetWord}`;
const slurClass = `slur-container-${targetWord}`
const parts = tempParent.innerHTML.split(targetWord);
- console.log("PARTS: ",parts)
+ // console.log("PARTS: ",parts)
const replacedHTML = parts.join(`${targetWord}`);
tempParent.innerHTML = replacedHTML
slurPresentInTempParent = true;
@@ -164,20 +164,20 @@ function locateSlur(uliStore, targetWords) {
textnode.replaceWith(tempParent)
}
- console.log("TEMPParent: ",tempParent)
+ // console.log("TEMPParent: ",tempParent)
}
return uliStore;
}
-function addMetaData(targetWords) {
+function addMetaData(targetWords, jsonData) {
// console.log(targetWords)
targetWords.forEach(targetWord => {
const className = `slur-container-${targetWord}`
const elements = Array.from(document.querySelectorAll(`.${className}`))
- console.log("ELEMENTS are: ",elements)
+ // console.log("ELEMENTS are: ",elements)
elements.forEach(element => {
- console.log("ELements InnerHTML:",element.innerHTML)
+ // console.log("ELements InnerHTML:",element.innerHTML)
// element.innerHTML = element.innerHTML.replace(/
]*>/g, '')
@@ -268,15 +268,15 @@ function addMetaData(targetWords) {
sup.appendChild(span)
- console.log("Element first child",element.children[0])
- console.log("Element last child",element.children[element.children.length-1])
- console.log("SUP: ",sup)
- console.log("ELEMENT IS: ",element)
- console.log("ELEMENT INNERHTML: ",element.innerHTML)
+ // console.log("Element first child",element.children[0])
+ // console.log("Element last child",element.children[element.children.length-1])
+ // console.log("SUP: ",sup)
+ // console.log("ELEMENT IS: ",element)
+ // console.log("ELEMENT INNERHTML: ",element.innerHTML)
element.append(span)
- console.log("ELEMENT AFTER IS: ",element)
+ // console.log("ELEMENT AFTER IS: ",element)
// element.append(img)
let slur = element.children[0]
slur.style.backgroundColor="#ffde2155"
@@ -284,7 +284,7 @@ function addMetaData(targetWords) {
slur.style.cursor = "pointer"
let metabox = element.children[1]
- console.log("METABOX IS: ",metabox)
+ // console.log("METABOX IS: ",metabox)
let spans = element.children[0].children[1]
// const svgs = element.children[0].children[0];
const svgs = element.children[element.children.length-1];
diff --git a/browser-extension/plugin/src/ui-components/pages/App.jsx b/browser-extension/plugin/src/ui-components/pages/App.jsx
index d3fe2034..6a2ba42b 100644
--- a/browser-extension/plugin/src/ui-components/pages/App.jsx
+++ b/browser-extension/plugin/src/ui-components/pages/App.jsx
@@ -219,4 +219,4 @@ export function App() {
);
-}
+}
\ No newline at end of file
diff --git a/browser-extension/plugin/src/ui-components/pages/Preferences.jsx b/browser-extension/plugin/src/ui-components/pages/Preferences.jsx
index cc65fb03..d4068fba 100644
--- a/browser-extension/plugin/src/ui-components/pages/Preferences.jsx
+++ b/browser-extension/plugin/src/ui-components/pages/Preferences.jsx
@@ -9,7 +9,8 @@ import {
Button,
Select,
CheckBox,
- RadioButtonGroup
+ RadioButtonGroup,
+ Tip
} from 'grommet';
// import { HelpCircle } from 'react-feather';
import Api from '../pages/Api';
@@ -21,7 +22,7 @@ const { savePreference } = Api;
import { UserContext, NotificationContext } from '../atoms/AppContext';
import { userBrowserTabs } from '../../browser-compat';
import { Link, Outlet, useNavigate } from 'react-router-dom';
-import { FormClose, FormPreviousLink, LinkPrevious } from 'grommet-icons';
+import { FormClose, FormPreviousLink, LinkPrevious, Sync } from 'grommet-icons';
const { setPreferenceData, getPreferenceData } = repository;
const defaultValue = {};
@@ -221,7 +222,7 @@ export function PreferencesHome() {
type: 'message',
message: t('message_ok_saved')
});
- browserUtils.sendMessage('updateData', undefined);
+ // browserUtils.sendMessage('updateData', undefined);
} catch (err) {
showNotification({
type: 'error',
@@ -236,10 +237,33 @@ export function PreferencesHome() {
i18n.changeLanguage(langNameMap[option]);
}
+ async function handleSyncApprovedSlurs() {
+ try {
+ browserUtils.sendMessage('syncApprovedCrowdsourcedSlurs', undefined);
+
+ console.log('Sync message sent to content-script.js');
+ } catch (error) {
+ console.error('Error syncing approved slurs:', error);
+ }
+ }
+
return (
- {t('language')}
+
+ {t('language')}
+ }
+ onClick={handleSyncApprovedSlurs}
+ plain
+ title="Add Approved Crowdsourced Slurs"
+ style={{
+ border: '1px solid black',
+ borderRadius: '4px',
+ padding: '4px',
+ }}
+ />
+