I am trying to get into chrome extension development and want to make an extension which highlights a specific word on every page from a background script.
If I give my extension the activeTab permission, it is listed as "Access requested" and I need to invoke it by opening the popup, then after reloading the page it will highlight the word.
The documentation says "essentially, activeTab grants the tabs permission temporarily", so I switched to giving the tabs permission because I don't want to open the popup every time I visit a new website. However, now the extension is listed as "no access needed" and the highlighting does not work regardless of whether I invoke the popup or not.
Here is my service-worker background.js:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab){
if (changeInfo.status == 'complete') {
chrome.scripting.executeScript({
target: { tabId: tabId },
function: highlightwords,
});
}
})
function highlightwords(){
var list = document.getElementsByTagName("p")
var search_words = ["the", "it", "you"]
var words = []
for(var i = 0; i < list.length; i++){
var words = list[i].textContent.split(' ')
for (var j = 0; j < words.length; j++) {
if (search_words.includes(words[j])) {
console.log(words[j]);
var elem = document.createElement("span")
elem.textContent = words[j]
elem.style.color = "red"
words[j]=elem.outerHTML
}
}
list[i].innerHTML = words.join(' ')
}
}
manifest.json:
{
"name": "Getting Started Example",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "/images/get_started16.png",
"32": "/images/get_started32.png",
"48": "/images/get_started48.png",
"128": "/images/get_started128.png"
}
},
"icons": {
"16": "/images/get_started16.png",
"32": "/images/get_started32.png",
"48": "/images/get_started48.png",
"128": "/images/get_started128.png"
},
"options_page": "options.html",
"permissions": ["storage", "scripting", "tabs"]
}
I'd be very grateful for any hint on what's going wrong here or which alternatives there are (apart from using manifest v2, which probably doesn't have much of a future, at least in Chrome).
The only purpose of the tabs permission is to show url in changeInfo and tab objects e.g. in chrome.tabs.onUpdated event. You don't use it and you don't need it for this task.
Remove tabs and scripting permissions, remove the background worker.
Declare a content script in manifest.json
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["content.js"]
}]
content.js will run in all http/https sites (this is what the first * in *://*/* means) and highlight the text.
P.S. Note that your current code destroys event listeners added by the page to any nested elements inside p because you assign to innerHTML. This is bad. A much better approach is to replace the matching parts of text inline by using DOM methods createTreeWalker and splitText, example, or just use mark.js.
Related
im working to create a very simple chrome extension just to remove an annoying tag from a site here is my codes
my manifest.json file include those lines :
{
"manifest_version": 2,
"name": "RemoveMysatgoHelp",
"description": "Remove Mysatgo Help tag",
"version": "1.0",
"icons": {
"16": "imgs/16.png",
"32": "imgs/32.png",
"64": "imgs/64.png",
"128": "imgs/128.png"
},
"content_scripts": [
{
"matches": [
"*://*.mysatgo.com/*"
],
"js": [
"content.js"
],
"run_at": "document_idle"
}
]
}
my content.js file include this single line:
var elements0 = document.getElementById('launcher');
elements0.style.display='none';
i need to remove these "Help window"at the bottom of the page it disturbing the main player control, here is my illustration https://prnt.sc/qaeaf5
i believe it is a dynamic tag inside an anonymous div tag ,the only id name that we have is within the iframe tag and the idname is "launcher"
my question
the problem again the elements0 return null ,because it seems the page not fully loaded with all the sources
any solution ?
Thanks
Can anyone tell me why I cannot get a string for the selected text on any given page using windows.getSelection().toString()?
The script is running in the background, even though I've named it as popup.js.
Everything I can find shows a variation of this, but in my code it always returns null.
I am calling window.getSelection() on a shortcut combination being pressed. Text is definitely selected, but the result is always null.
manifest.json
{
"name": "CM_TextDiff",
"version": "1.0",
"manifest_version": 2,
"description": "Highlight changes in two lines of text. Useful to language teachers to highlight corrections.",
"icons": {
"128": "compare128.png"
},
"background": {
"scripts": [
"popup.js"
]
},
"browser_action": {
"default_title": "highlight your corrections",
"default_popup": "popup.html"
},
"permissions": [
"tabs",
"activeTab",
"http://*/*",
"https://*/*",
"clipboardRead",
"clipboardWrite",
"contextMenus"
],
popup.js
chrome.commands.onCommand.addListener(function(command) {
console.log('Command:', command);
getSelectedText();
});
function getSelectedText(){
alert ("The text content of the selection:\n" + window.getSelection().toString ());
}
I would expect this to display a popup with the text that is selected on the page. However, the result is always a nullstring.
For anyone else who gets stuck on this:
Be sure to have "active tab" in permissions.
To pull the selected text from the active tab:
function getSelectedText(){
chrome.tabs.executeScript({code: 'getSelection().toString()'},
res => callback(res) //res => { alert(res[0]) });
);
}
var blah;
function callback(results){
console.log(results);
blah = results[0];
}
"blah" will contain the selected text in the calling process where you can work with it.
Thanks to wOxxOm for pointing me in the right direction and giving me a push.
I am developing a simple Chrome extension, that does something when a password-input box is focused. I'm using following content script to achieve the same (code is simplified for asking this question). The code does not work on pages like https://accounts.google.com/ but it works perfectly for pages like https://www.linkedin.com/. Is it because of some Javascript/JQuery conflicts? Or some other reason? Please help. I tried using noConflict api, but it didn't help.
Content script:
var inputs = document.getElementsByTagName('input');
function foo() {
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].type.toLowerCase() == 'password')
inputs[i].addEventListener("focus", bar);
}
}
function bar() {
alert(1);
}
foo();
Above script finds input elements of type passwords, but does not add event listener.
Manifest:
{
"manifest_version": 2,
"name": "MyExtension",
"version": "1.0",
"options_page": "options.html",
"browser_action": {
"default_icon": "img/abcd.png",
"default_title": "MyExtension",
"default_popup": "popup.html"
},"icons": { "16": "img/abcd16.png",
"48": "img/abcd48.png",
"128": "img/abcd128.png" },"description":"abcd abcd",
"permissions": [
"storage","tabs"
],
"content_scripts": [
{
"matches": ["<all_urls>"
],
"js": ["js/content.js","js/jquery.1.8.3.min.js"],
"css": ["css/style.css"],
"run_at": "document_end",
"all_frames": true
}
],"web_accessible_resources": [
"img/*.png",
"css/*.css"
]
}
Have you considered that the input field you seek doesn't exist by the time that the script executes? https://accounts.google.com/ is a dynamic form, the password field is created long after the page is loaded (document_end) and therefore long after you collect inputs.
In addition to binding the handler to existing elements, you need to watch for new ones being added. I would suggest using mutation-summary library with a query {element: "input[type=password]"}, but if you don't want to involve a library the basic building block to look at is MutationObserver.
I wrote a short content script, which stops a particular site from creating new windows for link clicks.
This is my first Chrome extension, and I've scored this website and the internet for a reason why it won't run, but I can't find any. I'm probably making a fundamental amateur mistake somewhere.
Manifest.json:
{
"manifest_version": 2,
"name": "DHS Links",
"description": "Stops the school's site from constantly opening new windows.",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png"
},
"content_scripts":[
{
"matches": ["*://www.darienps.org/dhs/*"],
"js": ["jquery.js", "makeNormalLinks.js"],
"run_at": "document_end"
}
]
}
I tested the Javascript file by itself on a local version of the site, so I'm pretty sure it's fine, but just in case:
makeNormalLinks.js:
$(document).ready(function() {
$("a").each(function(){
$(this).removeAttr("onclick");
});
});
A copy of jQuery is in the same directory and doesn't seem to have any issues.
Here's the onclick code for many links on the website:
onclick="window.open(this.href,'targetWindow','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,')
Thank you for looking this over!
Edit:
I tried two of the injection methods from Rob W's response to another question linked to in the comments by Teepeemm.
Here's the new code for Method 1:
Manifest.json:
{
"manifest_version": 2,
"name": "DHS Links",
"description": "Stops the school's site from constantly opening new windows.",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png"
},
"content_scripts":[
{
"matches": ["*://www.darienps.org/dhs/*"],
"js": ["jquery.js", "scriptLauncher.js"]
}
],
"web_accessible_resources": ["makeNormalLinks.js"]
}
scriptLauncher.js:
var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = chrome.extension.getURL('makeNormalLinks.js');
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
Method 2a:
(Uses old Manifest.js)
makeNormalLinks.js:
var actualCode = ['$(document).ready(function(){',
'$("a").each(function(){',
'$(this).removeAttr("onclick");',
'});',
'});'].join('\n');
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
Unfortunately, neither method seems to work. I'm extremely grateful to those who commented and think we're getting close to an answer.
Solution:
Manifest.json:
{
"manifest_version": 2,
"name": "DHS Links",
"description": "Stops the school's site from constantly opening new windows.",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png"
},
"content_scripts":[
{
"matches": ["*://www.darienps.org/dhs/*"],
"js": ["makeNormalLinks.js"]
}
]
}
makeNormalLinks.js:
document.addEventListener("click", function(e) {
e.stopPropagation();
}, true);
Thanks you, Scott and all who commented!
Using the onclick attribute has many weird side effects. A more up to date approach would be to add a listener to the document that filters unwanted events. Like:
document.addEventListener("click", function(e) {
e.stopPropagation();
}, true);
The true argument is important (see event capture). This will block all click event listeners from firing, but the default click action will still be triggered.
I was having a similiar issue getting the content script to fire in Google Mail. I stumbled upon a page that recommended using the "hashchange" event.
// Event listener
window.addEventListener("hashchange", function () {
alert("hashchanged");
}, false);
I am trying to integrate CodeMirror's syntax highlighting with a textarea using chrome extensions.
Here is my test.js...
var srcArray = ["lib/codemirror.js",
"lib/util/matchbrackets.js",
"lib/util/continuecomment.js",
"mode/htmlmixed/htmlmixed.js",
"mode/xml/xml.js",
"mode/javascript/javascript.js",
"mode/css/css.js",
"mode/clike/clike.js",
"mode/php/php.js"];
function AddScript(value)
{
var s = document.createElement("SCRIPT")
s.src = chrome.extension.getURL(value);
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
}
srcArray.forEach(AddScript);
... and manifest.json:
{
"name":"Test",
"description":"Test description",
"version":"1.0",
"manifest_version": 2,
"browser_action": {
"default_icon": "icon.png"
},
"content_scripts": [
{
"matches": ["file:///*Test*"],
"js": ["test.js"]
}
],
"web_accessible_resources": ["lib/codemirror.js",
"lib/util/matchbrackets.js",
"lib/util/continuecomment.js",
"mode/htmlmixed/htmlmixed.js",
"mode/xml/xml.js",
"mode/javascript/javascript.js",
"mode/css/css.js",![enter image description here][1]
"mode/clike/clike.js",
"mode/php/php.js"]
}
And here is the issue I am facing:
<script>...</script> are being added to the page, however when the last one is added they all disappear.
I suspect this has someting to do with security mechanisms introduced in 2nd version of the manifest. I cannot however figure out what is missing.
Your advice would be greatly appreciated, thanks.