I am writing a small extension that allows me to easy submit links to reddit.
This extensions adds a new context menu ('Submit Page'). If the users right clicks and selects this menu the www.redddit.com/submit page is opened in another tab, and the page from where the menu was triggered is submitted.
I've added the context menus:
contextMenu.js
// Setup where the menu is presents;
// A list of [context, context menu text, id]
var redditURL = 'http://www.reddit.com/submit';
var contexts = [["page", "Submit page", "id-submitPage"], ["link", "Submit link", "id-submitLink"], ["editable", "Submit text", "id-submitText"], ["image", "Submit image", "id-submitImage"]];
// Add all menus to their context
contexts.forEach(function(element) {
chrome.contextMenus.create({
"title" : element[1],
"contexts" : [element[0]],
"id" : element[2]
});
});
// Add actions to menus
chrome.contextMenus.onClicked.addListener(function(info, tab) {
var submittedURL = tab && tab.url;
if (info["menuItemId"] == "id-submitPage") {
chrome.tabs.create({
"url" : redditURL
}, function(tab) {
// After we create the tab we also send a message to the content
// script associated with the page to intercept our info
console.log(submittedURL);
chrome.tabs.sendMessage(tab.id, {
"url" : submittedURL,
"type" : "submitPage"
});
});
}
});
As you can in see in the addListener I am using chrome.tabs.sendMessage to send the URL I am submitting to the content script associated with: redditURL .
The content script: contextMenu-RedditSubmit.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
alert('here');
console.log(sender.tab ? "from a content script:" + sender.tab.url : "from the extension");
});
And the manifest file:
...
"background": {
"scripts": ["contextMenu.js"],
"persistent": false
},
"content_scripts": [
{
"matches": ["http://www.reddit.com/submit"],
"js": ["contextMenu-RedditSubmit.js"],
"run_at": "document_start"
}
],
...
Problem is my messages are not received inside the contextMenu-RedditSubmit.js content script. I cannot see neither the console.log nor the alert. Any tips ?
Your message is sent before event document_start content scripts execute.
To ensure it works, switch to using programmatic injection:
chrome.tabs.create({
"url" : redditURL
}, function(tab) {
// After we create the tab we also send a message to the content
// script associated with the page to intercept our info
chrome.tabs.executeScript(
tab.id,
{file: "contextMenu-RedditSubmit.js"},
function() {
// Here, it is guaranteed that the script finished executing
// (or there was an error)
chrome.tabs.sendMessage(tab.id, {
"url" : submittedURL,
"type" : "submitPage"
});
}
);
});
Related
I'm new on chrome extension,
I'm creating a basic extension, thats will show the selected html with tags (spans, divs and all other DOMs) on an alert
I try this chrome.contextMenus.create (code below) but it showing just the selected string
chrome.contextMenus.create({title: "Selected HTML", contexts:["selection"], onclick: showSelectedHtml});
I just want to know if theres a way to get selected html doms(with tags if available) instead of string!
Thanks;
As you can see in the documentation contextMenus API can't do that.
The solution is to run a content script that gets the HTML and returns it into your background script.
manifest.json:
"permissions": ["activeTab", "contextMenus"],
"background": {
"scripts": ["background.js"],
"persistent": false
}
background.js:
// in Chrome the menus should be created only at install/update
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: 'sel',
title: 'Selected HTML',
contexts: ['selection'],
}, () => chrome.runtime.lastError); // ignore errors about an existing id
});
chrome.contextMenus.onClicked.addListener((info, tab) => {
chrome.tabs.executeScript(tab.id, {
code: `(${getSelectedHtml})()`,
frameId: info.frameId,
matchAboutBlank: true,
runAt: 'document_start',
}, data => {
if (chrome.runtime.lastError) {
alert('Error: ' + chrome.runtime.lastError.message);
} else {
prompt('HTML', data[0]);
}
});
});
// this function's code will be executed as a content script in the web page
function getSelectedHtml() {
const sel = getSelection();
let html;
if (sel.rangeCount) {
const div = document.createElement('div');
div.appendChild(sel.getRangeAt(0).cloneContents());
html = div.innerHTML;
}
return html || '';
}
Note: don't use the onclick property in contextMenus.create() because it doesn't work with "persistent":false background script, which is the preferred type (more info).
I'm building a very basic google chrome extension that has to listen all received notifications comes through google chrome!
My Extension's file structure;
manifest.json
background.js
icons
main.png
manifest.json
{
"manifest_version": 2,
"name": "My Extension",
"version": "1.0.0",
"browser_action": {
"default_icon": {
"16": "icons/main.png",
"24": "icons/main.png",
"32": "icons/main.png"
}
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"permissions": [
"notifications"
]
}
background.js
console.log('Lady Gaga');
chrome.browserAction.onClicked.addListener(function(){
console.log('Clicked');
});
chrome.notifications.onClosed.addListener(function (s,b){
console.log('notification Closed');
});
chrome.notifications.onClicked.addListener(function (){
console.log('notification Clicked');
});
chrome.notifications.onButtonClicked.addListener(function (){
console.log('notification Button Clicked');
});
So if I click my extension's button
chrome.browserAction.onClicked
Fired, and when I check the background LOGS, I can see that "Lady Gaga" and "Clicked" logs got fired!
Next, I'm trying to see logs of the notifications listeners. In order to fire up to notification's listeners found a website which has basic HTML buttons that sending notifications easily.
https://web-push-book.gauntface.com/demos/notification-examples/
I'm using this website to send notifications on my own to test background event listeners which are defined as listeners for notifications events.
But none of the notifications events is not triggering, working properly. I can't see any logs like "notification Button Clicked" or "notification Closed"
What's wrong with that scenario?
manifest.json
{
"manifest_version" : 2,
"name" : "demo1",
"description" : "Demo",
"version" : "0.1",
"background" : {
"scripts" : ["background.js"],
"persistent" : false
},
"permissions" : [
"notifications"
]
}
background.js
var description = "dvcvv";
var news = "cvcvcvcvcvcvcvcvcv";
var pattern = {
OPTION : "list",
};
var a1 = {
title : "xxxxxxxxxxxxxxxxxx",
message : "dsdsdsdX"
};
var a2 = {
title : "yyyyyyyyyyyy",
message : "sdsdsdsdY"
};
var butt1 = {
title : "Button 1 "
};
var butt2 = {
title : "Button 2"
};
var notifopt = {
type : pattern.OPTION,
iconUrl : "icon.png",
title : description,
message : news,
buttons : [butt1,butt2],
items : [a1,a2]
};
chrome.notifications.create(notifopt,function() {
console.log('Lady Gaga');
});
chrome.notifications.onClicked.addListener(function() {
console.log('notification Clicked');
});
chrome.notifications.onClosed.addListener(function() {
console.log('notification Closed');
});
chrome.notifications.onButtonClicked.addListener(function() {
console.log('notification Button Clicked');
});
google chrome --> more tools --> extension --> load unpacked --> refresh extension --> display notification --> click button1 --> click See the views page, in the background --> you see console.log
I am developing a Mozilla WebExtension. I want to inject a JavaScript file only into the frame in which I have clicked on the context menu selection created with contextMenus.create().
I am using:
browser.contextMenus.create({
"title": "Records",
"contexts": ["all","link"],
"id" : "M1",
"onclick": onClickContextMenu,
}, function() { });
function onClickContextMenu(info, tab){
var clickedFrameID=""; //How do I get the actual frameId where click occurred?
browser.tabs.executeScript(tab.id,{
file: "fileName.js",
allFrames: false,
frameId: clickedFrameID
}, function() {
console.log("Script injected");
});
}
How to get clickedFrameID?
After Making so many testing me (Chandrakant Thakkar) and my team leader Mr. Nitin Makwana got the solution for this situation,
First I have injected "messageListener.js" file in all frames from manifest.json file as
"content_scripts": [
{
"matches": ["https://*/*","http://*/*"],
"css":["jquery-ui.css"],
"js": [
"jquery.js",
"jquery-ui.js",
"content_scripts/msg_listener.js"
],
"all_frames":true
}
Then in "messageListener.js" file created "contextMenu" Listener and send message to Background js file when I click contextMenu (Right Click Of Mouse)
as
document.addEventListener("contextmenu", handleContextMenu, false);
function handleContextMenu(event){
browser.runtime.sendMessage("abc#gmail.com",{type:
"onContextMenuClicked", sender:event });
}
here, "abc#gmail.com" is id of my web extension where I want to send message.
Then, In my background js file I have declared on global variable named "clickedFrameID" and in same file I have added onMessage Listener as below
browser.runtime.onMessage.addListener(
function(msg, sender, callback) {
if(msg.type === 'onContextMenuClicked')
{
if(sender.hasOwnProperty("frameId")){
clickedFrameID=sender.frameId;
}else{
clickedFrameID="";
}
}
});
Now I have injected "fileName.js" file in specific Frame as Below
var clickedFrameID=""; //This is a Global Variable
browser.contextMenus.create({
"title": "Records",
"contexts": ["all","link"],
"id" : "M1",
"onclick": onClickContextMenu,
}, function() { });
function onClickContextMenu(info, tab){
var options={};
if(clickedFrameID !="" && clickedFrameID!=null &&
clickedFrameID!=undefined )
{
options={
file: "fileName.js",
allFrames: false,
frameId: clickedFrameID
};
}
browser.tabs.executeScript(tab.id,options, function() {
console.log("Script injected");
});
}
Now "fileName.js" will be injected in specific frame in that I have right clicked.
Thanks #wOxxOm, #MohammedAshrafali, #Makyen to take interest
I am trying to build a simple chrome extension to get a value from a page and populate a second page after.
I'm new to chrome extensions, and I'm really only doing this to make something I have to do often simpler.
So I got the part where I open the first page, get the value I need and then I open the second page in another tab. Now I'm not sure how to populate the field.
Since I already have the value on content.js, is it possible to know when the other tab has loaded to just look for the field where i need to put that value in? Or is there another way to do it? I can't get it to work.. I also tried to listen to page loads, but I don't think that will help me, as I'm only interested in one particular page.
Manifest:
{
"manifest_version": 2,
"name": "my Extension",
"version": "1",
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["jquery-3.2.1.min.js", "content.js"]
}
],
"browser_action": {
"default_icon": "icon.png"
},
"background": {
"scripts": ["background.js"]
}
}
background.js
// Called when the user clicks on the browser action.
chrome.browserAction.onClicked.addListener(function(tab) {
// Send a message to the active tab
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var activeTab = tabs[0];
chrome.tabs.sendMessage(activeTab.id, {"message": "clicked_browser_action"});
});
});
//
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "open_new_tab" ) {
chrome.tabs.create({"url": request.url},
function(tab){ alert(tab.id) });
}
}
);
chrome.tabs.onUpdated.addListener(function (tabId , info) {
if (info.status === 'complete') {
chrome.tabs.sendMessage(activeTab.id, {"message": "page_loaded"});
}
});
content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "clicked_browser_action" ) {
var myUrl = "http://www.google.com";
var myValue = document.getElementById("thisId").value;
if(myValue ) {
chrome.runtime.sendMessage({
"message": "open_new_tab",
"url": myUrl,
"myValue ": myValue
});
}
}
if( request.message === "page_loaded" ) {
alert("hi");
}
});
I am making a chrome extension with two buttons : Start and Stop. On click of start button the html page, should start refreshing after a particular timer, and on click of stop it should stop refreshing.
The HTML page has a table in it say with id myTable.So after every refresh, I want to have row count of this table.
To get this I did something like this :
First for pop up, I made popup.js
window.onload = function() {
document.getElementById("startbutton").onclick = function() {
chrome.extension.sendMessage({
type: "table-row-count_start"
});
}
document.getElementById("stopbutton").onclick = function() {
chrome.extension.sendMessage({
type: "table-row-count_stop"
});
}
}
In background.js
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
switch(request.type) {
case "table-row-count_start":
alert("Refershing started");
RefreshAndCount();
break;
case "table-row-count_stop":
alert("Stop Refershing");
break;
}
return true;
});
var RefreshAndCount = function(){
chrome.tabs.getSelected(null, function(tab){
chrome.tabs.sendMessage(tab.id, {type: "table-row-count"});
chrome.browserAction.setBadgeText({text: "Counting!"});
});
}
This will make call to content.js as we need to interact with DOM of HTML page. In this script I did something like this :
chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {
switch(message.type) {
case "table-row-count":
var x = document.getElementById("myTable").rows.length;
alert("Row count = " + x);
var Refresh = confirm("Do you want to refresh the page?");
if (Refresh)
{
setTimeout("location.reload(true);",5000);
}
break;
}
});
The script content.js is never called. I don't know why so. Please help.
Also it will be refreshing only once, how to keep refershing after fixed timer.
Here is manifest.json
{
"name": "Refresher",
"version": "0.0.1",
"manifest_version": 2,
"description" : "Refresh the site contents after a while",
"icons": { "32": "icon.jpg" },
"browser_action": {
"default_icon": { "32": "icon.jpg" },
"default_title": "Refersher",
"default_popup": "browseraction/popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": true
},
"content_scripts": [{
"matches": ["http://www.w3schools.com/html/tryit.asp?filename=tryhtml_table"],
"js": ["content.js"]
}]
}
In this case you've used a deprecated chrome.tabs.getSelected which returned the wrong tab with id -1 so the message was never delivered and an error was displayed in the console.
Use chrome.tabs.query:
var RefreshAndCount = function() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {type: "table-row-count"});
chrome.browserAction.setBadgeText({tabId: tabs[0].id, text: "Counting!"});
});
};
Also note how setBadgeText was used just for the specified tab.
N.B. Always, always use the debugger to check what's wrong. Thus you can stop using alert and start using console.log or inspect/watch the variables in the debugger.