From e94e5f2e076d40705beac8438a498f6aef8e67d9 Mon Sep 17 00:00:00 2001 From: Jean Date: Mon, 23 Dec 2024 02:58:48 -0800 Subject: [PATCH] Implementing prn, pov, and plv --- src/content_script.js | 292 ++++++++++++++++++++++++++++----------- src/options/options.css | 1 - src/options/options.html | 40 +++--- src/options/options.js | 36 +++-- 4 files changed, 258 insertions(+), 111 deletions(-) diff --git a/src/content_script.js b/src/content_script.js index 61fba69..67a9893 100644 --- a/src/content_script.js +++ b/src/content_script.js @@ -1,103 +1,241 @@ -DEACTIVATE_KEY = 'deactivate-this-extension-pls-interactive-fics-yalla-bina'; -MUTATION_OBSERVER_KEY = 'observe-this-dom-pls-interactive-fics-yalla-bina'; PAUSED_KEY = 'pause-this-domain-pls-interactive-fics-yalla-bina'; - -chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { - if ('input_word' in message){ - escapeAndReplace(message.input_word, message.replace_value, message.case_sensitive) - } else { - replaceAll() - } +browser.runtime.onMessage.addListener((message, sender, sendResponse) => { + if ('input_word' in message){ + escapeAndReplace(message.input_word, message.replace_value, message.case_sensitive) + } else { + replaceAll() + } }); const replaceAll = () => { - chrome.storage.sync.get(null, replaceAllInStorage) - chrome.storage.local.get(null, replaceAllInStorage) + browser.storage.local.get(null, replaceAllInStorage) } -const observeChanges = () => { - chrome.storage.sync.get(MUTATION_OBSERVER_KEY, obj => { - if (obj[MUTATION_OBSERVER_KEY]) { - const observer = new MutationObserver((mutation_list, observer) => { - replaceAll() - }) - observer.observe(document, { - subtree: true, - childList: true - }) - } - }) +const replaceAllInStorage = (options) => { + const hostname = window.location.hostname + const is_paused = options[PAUSED_KEY] && options[PAUSED_KEY].indexOf(hostname) !== -1 + if (true) { // change paused later to only care about hostname + replaceName(options); + replacePronouns(options); + replacePov(options); + replacePlv(options); + replaceAlso(options); + } } -const replaceAllInStorage = (items) => { - const hostname = window.location.hostname - const is_paused = items[PAUSED_KEY] && items[PAUSED_KEY].indexOf(hostname) !== -1 - if (!items[DEACTIVATE_KEY] && !is_paused) { - for (var key in items) { - if (key == 'person') { - const regexp_y_n = /\by\/n\b|\(y\/n\)|\[y\/n\]/ig - replace(regexp_y_n, items[key]) - } else if (key !== DEACTIVATE_KEY && !key.endsWith('_case_sensitive')) { - escapeAndReplace(key, items[key], items[`${key}_case_sensitive`]) - } - } - } +function replaceName(options) { + const regexp = /\by\/n\b|\(y\/n\)|\[y\/n\]/ig; + replace(regexp, options["name"]); } -const escapeAndReplace = (input_word, replace_value, case_sensitive) => { - if (input_word.length == 0) { return; } - let input_word_escaped = escapeRegExp(input_word.trim()) - const flags = case_sensitive ? "g" : "ig" - if (input_word_escaped[0].match(/[a-z]/i)) { - input_word_escaped = `\\b${input_word_escaped}` - } - if (input_word_escaped[input_word_escaped.length - 1].match((/[a-z]/i))) { - input_word_escaped = `${input_word_escaped}\\b` - } - const regexp_input_word = new RegExp(input_word_escaped, flags) - replace(regexp_input_word, replace_value) +// TODO case sensitivity, premade regexp +function replacePronouns(options) { + if (options.preset == "") { return; } + let pronouns = getPronouns(options.preset, options.other); + replacePronounSet("Prn/s", "prn/s", pronouns["subjective"]); + replacePronounSet("Prn/o", "prn/o", pronouns["objective"]); + replacePronounSet("Prn/p", "prn/p", pronouns["possessive"]); + replacePronounSet("Prn/a", "prn/a", pronouns["adjective"]); + replacePronounSet("Prn/r", "prn/r", pronouns["reflexive"]); + replacePronounSet("Prn/H", "prn/H", pronouns["honorific-abbr"]); + replacePronounSet("Prn/h", "prn/h", pronouns["honorific"]); + replacePronounSet("Prn/N", "prn/N", pronouns["noun-adult"]); + replacePronounSet("Prn/n", "prn/n", pronouns["noun-child"]); +} + +function getPronouns(key, other) { + switch (key) { + case "she": + return { + "subjective": "she", + "objective": "her", + "possessive": "her", + "adjective": "hers", + "reflexive": "herself", + "honorific-abbr": "Ms.", + "honorific": "miss", + "noun-adult": "woman", + "noun-child": "girl", + "plurality": "singular" + }; + case "he": + return { + "subjective": "he", + "objective": "him", + "possessive": "his", + "adjective": "his", + "reflexive": "himself", + "honorific-abbr": "Mr.", + "honorific": "mister", + "noun-adult": "man", + "noun-child": "boy", + "plurality": "singular" + }; + case "they": + return { + "subjective": "they", + "objective": "them", + "possessive": "their", + "adjective": "theirs", + "reflexive": "themself", + "honorific-abbr": "Mx.", + "honorific": "mix", + "noun-adult": "person", + "noun-child": "kid", + "plurality": "plural" + }; + case "first": + return { + "subjective": "I", + "objective": "me", + "possessive": "my", + "adjective": "mine", + "reflexive": "myself" + }; + case "second": + return { + "subjective": "you", + "objective": "you", + "possessive": "your", + "adjective": "yours", + "reflexive": "yourself" + }; + case "first-plural": + return { + "subjective": "we", + "objective": "us", + "possessive": "our", + "adjective": "ours", + "reflexive": "ourselves" + }; + case "second-plural": + return { + "subjective": "you", + "objective": "you", + "possessive": "your", + "adjective": "yours", + "reflexive": "yourselves" + }; + case "third-plural": + return { + "subjective": "they", + "objective": "them", + "possessive": "their", + "adjective": "theirs", + "reflexive": "themselves" + }; + case "other": + return options.other; + } +} + +function replacePronounSet(keyCapital, key, pronoun) { + if (pronoun === undefined) { return; } + escapeAndReplace(keyCapital, capitalize(pronoun), true); + escapeAndReplace(key, pronoun, true); +} + +function replacePov(options) { + let pronouns; + switch (options.pov) { + case "": + return; + case "third": + pronouns = getPronouns(options.preset, options.other); + replacePronounSet("Pov/S", "pov/S", options.name); + replacePronounSet("Pov/O", "pov/O", options.name); + replacePronounSet("Pov/P", "pov/P", options.name + "'s"); + replacePronounSet("Pov/A", "pov/A", options.name + "'s"); + replacePronounSet("Pov/R", "pov/R", options.name + "'s self"); + break; + default: + pronouns = getPronouns(options.pov, null); + replacePronounSet("Pov/S", "pov/S", pronouns["subjective"]); + replacePronounSet("Pov/O", "pov/O", pronouns["objective"]); + replacePronounSet("Pov/P", "pov/P", pronouns["possessive"]); + replacePronounSet("Pov/A", "pov/A", pronouns["adjective"]); + replacePronounSet("Pov/R", "pov/R", pronouns["reflexive"]); + } + + replacePronounSet("Pov/s", "pov/s", pronouns["subjective"]); + replacePronounSet("Pov/o", "pov/o", pronouns["objective"]); + replacePronounSet("Pov/p", "pov/p", pronouns["possessive"]); + replacePronounSet("Pov/a", "pov/a", pronouns["adjective"]); + replacePronounSet("Pov/r", "pov/r", pronouns["reflexive"]); +} + +function replacePlv(options) { + if (options.pov == "") { return; } + let pronouns = getPronouns(options.pov + "-plural", null); + replacePronounSet("Plv/s", "plv/s", pronouns["subjective"]); + replacePronounSet("Plv/o", "plv/o", pronouns["objective"]); + replacePronounSet("Plv/p", "plv/p", pronouns["possessive"]); + replacePronounSet("Plv/a", "plv/a", pronouns["adjective"]); + replacePronounSet("Plv/r", "plv/r", pronouns["reflexive"]); +} + +function replaceAlso(options) { + Object.entries(options.also).forEach(([key, value]) => { + escapeAndReplace(key, value, true); + }); +} + +function escapeAndReplace(input_word, replace_value, case_sensitive) { + let input_word_escaped = escapeRegExp(input_word.trim()) + const flags = case_sensitive ? "g" : "ig" + if (input_word_escaped[0].match(/[a-z]/i)) { + input_word_escaped = `\\b${input_word_escaped}` + } + if (input_word_escaped[input_word_escaped.length - 1].match((/[a-z]/i))) { + input_word_escaped = `${input_word_escaped}\\b` + } + const regexp_input_word = new RegExp(input_word_escaped, flags) + replace(regexp_input_word, replace_value) } const escapeRegExp = (str) => str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") const replace = (input_word, replace_value) => { - chrome.storage.sync.get(DEACTIVATE_KEY, obj => { - if (replace_value && !obj[DEACTIVATE_KEY]) { - walk(document.body, input_word, replace_value) - } - }) + browser.storage.local.get(obj => { + if (replace_value) { + walk(document.body, input_word, replace_value) + } + }) } const replaceText = (textNode, input_word, replace_value) => { - let node_value = textNode.nodeValue - node_value = node_value.replace(input_word, replace_value) - textNode.nodeValue = node_value + let node_value = textNode.nodeValue + node_value = node_value.replace(input_word, replace_value) + textNode.nodeValue = node_value } function walk(node, v, p){ - // I stole the base to this function from here: - // http://is.gd/mwZp7E - if (node.contentEditable != 'true' && node.type != 'textarea' && node.type != 'input') { - var child, next; - switch (node.nodeType){ - case 1: // Element - case 9: // Document - case 11: // Document fragment - child = node.firstChild; - while (child){ - next = child.nextSibling; - walk(child, v, p); - child = next; - } - break; - case 3: // Text node - replaceText(node, v, p); - break; - } - } + // I stole the base to this function from here: + // https://stackoverflow.com/questions/5904914/javascript-regex-to-replace-text-not-in-html-attributes/5904945 + if (node.contentEditable != 'true' && node.type != 'textarea' && node.type != 'input') { + var child, next; + switch (node.nodeType){ + case 1: // Element + case 9: // Document + case 11: // Document fragment + child = node.firstChild; + while (child){ + next = child.nextSibling; + walk(child, v, p); + child = next; + } + break; + case 3: // Text node + replaceText(node, v, p); + break; + } + } +} + +function capitalize(word) { + return word.charAt(0).toUpperCase() + word.slice(1); } replaceAll() -observeChanges() diff --git a/src/options/options.css b/src/options/options.css index 487dade..b062f63 100644 --- a/src/options/options.css +++ b/src/options/options.css @@ -90,7 +90,6 @@ label { visibility: hidden; } - #button-grid { display: grid; grid-template-columns: 2fr 1fr; diff --git a/src/options/options.html b/src/options/options.html index 63b1d16..441cebf 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -33,53 +33,53 @@