Implementing prn, pov, and plv

This commit is contained in:
Jean Viscogliosi-Pate 2024-12-23 02:58:48 -08:00
parent 731825b755
commit e94e5f2e07
4 changed files with 258 additions and 111 deletions

View File

@ -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()

View File

@ -90,7 +90,6 @@ label {
visibility: hidden;
}
#button-grid {
display: grid;
grid-template-columns: 2fr 1fr;

View File

@ -33,53 +33,53 @@
<ul id="other">
<li>
<label for="prn-s">Subjective</label>
<input type="text" id="prn-s" name="subjective" placeholder="e.g. he, they">
<label for="subjective">Subjective</label>
<input type="text" id="subjective" name="subjective" placeholder="e.g. he, they">
</li>
<li>
<label for="prn-o">Objective</label>
<input type="text" id="prn-o" name="objective" placeholder="e.g. her, them">
<label for="objective">Objective</label>
<input type="text" id="objective" name="objective" placeholder="e.g. her, them">
</li>
<li>
<label for="prn-p">Possessive</label>
<input type="text" id="prn-p" name="possessive" placeholder="e.g. his, their">
<label for="possessive">Possessive</label>
<input type="text" id="possessive" name="possessive" placeholder="e.g. his, their">
</li>
<li>
<label for="prn-a">Adjective</label>
<input type="text" id="prn-a" name="adjective" placeholder="e.g. hers, theirs">
<label for="adjective">Adjective</label>
<input type="text" id="adjective" name="adjective" placeholder="e.g. hers, theirs">
</li>
<li>
<label for="prn-r">Reflexive</label>
<input type="text" id="prn-r" name="reflexive" placeholder="e.g. himself, themself">
<label for="reflexive">Reflexive</label>
<input type="text" id="reflexive" name="reflexive" placeholder="e.g. himself, themself">
</li>
<li>
<label for="prn-h-abbr">Honorific abbr.</label>
<input type="text" id="prn-h-abbr" name="honorific-abbr" placeholder="e.g. Ms., Mx.">
<label for="honorific-abbr">Honorific abbr.</label>
<input type="text" id="abbr" name="honorific-abbr" placeholder="e.g. Ms., Mx.">
</li>
<li>
<label for="prn-h">Honorific</label>
<input type="text" id="prn-h" name="honorific" placeholder="e.g. mister, mix">
<label for="honorific">Honorific</label>
<input type="text" id="honorific" name="honorific" placeholder="e.g. mister, mix">
</li>
<li>
<label for="prn-n-adult">Adult noun</label>
<input type="text" id="prn-n-adult" name="adult-noun" placeholder="e.g. woman, person">
<label for="noun-adult">Adult noun</label>
<input type="text" id="adult" name="adult-noun" placeholder="e.g. woman, person">
</li>
<li>
<label for="prn-n-child">Child noun</label>
<input type="text" id="prn-n-child" name="child-noun" placeholder="e.g. boy, kid">
<label for="noun-child">Child noun</label>
<input type="text" id="child" name="child-noun" placeholder="e.g. boy, kid">
</li>
<li>
<label for="prn-plural">Conjugates</label>
<select id="prn-plural" name="conjugates">
<label for="plurality">Conjugates</label>
<select id="plurality" name="conjugates">
<option value="singular">singular</option>
<option value="plural">plural</option>
</select>

View File

@ -18,52 +18,52 @@ function load(options) {
if (options.name === undefined) {
options.name = "";
options.preset = "";
options.other = {};
options.pov = "";
options.also = {};
}
document.querySelector("#name").value = options.name;
document.querySelector("#preset").value = options.preset;
document.querySelector("#pov").value = options.pov;
loadOther(options);
document.querySelector("#pov").value = options.pov;
loadAlso(options);
showOther();
}
/* Helper for load, sets contents of other */
/* Helper for load, sets contents of other in HTML */
function loadOther(options) {
if (options.other === undefined) {
if (Object.keys(options.other).length === 0) {
return;
}
document.querySelector("#other").querySelectorAll("input, select").forEach((pronoun) => {
pronoun.value = options.other[pronoun.id];
});
showOther();
}
/* Helper for load, sets contents of also */
/* Helper for load, sets contents of also in HTML */
function loadAlso(options) {
const also = document.querySelector("#also");
also.innerHTML = "";
if (options.also === undefined) {
const li = createLi(0);
setFinal(li, true);
also.append(li);
if (Object.keys(options.also).length === 0) {
addFinal(also, 0);
return;
}
let li;
let i = 0;
Object.entries(options.also).forEach(([id, value]) => {
Object.entries(options.also).forEach(([key, value]) => {
li = createLi(i);
li.querySelector("#lhs-" + i).value = id;
li.querySelector("#lhs-" + i).value = key;
li.querySelector("#rhs-" + i).value = value;
also.append(li);
i++;
});
setFinal(li, true);
addFinal(also, i);
}
/* Saves options */
@ -75,6 +75,7 @@ function save() {
"pov": document.querySelector("#pov").value,
"also": saveAlso()
});
browser.tabs.reload();
}
/* Helper for save, gets contents of other */
@ -92,6 +93,7 @@ function saveAlso() {
const lhs = document.querySelectorAll(".lhs");
const rhs = document.querySelectorAll(".rhs");
for (let i = 0; i < lhs.length; i++) {
if (lhs[i].value == "") { continue; }
also[lhs[i].value] = rhs[i].value;
}
return also;
@ -164,6 +166,14 @@ function removeLi() {
});
}
/* Adds a final, empty field to the list of also replacements */
function addFinal(also, index) {
const li = createLi(index);
setFinal(li, true);
also.append(li);
return;
}
/* Shows the button to clear the field if isFinal is true */
function setFinal(li, isFinal) {
if (isFinal) {