// manifest.json ------------------------------------------------------------------------------------------
{
"manifest_version": 2,
"name": "peephole",
"version": "1.0",
"description": "peephole",
"permissions": [],
"browser_action": {
"default_title": "peephole"
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["main.js"]
}
]
}
// main.js ------------------------------------------------------------------------------------------------
(() => {
/**
* Check and set a global guard variable.
* If this content script is injected into the same page again,
* it will do nothing next time.
*/
console.log(browser);
if (window.hasRun) {
return;
}
window.hasRun = true;
var matchText = function(node, regex, callback, excludeElements) {
excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas']);
var child = node.firstChild;
while (child) {
switch (child.nodeType) {
case 1:
if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1)
break;
matchText(child, regex, callback, excludeElements);
break;
case 3:
var bk = 0;
child.data.replace(regex, function(all) {
var args = [].slice.call(arguments),
offset = args[args.length - 2],
newTextNode = child.splitText(offset+bk), tag;
bk -= child.data.length + all.length;
newTextNode.data = newTextNode.data.substr(all.length);
tag = callback.apply(window, [child].concat(args));
child.parentNode.insertBefore(tag, newTextNode);
child = newTextNode;
});
regex.lastIndex = 0;
break;
}
child = child.nextSibling;
}
return node;
};
// Function to recursively modify all text nodes in a node and its children
function modifyAllTextNodes(node) {
matchText(node, /o|0/gi, function(node, match, offset) {
var button = document.createElement("span");
const href = node.parentNode.attributes["href"]?.value;
// button.innerText = match;
if (node.parentNode.tagName === "A" && href) {
button.className = "fabulation-ornament";
const iframe = document.createElement("iframe");
iframe.className = "fabulation-peephole";
iframe.width = "500";
iframe.height = "500";
iframe.src = href;
button.appendChild(iframe);
} else {
button.innerText = match;
}
return button;
});
}
modifyAllTextNodes(document.body);
const style = document.createElement("style");
style.innerText = `
.fabulation-ornament {
position: relative;
width: 20px; height: 20px;
border: 2px solid black; border-radius: 50px;
display: inline-block; vertical-align: middle;
}
.fabulation-peephole {
position: absolute;
transform: scale(0.04);
transform-origin: top left;
border-radius: 9999px;
top: 0;
left: 0;
}
`;
document.body.appendChild(style);
})();