Run Content Script From Toolbar - javascript

I want to have a Chrome Extension that will replace text on a page. I've got all the code working on the Javascript side of things, and it runs perfectly when a page loads, the problem is I only want it to replace the text on the page when you click a button on the toolbar.
I setup a button on the toolbar but the replacement Javascript still just runs when the page loads, rather than when you click the button. Additionally at the moment when you click the toolbar button, despite it not doing anything, it still shows a flash of a popup window. All I want it to do is run the text replacement code when you click the toolbar button, without showing a popup.html box.
The code currently is as follows,
Manifest.json
{
"name": "Browser Action",
"version": "0.0.1",
"manifest_version": 2,
"description": "Show how options page works",
// Needed to retrieve options from content script
"background": "background.html",
// This is how you load Browser Action. Nearly equal to Page one.
"browser_action": {
"default_icon": "icon.png",
"popup": "popup.html"
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js" : ["popup.js"]
}
]
}
popup.js
function htmlreplace(a, b, element) {
if (!element) element = document.body;
var nodes = element.childNodes;
for (var n=0; n<nodes.length; n++) {
if (nodes[n].nodeType == Node.TEXT_NODE) {
var r = new RegExp(a, 'gi');
nodes[n].textContent = nodes[n].textContent.replace(r, b);
} else {
htmlreplace(a, b, nodes[n]);
}
}
}
htmlreplace('a', 'IT WORKS!!!');
popup.html - Blank
background.html
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {file: "popup.js"});
});

There are a few changes you must make (most of them mentioned by rsanchez - but not all) and a couple more changes that could/should be made.
So, instead of listing things that could/should/must be changed, I will demonstrate a sample extension that does what you want.
First things first - More info on a few key concepts, related to your question/problem:
Manifest File Format
Permissions
Background pages, Event pages
Content scripts
Browser actions
Extension directory structure:
extension-root-directory/
|_____manifest.json
|_____background.js
|_____content.js
manifest.json:
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"offline_enabled": true,
"background": {
"persistent": false,
"scripts": ["./bg/background.js"]
},
"browser_action": {
"default_title": "Test Extension"
//"default_icon": {
// "19": "img/icon19.png",
// "38": "img/icon38.png"
//},
},
"permissions": [
"activeTab"
]
}
background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, { file: "content.js" });
});
content.js:
function htmlReplace(a, b, element) {
if (!element) {
element = document.body;
}
var r = new RegExp(a, "gi");
var nodes = element.childNodes;
for (var n = 0; n < nodes.length; n++) {
if (nodes[n].nodeType == Node.TEXT_NODE) {
nodes[n].textContent = nodes[n].textContent.replace(r, b);
} else {
htmlReplace(a, b, nodes[n]);
}
}
}
htmlReplace("a", "IT WORKS !!!");

You just need to do the following changes to your manifest:
Remove the content_scripts section.
Remove the browser_action.popup entry.
Add a section: "permissions": ["activeTab"]
Change your background section to read: "background": { "scripts": ["background.js"] } and rename your file background.html to background.js

Related

how do i pass selected text in chrome extension from background script to content script?

I am building a extension which is essentially a plagiarism checker. So, you copy the text and then right click after that you have are directed to our website. Now, what I want to do is that I want to send the selected text from my copied website to my website input page and then I want to click the submit button.
To do that I need to execute these two lines.
document.getElementById("mycontent").value = "selected text";
document.getElementById("checkButton").click();
But the selected text remains in just background.js and never shows up in content script that's why my extension is not working. So, i want to know how can I fix this or is there any other way I can input my text and click the button.
Background.js
var contextsList = ["selection"];
for(i = 0;i<contextsList.length; i++){
var context = contextsList[i];
var titleX = " Check Plagiarism of Selected Text";
chrome.contextMenus.create({title: titleX, contexts:[context], onclick: clickHandler, id: context });
}
function clickHandler(data, tab) {
switch(data.menuItemId.id){
case 'selection' :
ex = encodeURIComponent(data.selectionText);
var config = {content: ex};
chrome.tabs.executeScript(tab.id, {
code: 'var config = ' + JSON.stringify(config)
}, function() {
chrome.tabs.executeScript(tab.id, {file: 'contentScript.js'});
});
// background script
chrome.runtime.onMessage.addListener((request,sender,sendMessage)=>{
if(request.type==="Getcontent"){
const content=// set your content
sendMessage({msg:"cont",content:content})
}
})
chrome.tabs.create({url: "https://greatseotools.net/plagiarism-checker"});
break;
}
}
ContentScript.js
//Content script
chrome.runtime.onMessage.addListener((request,sender,sendMessage)=>{
if(request==='content'){
console.log("content",request.content)
}
})
//wrap this in an event
chrome.runtime.sendMessage({
type:'Getcontent'
})
manifest.json
{
"background": {
"scripts": [ "background.js" ]
},
"browser_action": {
"default_icon": "icons/19.png",
"default_popup": "popup.html"
},
"content_scripts": [ {
"all_frames": true,
"js": ["contentScript.js" ],
"matches": [ "*://*.greatseotools.net/*" ],
"run_at": "document_end"
} ],
"description": "Check Plagiarism by just selecting text..",
"homepage_url": "https://www.prepostseo.com/plagiarism-checker",
"icons": {
"128": "icons/128.png",
"16": "icons/16.png",
"48": "icons/48.png"
},
"manifest_version": 2,
"name": "Plagiarism Checker for Chrome",
"permissions": [ "activeTab","*://*/*", "https://ajax.googleapis.com/", "contextMenus" ],
"update_url": "https://clients2.google.com/service/update2/crx",
"version": "1.0"
}
Website on which I have to input text and click the button.
https://greatseotools.net/plagiarism-checker
In this line chrome.tabs.executeScript({file: 'contentScript.js'}) you didn't pass your selectionText to the content script you can acheive that in many ways here are two of my suggestions :
background script
1. Using the chrome.tabs.executeScript api
ex = encodeURIComponent(data.selectionText);
var config = {content: ex};
chrome.tabs.executeScript(tab.id, {
code: 'var config = ' + JSON.stringify(config)
}, function() {
chrome.tabs.executeScript(tab.id, {file: 'content.js'});
});
content script
and in your content script you should be able to retrieve ex :
alert('mycontent:' + config);
2. Using the chrome messages api between backgound and content script
background script
// background script
chrome.runtime.onMessage.addListener((request,sender,sendMessage)=>{
if(request.type==="Getcontent"){
const content=// set your content
sendMessage({msg:"cont",content:content})
}
})
Content script
//Content script
chrome.runtime.onMessage.addListener((request,sender,sendMessage)=>{
if(request==='content'){
console.log("content",request.content)
}
})
//wrap this in an event
chrome.runtime.sendMessage({
type:'Getcontent'
})
3.use chrome storage
background script
chrome.storage.sync.set({'content':ex})
content script
chrome.storage.sync.get(['content'], function(res) {
console.log('Value currently is ' + res.content);
});
manifest
"permissions": ["storage"]

Chrome extension - injecting script and running it on inactive tab

I have Chrome extension that injects a script into a page on load. If it is a certain page, it opens a set of links on that page in new tabs and when those tabs are loaded the injected script submits a form on the tab. The issue is that the injection is not happening on tabs that are not current. It works only on the current tab.
A simplified version of my code:
manifest.json
{
"name": "name",
"version": "0.0.1",
"manifest_version": 2,
"description": "Doing stuff",
"background": {
"scripts": [
"background.js"
],
"persistent": true
},
"browser_action": {
"default_title": "Bot"
},
"permissions": [
"https://*.url.com/*",
"*://*/*",
"tabs"
]
}
background.js :
chrome.tabs.onUpdated.addListener( function (tabId, changeInfo, tab) {
if(changeInfo.status == 'complete') {
try {
chrome.tabs.executeScript(tab.ib, {
file: 'inject.js'
});
} catch(err) {
console.log(" extension cannot run on the chrome:// page ")
}
}
})
inject.js :
(function() {
function page1() {
links = document.querySelectorAll("a.link_class");
for(var link in links) {
link.setAttribute("target", "_blank");
link.click();
}
}
function page2() {
// this does not run in tabs that are inactive
// in order to make it run, i have to click in the inactive tab and reload it manually
document.querySelector("input[name='field_to_update']").text = "setting the field value";
button = document.querySelector("input[name='button']");
button.click();
}
if(document.querySelector("div.page1") != null) {
page1();
} else {
page2();
}
})();

Open array of links

I am working on simple Chrome Extension with the aim of opening every link on a page with the class of entry. Currently, I have this....
manifest.json:
{
"manifest_version": 2,
"name": "Hello World",
"description": "A simple Chrome Extension",
"version": "1.0",
"background": {
"scripts": ["openlinks.js"],
"persistent": true
},
"permissions": [
"tabs",
"http://*/",
"https://*/"
],
"browser_action": {
"default_icon": "logo.png"
}
}
openlinks.js:
chrome.browserAction.onClicked.addListener(function(tab) {
var linkArray = ['https://www.google.com', 'http://www.bbc.co.uk']; // your links
for (var i = 0; i < linkArray.length; i++) {
chrome.tabs.create({
url: linkArray[i]
});
}
});
Now I am trying to replace the array of sample links with an array of links from the current tab. Is it just a case of using standard JavaScript or jQuery to achieve this?
Take a look at Chrome Extensions Overview # Architecture, because you'll need both an Event Page and a Content Script to make this happen.
Here's an outline of how I would go about solving this:
Manifest structure (Event Page + activeTab permission).
"background": { "scripts": ["bg.js"], "persistent": false },
"permissions": ["activeTab"],
"browser_action": {},
When the browser action is clicked, the browser grants permission to access the current tab, which we use to inject the script. See Content Scripts # Programmatic Injection.
// bg.js
chrome.browserAction.onClicked.addListener(tab =>
chrome.tabs.executeScript({file: 'content.js'});
});
The content script has permission to access the DOM and use message passing, but is restricted from most of the extension APIs (in particular chrome.tabs).
// content.js
message = {}
message.links = [...document.querySelectorAll(
'div.question-summary a.question-hyperlink')].map(e=>e.href);
chrome.runtime.sendMessage(message);
The background page listens for the message.
// bg.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
request.links.forEach(link => chrome.tabs.create({url: link});
});

Chrome Extension to trigger click event on icon press

I'm trying to make an extension for Chrome, so that when the icon is clicked, it triggers a click event on a div in the relevant webpages. I can't figure it out. Can anyone see or tell me what I'm doing wrong? Is this even possible?
Manifest.json
{
"name": "Name",
"version": "1.0",
"manifest_version": 2,
"icons": {
"128": "icon128.png",
"48": "icon.png"
},
"browser_action": {
"name": "Name"
},
"background":{
"scripts":["background.js"]
},
"permissions":["https://inbox.google.com/*"] //Put All your URL here
}
background
chrome.browserAction.onClicked.addListener(function (tab) {
if (tab.url.indexOf("https://inbox.google.com/*") != -1) {
chrome.tabs.executeScript(tab.id, {
"file": "clicky.js"
}, function () {
console.log("Script Executed .. ");
});
}
});
js
$('.b2')[0].click()
You're not including jquery in your manifest.json and you don't have access to the page's jQuery instance (read this), so you can't use jQuery on your content scripts.
Assuming there's an element with the 'b2' class present, change the code in clicky.js to this and it should work:
var btn = document.querySelector('.b2');
if(btn){
btn.click();
}
EDIT
Also, in your background.js, remove the wildcard when you call indexOf:
if (tab.url.indexOf("https://inbox.google.com/") != -1) {

Chrome extension: Execute only on current domain name once browser action is clicked

Here is my scenario: By clicking the browser icon, I create a sidebar (html and css) next to the whole page, thus creating two columns (one is my sidebar, the other one is the actual page).
What I to achieve is having the sidebar stay when I reload the page or navigate to another page WITHIN the same domain. What I have right now is just the creation of the sidebar, but I have to click the browser action every time I navigate or reload the web page.
Manifest:
{
"name": "apdrop",
"version": "0.1",
"manifest_version": 2,
"description": "first prototype for apdrop extension",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_icon": "icons/icon19.png",
"default_title": "apdrop"
},
"permissions": [
"background",
"tabs",
"http://*/*/",
"https://*/*/"
]
}
Background.js
function injectedScript(tab, method){
chrome.tabs.insertCSS(tab.id, {file:"style.css"});
//chrome.tabs.insertCSS(tab.id, {file:"bootstrap.css"});
chrome.tabs.executeScript(tab.id, { file: 'jquery-2.1.1.min.js'});
//chrome.tabs.executeScript(tab.id, { file: 'bootstrap.min.js'});
chrome.tabs.executeScript(tab.id, { file: 'inject.js'});
}
function click(tab){
console.log("browser action clicked");
injectedScript(tab, 'click');
//alert("action button was clicked");
}
chrome.browserAction.onClicked.addListener(click);
Inject.js
var ev = $("body > *");
if (!document.getElementById('contentxf343487d32'))
{
ev.wrapAll("<div id='insidecontent65675f526567'>");
$("#insidecontent65675f526567").wrapAll("<div id='contentxf343487d32'>");
$("<div id='sidebar343gf87897fh'><div id='insidesidebar87678bbbb'><p>this is my name</p></div></div>").insertBefore("#contentxf343487d32");
}
else
{
$("#sidebar343gf87897fh").remove();
$("#insidecontent65675f526567").unwrap();
$("#insidecontent65675f526567 > div").unwrap();
}
Hope this helps clarify a bit more.
The simplest strategy would be to save state in domain's sessionStorage and have a "detector" script that re-injects your UI.
Add setting the state in your content script:
// inject.js
if (!document.getElementById('contentxf343487d32'))
{
// ...
sessionStorage["contentxf343487d32"] = true;
}
else
{
// ...
sessionStorage["contentxf343487d32"] = false;
}
Add a "detector" script:
// detect.js
if(sessionStorage["contentxf343487d32"])
{
chrome.runtime.sendMessage({injectSidebar: true});
}
Always inject the script on page load, via the manifest (and change to a better permission):
"content_scripts" : [
{
"matches": ["<all_urls>"],
"js": ["detect.js"]
}
],
"permissions": [
"background",
"tabs",
"<all_urls>"
]
In the background, inject the script upon message:
// background.js
chrome.runtime.onMessage.addListener( function (message, sender, sendResponse){
if(message.injectSidebar)
{
click(sender.tab);
}
});
If you need more persistence than sessionStorage provides, use localStorage. If you need a different logic, you can still use this skeleton of a detector signalling the background.

Categories