move content_script injection to background.js

This commit is contained in:
ngxson
2020-08-26 11:19:30 +02:00
parent 4c22a40002
commit 57773adeab
4 changed files with 238 additions and 232 deletions
+12
View File
@@ -0,0 +1,12 @@
import browser from "webextension-polyfill";
browser.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
browser.tabs.executeScript(tabId, {
file: 'content_script/input_tools.js',
runAt: 'document_idle',
});
browser.tabs.insertCSS(tabId, {
file: 'content_script/input_tools.css',
});
});
+4 -3
View File
@@ -1,10 +1,11 @@
import browser from "webextension-polyfill";
import APIService from "../popup/APIService";
import SLStorage from "../popup/SLStorage";
import "./content-script";
import { handleNewRandomAlias } from "./create-alias";
import { handleOnClickContextMenu } from "./context-menu";
global.browser = require("webextension-polyfill");
global.isBackgroundJS = true;
/**
@@ -24,7 +25,7 @@ async function handleGetAppSettings() {
/**
* Register onMessage listener
*/
global.browser.runtime.onMessage.addListener(async function (request, sender) {
browser.runtime.onMessage.addListener(async function (request, sender) {
if (request.tag === "NEW_RANDOM_ALIAS") {
return await handleNewRandomAlias(sender.tab);
} else if (request.tag === "GET_APP_SETTINGS") {
@@ -35,7 +36,7 @@ global.browser.runtime.onMessage.addListener(async function (request, sender) {
/**
* Register context menu
*/
global.browser.contextMenus.create({
browser.contextMenus.create({
title: "Create random email alias (copied)",
contexts: ["all"],
onclick: handleOnClickContextMenu,
+218 -216
View File
@@ -1,235 +1,237 @@
let SLSettings = {};
if (!typeof InputTools !== 'undefined') {
let SLSettings = {};
const InputTools = {
isLoading: false,
const InputTools = {
isLoading: false,
// store tracked input elements
trackedElements: [],
// store tracked input elements
trackedElements: [],
init(target) {
InputTools.queryEmailInputAndApply(target, (element) => {
if (!InputTools.isValidEmailInput(element)) {
init(target) {
InputTools.queryEmailInputAndApply(target, (element) => {
if (!InputTools.isValidEmailInput(element)) {
return;
}
// ignore if this elements has already been tracked
const i = InputTools.trackedElements.indexOf(element);
if (i === -1) {
InputTools.trackedElements.push(element);
InputTools.addSLButtonToInput(element);
}
});
},
destroy(target) {
InputTools.queryEmailInputAndApply(target, (element) => {
// remove element from tracking list
const i = InputTools.trackedElements.indexOf(element);
if (i !== -1) {
InputTools.trackedElements.splice(i, 1);
}
});
},
queryEmailInputAndApply(target, actionFunction) {
if (!target.querySelectorAll) return;
const elements = target.querySelectorAll(
"input[type='email'],input[name*='email'],input[id*='email']"
);
for (const element of elements) {
actionFunction(element);
}
},
isValidEmailInput(element) {
const style = getComputedStyle(element);
return (
// check if element is visible
style.visibility !== "hidden" &&
style.display !== "none" &&
style.opacity !== "0" &&
style.pointerEvents === "auto" &&
// check if element is not disabled
!element.disabled &&
// for example, we must filter out a checkbox with name*=email
// check if element is text or email input
(element.type === "text" || element.type === "email")
);
},
addSLButtonToInput(inputElem) {
// create wrapper for SL button
const btnWrapper = InputTools.newDiv("sl-button-wrapper");
const inputSumHeight = inputElem.getBoundingClientRect().height + "px";
btnWrapper.style.height = inputSumHeight;
btnWrapper.style.width = inputSumHeight;
document.body.appendChild(btnWrapper);
// create the SL button
const slButton = InputTools.newDiv("sl-button");
slButton.addEventListener("click", function () {
InputTools.handleOnClickSLButton(inputElem, slButton);
});
slButton.style.height = inputSumHeight;
slButton.style.width = inputSumHeight;
btnWrapper.appendChild(slButton);
InputTools.placeBtnToTheRightOfElement(inputElem, btnWrapper);
},
newDiv(...className) {
const div = document.createElement("div");
div.classList.add(...className);
return div;
},
placeBtnToTheRightOfElement(inputElem, btnWrapper) {
let intervalId = 0;
function updatePosition() {
// check is element is removed from trackedElements
const i = InputTools.trackedElements.indexOf(inputElem);
if (i === -1) {
btnWrapper.parentNode.removeChild(btnWrapper);
clearInterval(intervalId);
}
// get dimension & position of input
const inputCoords = inputElem.getBoundingClientRect();
const inputStyle = getComputedStyle(inputElem);
const elemWidth = InputTools.dimensionToInt(btnWrapper.style.width);
const pageXOffset = window.pageXOffset;
const pageYOffset = window.pageYOffset;
const buttonXOffset =
SLSettings.SLButtonPosition === "right-inside"
? -elemWidth * 1.02
: elemWidth * 0.02;
// calculate elem position
const left =
InputTools.sumPixel([
inputCoords.left,
pageXOffset,
inputElem.offsetWidth,
buttonXOffset,
-inputStyle.paddingRight,
]) + "px";
const top = InputTools.sumPixel([inputCoords.top, pageYOffset]) + "px";
if (btnWrapper.style.left !== left) {
btnWrapper.style.left = left;
}
if (btnWrapper.style.top !== top) {
btnWrapper.style.top = top;
}
}
intervalId = setInterval(updatePosition, 200);
updatePosition();
},
async handleOnClickSLButton(inputElem, slButton) {
if (InputTools.isLoading) {
return;
}
InputTools.isLoading = true;
slButton.classList.add("loading");
// ignore if this elements has already been tracked
const i = InputTools.trackedElements.indexOf(element);
if (i === -1) {
InputTools.trackedElements.push(element);
InputTools.addSLButtonToInput(element);
}
});
},
destroy(target) {
InputTools.queryEmailInputAndApply(target, (element) => {
// remove element from tracking list
const i = InputTools.trackedElements.indexOf(element);
if (i !== -1) {
InputTools.trackedElements.splice(i, 1);
}
});
},
queryEmailInputAndApply(target, actionFunction) {
if (!target.querySelectorAll) return;
const elements = target.querySelectorAll(
"input[type='email'],input[name*='email'],input[id*='email']"
);
for (const element of elements) {
actionFunction(element);
}
},
isValidEmailInput(element) {
const style = getComputedStyle(element);
return (
// check if element is visible
style.visibility !== "hidden" &&
style.display !== "none" &&
style.opacity !== "0" &&
style.pointerEvents === "auto" &&
// check if element is not disabled
!element.disabled &&
// for example, we must filter out a checkbox with name*=email
// check if element is text or email input
(element.type === "text" || element.type === "email")
);
},
addSLButtonToInput(inputElem) {
// create wrapper for SL button
const btnWrapper = InputTools.newDiv("sl-button-wrapper");
const inputSumHeight = inputElem.getBoundingClientRect().height + "px";
btnWrapper.style.height = inputSumHeight;
btnWrapper.style.width = inputSumHeight;
document.body.appendChild(btnWrapper);
// create the SL button
const slButton = InputTools.newDiv("sl-button");
slButton.addEventListener("click", function () {
InputTools.handleOnClickSLButton(inputElem, slButton);
});
slButton.style.height = inputSumHeight;
slButton.style.width = inputSumHeight;
btnWrapper.appendChild(slButton);
InputTools.placeBtnToTheRightOfElement(inputElem, btnWrapper);
},
newDiv(...className) {
const div = document.createElement("div");
div.classList.add(...className);
return div;
},
placeBtnToTheRightOfElement(inputElem, btnWrapper) {
let intervalId = 0;
function updatePosition() {
// check is element is removed from trackedElements
const i = InputTools.trackedElements.indexOf(inputElem);
if (i === -1) {
btnWrapper.parentNode.removeChild(btnWrapper);
clearInterval(intervalId);
let res = await sendMessageToBackground("NEW_RANDOM_ALIAS");
if (res.error) {
alert("SimpleLogin Error: " + res.error);
res = { alias: "" };
}
// get dimension & position of input
const inputCoords = inputElem.getBoundingClientRect();
const inputStyle = getComputedStyle(inputElem);
const elemWidth = InputTools.dimensionToInt(btnWrapper.style.width);
const pageXOffset = window.pageXOffset;
const pageYOffset = window.pageYOffset;
const buttonXOffset =
SLSettings.SLButtonPosition === "right-inside"
? -elemWidth * 1.02
: elemWidth * 0.02;
InputTools.isLoading = false;
slButton.classList.remove("loading");
// calculate elem position
const left =
InputTools.sumPixel([
inputCoords.left,
pageXOffset,
inputElem.offsetWidth,
buttonXOffset,
-inputStyle.paddingRight,
]) + "px";
inputElem.value = res.alias;
},
const top = InputTools.sumPixel([inputCoords.top, pageYOffset]) + "px";
if (btnWrapper.style.left !== left) {
btnWrapper.style.left = left;
sumPixel(dimensions) {
let sum = 0;
for (const dim of dimensions) {
sum += !isNaN(dim) ? dim : InputTools.dimensionToInt(dim);
}
return sum;
},
if (btnWrapper.style.top !== top) {
btnWrapper.style.top = top;
dimensionToInt(dim) {
try {
const pixel = parseFloat(dim.replace(/[^0-9.]+/g, ""));
return isNaN(pixel) ? 0 : pixel;
} catch (e) {
return 0;
}
}
},
};
intervalId = setInterval(updatePosition, 200);
updatePosition();
},
const MutationObserver =
window.MutationObserver ||
window.WebKitMutationObserver ||
window.MozMutationObserver;
async handleOnClickSLButton(inputElem, slButton) {
if (InputTools.isLoading) {
return;
}
InputTools.isLoading = true;
slButton.classList.add("loading");
let res = await sendMessageToBackground("NEW_RANDOM_ALIAS");
if (res.error) {
alert("SimpleLogin Error: " + res.error);
res = { alias: "" };
}
InputTools.isLoading = false;
slButton.classList.remove("loading");
inputElem.value = res.alias;
},
sumPixel(dimensions) {
let sum = 0;
for (const dim of dimensions) {
sum += !isNaN(dim) ? dim : InputTools.dimensionToInt(dim);
}
return sum;
},
dimensionToInt(dim) {
try {
const pixel = parseFloat(dim.replace(/[^0-9.]+/g, ""));
return isNaN(pixel) ? 0 : pixel;
} catch (e) {
return 0;
}
},
};
const MutationObserver =
window.MutationObserver ||
window.WebKitMutationObserver ||
window.MozMutationObserver;
/**
* Add DOM mutations listener
*/
function addMutationObserver() {
const mutationObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
for (const addedNode of mutation.addedNodes) {
// add SLButton for newly added nodes
InputTools.init(addedNode);
}
for (const removedNode of mutation.removedNodes) {
// destroy SLButton for removed nodes
InputTools.destroy(removedNode);
}
});
});
const target = document.body;
if (!target) return;
mutationObserver.observe(target, {
childList: true,
subtree: true,
});
}
/**
* Send message to background.js and resolve with the response
* @param {string} tag
* @param {object} data
*/
function sendMessageToBackground(tag, data = null) {
const _browser = window.chrome || browser;
return new Promise((resolve) => {
try {
_browser.runtime.sendMessage(
{
tag,
data,
},
function (response) {
resolve(response);
/**
* Add DOM mutations listener
*/
function addMutationObserver() {
const mutationObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
for (const addedNode of mutation.addedNodes) {
// add SLButton for newly added nodes
InputTools.init(addedNode);
}
);
} catch (e) {
// Extension context invalidated.
console.error(e);
}
});
}
async function initModule() {
SLSettings = await sendMessageToBackground("GET_APP_SETTINGS");
if (SLSettings.showSLButton) {
InputTools.init(document);
addMutationObserver();
for (const removedNode of mutation.removedNodes) {
// destroy SLButton for removed nodes
InputTools.destroy(removedNode);
}
});
});
const target = document.body;
if (!target) return;
mutationObserver.observe(target, {
childList: true,
subtree: true,
});
}
}
initModule();
/**
* Send message to background.js and resolve with the response
* @param {string} tag
* @param {object} data
*/
function sendMessageToBackground(tag, data = null) {
const _browser = window.chrome || browser;
return new Promise((resolve) => {
try {
_browser.runtime.sendMessage(
{
tag,
data,
},
function (response) {
resolve(response);
}
);
} catch (e) {
// Extension context invalidated.
console.error(e);
}
});
}
async function initModule() {
SLSettings = await sendMessageToBackground("GET_APP_SETTINGS");
if (SLSettings.showSLButton) {
InputTools.init(document);
addMutationObserver();
}
}
initModule();
}
+4 -13
View File
@@ -8,11 +8,12 @@
"128": "icons/icon_128.png"
},
"permissions": [
"activeTab",
"storage",
"cookies",
"contextMenus",
"https://*.simplelogin.io/*"
"tabs",
"http://*/*",
"https://*/*"
],
"browser_action": {
"default_title": "simplelogin-extension",
@@ -27,15 +28,5 @@
"scripts": [
"background.js"
]
},
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["content_script/input_tools.js"],
"css": ["content_script/input_tools.css"],
"all_frames": true
}
]
}
}