I'm a newbie at Chrome extensions, and of course I stuck on every step, but this is specially hard. Maybe it is a silly mistake, but here is what I am trying to do:
Send a simple message from the content script to the background page and handle it as a variable. So I have this in my content script:
$(document).ready(function() {
var d = document.domain;
chrome.extension.sendMessage({dom: d});
});
And in my background script this:
chrome.extension.onMessage.addListener(function(request) {
alert(request.dom);
});
So, the alert works fine. But it "goes" to the page I am browing and not the HTML extension, this means, instead of poping up when clicking on my extension button, it will appear as it was coded into the content script when the page loads.
Please, any help would be appreciated.
My Demo extension is as follows
Files & Roles
a) manifest.json (Documentation)
b) myscript.js (Content Script See Documentation)
c) background.js (Background HTML File See Documentation)
d) popup.html (Browser Action Popup See Documentation)
e) popup.js (Receptor of Modified value from Background Page)
manifest.json
Registered all files to manifest(Viz background,popup,content scripts) with permissions
{
"name":"Communication Demo",
"description":"This demonstrates modes of communication",
"manifest_version":2,
"version":"1",
"permissions":["<all_urls>"],
"background":{
"scripts":["background.js"]
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["myscript.js"]
}
],
"browser_action":{
"default_icon":"screen.png",
"default_popup":"popup.html"
}
}
myscript.js
Used sendMessage() API for communicating with background page
var d = document.domain;
chrome.extension.sendMessage({
dom: d
});
background.js
Added Event Listeners for Content and popup.js using onMessage() and onConnect() Listeners
var modifiedDom;
chrome.extension.onMessage.addListener(function (request) {
modifiedDom = request.dom + "Trivial Info Appending";
});
chrome.extension.onConnect.addListener(function (port) {
port.onMessage.addListener(function (message) {
if (message == "Request Modified Value") {
port.postMessage(modifiedDom);
}
});
});
popup.html
Sample browser action HTML Page registering popup.js to avoid Inline Scripting
<!doctype html>
<html>
<head>
<script src="popup.js"></script>
</head>
<body></body>
</html>
popup.js
Used Port\Long Lived Connection for communicating with background page for fetching results
var port = chrome.extension.connect({
name: "Sample Communication"
});
port.postMessage("Request Modified Value");
port.onMessage.addListener(function (msg) {
console.log("Modified Value recieved is " + msg);
});
Hope this helps, let me know if you need more information
Related
I've taken a look at other related SO posts and the solutions haven't helped solve my issue. This is my first chrome extension, so please bear with me!
I'm writing a simple chrome extension that searches for user provided keywords on a webpage. I can't get the content script that returns the DOM content to run. Some of the code, I've taken from an answer in another SO post, but I can't seem to get it to work for me.
I put a console.log("hello world") at the top of the file, and it doesn't show up, so I think it might be the structure of my project.
manifest.json
{
"name": "keyword search",
"version": "0.0.1",
"manifest_version": 2,
"permissions": [ "tabs" , "storage", "activeTab", "<all_urls>"],
"browser_action": {
"default_popup": "html/form.html"
},
"content_scripts": [{
"matches": [ "<all_urls>" ],
"js": [ "js/jquery.min.js", "content_scripts/content_script.js" ]
}],
"homepage_url": "http://google.com/"
}
js/popup.js
function run() {
running = true;
console.log('running');
var url = "https://www.stackoverflow.com/"
// Get KW & category for search
chrome.storage.local.get(["kw"],
function (data) {
kw = data.kw;
console.log("redirecting to find kw: " + kw);
// Send current tab to url
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.update(tabs[0].id, {url: url});
chrome.tabs.sendMessage(tabs[0].id, {type: 'DOM_request'}, searchDOM);
});
}
);
}
function searchDOM(domContent) {
console.log("beginning dom search \n" + domContent);
}
content_scripts/content_script.js
// Listen for messages
console.log("hello world")
chrome.runtime.onMessageExternal.addListener(function (msg, sender, sendResponse) {
// If the received message has the expected format...
if (msg.type === 'DOM_request') {
// Call the specified callback, passing
// the web-page's DOM content as argument
sendResponse(document.all[0].outerHTML);
}
});
console
running
redirecting to find kw: TestKeyword
beginning dom search
undefined
First, onMessageExternal is the wrong event (it's for external messaging):
you should use the standard onMessage.
Second, chrome extensions API is asynchronous so it only registers a job, returns immediately to continue to the next statement in your code without waiting for the job to complete:
chrome.tabs.update enqueues a navigation to a new URL
chrome.tabs.sendMessage enqueues a message sending job
the current page context in the tab gets destroyed along with the running content scripts
the tab starts loading the new URL
the message is delivered into the tab but there are no listeners,
but this step may instead run right after step 2 depending on various factors so the content script running in the old page will receive it which is not what you want
the tab loads the served HTML and emits a DOMContentLoaded event
your content scripts run shortly after that because of the default "run_at": "document_idle"
There are at least three methods to properly time it all:
make your content script emit a message and add an onMessage listener in the popup
use chrome.tabs.onUpdated to wait for the tab to load
use chrome.tabs.onUpdated + chrome.tabs.executeScript to simplify the entire thing
Let's take the executeScript approach.
remove "content_scripts" from manifest.json
instead of chrome.tabs.query (it's not needed) use the following:
chrome.tabs.update({url}, tab => {
chrome.tabs.onUpdated.addListener(function onUpdated(tabId, change, updatedTab) {
if (tabId === tab.id && change.status === 'complete') {
chrome.tabs.onUpdated.removeListener(onUpdated);
chrome.tabs.executeScript(tab.id, {
code: 'document.documentElement.innerHTML',
}, results => {
searchDOM(results[0]);
});
}
});
});
i develop my first chrome extension.
I try to call the page from my default_popup.
I try with the chrome.runtime.onMessage.addListener and the chrome.runtime.sendMessage but that do not work.
I read this page https://developer.chrome.com/apps/messaging, but i can't figure out where to place correctly my Listiner.
I need when i open the "default popup", call an event in the page and return something to the "default_popup" came from the page.
More explication :
Actually i have a content.js in this content.js i am able to call the background.js by calling the chrome.runtime.sendMessage but it's call to fast.
The DOM of the page have not enought time to load. My content.js inject some .js file in the webpage to interact with the page.
It's there a way i can call the crhome.extension.sendMessage from the injected page ?
Any suggestion ?
Ok i found it.
We can register in the background.js an event
chrome.runtime.onMessageExternal.addListener(
function (request, sender, sendResponse) {
debugger;
if (sender.url == blacklistedWebsite)
return; // don't allow this web page access
if (request.openUrlInEditor)
openUrl(request.openUrlInEditor);
});
You need to put in the manifest the right rules
"externally_connectable": {
"matches": ["*://*.example.com/*"]
}
After that from your injected page :
chrome.runtime.sendMessage(extensionID, { openUrlInEditor: "test" },
function (response) {
debugger;
if (!response.success)
handleError("est");
});
I'm working on building an chrome extension that communicates with an external SignalR HUB on server side.
I've managed to configure both to communicate with one another if I write the JS code in the pop-up page, the problem with this method is that if the extension is not opened, then it can't get updates (doesn't respond to the raised event).
In order to solve it I read that I should write my event handlers in the background.js, so even if the extension pop up is not showing - it would still respond to the event. However, I still need to support a button click on my extension to fire an event - which after reading a bit more is not possible cause I don't have access to the DOM in a background file.
So my question is how do I tackle this issue? how can I, from the client side call a function (or make ajax requests) in the server SignalR HUB? and also receive a response from the server when the popup is not opened.
By response I mean a to update values in the background.js and a simple +1 to the value in the icon badge, Something that will notify the user that something happened.
I'm very new to chrome extensions so I would appreciate the help!
This is my current code:
manifest.json
{
"manifest_version": 2,
"name": "Getting started ex1ample",
"description": "This extension shows a Google Image search result for the current page",
"version": "1.0",
"background": {
"scripts": ["jquery-2.1.4.min.js", "jquery.signalR-2.2.0.min.js", "background.js"],
"persistent": false
},
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"http://localhost:61275/"
]
}
background.js
var singalR = {};
$(document).ready(function(){
singalR.connection = $.hubConnection('http://localhost:61275/signalr/hubs', {useDefaultPath: false});
singalR.connection.logging = true;
singalR.roomIndexHubProxy = singalR.connection.createHubProxy('roomIndexHub');
singalR.connection.start().done(function() {
// Wire up Send button to call RoomIndexHubProxy on the server.
console.log('Hub has started');
$("#btn-join").click(function(){
singalR.roomIndexHubProxy.invoke('test', 111);
});
});
singalR.connection.error(function (error) {
console.log('SignalR error: ' + error)
});
singalR.roomIndexHubProxy.on('test', function (val) {
chrome.browserAction.setBadgeText({ text: val } );
});
});
popup.html
<!doctype html>
<html>
<head>
<script src="popup.js"></script> //empty for now
</head>
<body>
<button id="btn-join">Join</button>
</body>
</html>
Server Side HUB
public class RoomIndexHub : Hub
{
static int val = 0;
public RoomIndexHub(){
}
public async Task test(int k)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<RoomIndexHub>();
val++;
await Task.Delay(4000);
hubContext.Clients.All.test(val.ToString());
}
}
Have you tried setting the lifetime of your background page? Set persistence to true so this hidden page in background will "live" all the time and is able to listen to incoming requests.
"background": {
"scripts": ["background.js"],
"persistent": true
},
This will give you a persistent background page.
Check this: Chrome documentation for event pages
Reards
Carsten
I am trying to show a simple desktop notification code from a content script, but it doesn't seem to work.. I have added the permissions in the maifest.json file. Is there a restriction on showing them from the content script ?
You can't show notifications directly through a content script.
But, you can show them through the background page.
Your manifest.js should look something like this:
{
"name": "Notify This",
"version": "0.1",
"permissions": [
"notifications"
],
"background_page": "background.html",
"content_scripts": [
{
"matches": ["http://www.example.com/*"],
"js": ["contentscript.js"]
}
]
}
Then use the chrome.extension.sendRequest():
// in your contentscript.js
chrome.extension.sendRequest({msg: "Sup?"}, function(response) { // optional callback - gets response
console.log(response.returnMsg);
});
And on the receiving end you should have a onRequest listener:
// in your background.html
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
// Create a simple text notification:
var notify = webkitNotifications.createNotification(
'48.png', // icon url - can be relative
'Hello!', // notification title
request.msg // notification body text
);
notify.show();
setTimeout(function(){ notify.cancel(); },5000);
sendResponse({returnMsg: "All good!"}); // optional response
});
Yes, notifications use Chrome specific API, and the content script is only valid for general javascript etc... The background page is where all chrome specific API's are capable of running... First you'll need to register your background page in the manifest.json file - like this:
"background_page": "background.html",
Also in the manifest file, Allow the required permissions:
"permissions": [ "notifications" ],
Then your script in the background page should look like this :
<script>
setTimeout("setNotification();",1);
function setNotification(){
var n
if (window.webkitNotifications.checkPermission() != 0){
setNotification();
return false;
}
n = window.webkitNotifications.createHTMLNotification('http://www.your-notification-address.com');
n.show();}
</script>
I'm having fun with Google Chrome extension, and I just want to know how can I store the URL of the current tab in a variable?
Use chrome.tabs.query() like this:
chrome.tabs.query({active: true, lastFocusedWindow: true}, tabs => {
let url = tabs[0].url;
// use `url` here inside the callback because it's asynchronous!
});
This requires that you request access to the chrome.tabs API in your extension manifest:
"permissions": [ ...
"tabs"
]
It's important to note that the definition of your "current tab" may differ depending on your extension's needs.
Setting lastFocusedWindow: true in the query is appropriate when you want to access the current tab in the user's focused window (typically the topmost window).
Setting currentWindow: true allows you to get the current tab in the window where your extension's code is currently executing. For example, this might be useful if your extension creates a new window / popup (changing focus), but still wants to access tab information from the window where the extension was run.
I chose to use lastFocusedWindow: true in this example, because Google calls out cases in which currentWindow may not always be present.
You are free to further refine your tab query using any of the properties defined here: chrome.tabs.query
Warning! chrome.tabs.getSelected is deprecated. Please use chrome.tabs.query as shown in the other answers.
First, you've to set the permissions for the API in manifest.json:
"permissions": [
"tabs"
]
And to store the URL :
chrome.tabs.getSelected(null,function(tab) {
var tablink = tab.url;
});
Other answers assume you want to know it from a popup or background script.
In case you want to know the current URL from a content script, the standard JS way applies:
window.location.toString()
You can use properties of window.location to access individual parts of the URL, such as host, protocol or path.
The problem is that chrome.tabs.getSelected is asynchronous. This code below will generally not work as expected. The value of 'tablink' will still be undefined when it is written to the console because getSelected has not yet invoked the callback that resets the value:
var tablink;
chrome.tabs.getSelected(null,function(tab) {
tablink = tab.url;
});
console.log(tablink);
The solution is to wrap the code where you will be using the value in a function and have that invoked by getSelected. In this way you are guaranteed to always have a value set, because your code will have to wait for the value to be provided before it is executed.
Try something like:
chrome.tabs.getSelected(null, function(tab) {
myFunction(tab.url);
});
function myFunction(tablink) {
// do stuff here
console.log(tablink);
}
This is a pretty simple way
window.location.toString();
You probaly have to do this is the content script because it has all the functions that a js file on a wepage can have and more.
Hi here is an Google Chrome Sample which emails the current Site to an friend. The Basic idea behind is what you want...first of all it fetches the content of the page (not interessting for you)...afterwards it gets the URL (<-- good part)
Additionally it is a nice working code example, which i prefer motstly over reading Documents.
Can be found here:
Email this page
This Solution is already TESTED.
set permissions for API in manifest.json
"permissions": [ ...
"tabs",
"activeTab",
"<all_urls>"
]
On first load call function. https://developer.chrome.com/extensions/tabs#event-onActivated
chrome.tabs.onActivated.addListener((activeInfo) => {
sendCurrentUrl()
})
On change call function. https://developer.chrome.com/extensions/tabs#event-onSelectionChanged
chrome.tabs.onSelectionChanged.addListener(() => {
sendCurrentUrl()
})
the function to get the URL
function sendCurrentUrl() {
chrome.tabs.getSelected(null, function(tab) {
var tablink = tab.url
console.log(tablink)
})
async function getCurrentTabUrl () {
const tabs = await chrome.tabs.query({ active: true })
return tabs[0].url
}
You'll need to add "permissions": ["tabs"] in your manifest.
For those using the context menu api, the docs are not immediately clear on how to obtain tab information.
chrome.contextMenus.onClicked.addListener(function(info, tab) {
console.log(info);
return console.log(tab);
});
https://developer.chrome.com/extensions/contextMenus
You have to check on this.
HTML
<button id="saveActionId"> Save </button>
manifest.json
"permissions": [
"activeTab",
"tabs"
]
JavaScript
The below code will save all the urls of active window into JSON object as part of button click.
var saveActionButton = document.getElementById('saveActionId');
saveActionButton.addEventListener('click', function() {
myArray = [];
chrome.tabs.query({"currentWindow": true}, //{"windowId": targetWindow.id, "index": tabPosition});
function (array_of_Tabs) { //Tab tab
arrayLength = array_of_Tabs.length;
//alert(arrayLength);
for (var i = 0; i < arrayLength; i++) {
myArray.push(array_of_Tabs[i].url);
}
obj = JSON.parse(JSON.stringify(myArray));
});
}, false);
If you want the full extension that store the URLs that opened or seen by the use via chrome extension:
use this option in your background:
openOptionsPage = function (hash) {
chrome.tabs.query({ url: options_url }, function (tabs) {
if (tabs.length > 0) {
chrome.tabs.update(
tabs[0].id,
{ active: true, highlighted: true, currentWindow: true },
function (current_tab) {
chrome.windows.update(current_tab.windowId, { focused: true });
}
);
} else {
window.addEventListener(hash, function () {
//url hash # has changed
console.log(" //url hash # has changed 3");
});
chrome.tabs.create({
url: hash !== undefined ? options_url + "#" + hash : options_url,
});
}
});
};
you need index.html file also. which you can find in the this Github
the manifest file should be like this:
{
"manifest_version": 2,
"name": "ind count the Open Tabs in browser ",
"version": "0.3.2",
"description": "Show open tabs",
"homepage_url": "https://github.com/sylouuu/chrome-open-tabs",
"browser_action": {},
"content_security_policy": "script-src 'self' https://ajax.googleapis.com https://www.google-analytics.com; object-src 'self'",
"options_page": "options.html",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"background": {
"scripts": ["background.js"]
},
"web_accessible_resources": ["img/*.png"],
"permissions": ["tabs", "storage"]
}
The full version of simple app can be found here on this Github:
https://github.com/Farbod29/extract-and-find-the-new-tab-from-the-browser-with-chrome-extention