Running content script in only one chrome tab - javascript

I created a chrome extension and I want this extension to work in only one open tab. For example, I want this extension to work only on google.com. But although I have two google.com addresses open, I want this extension to work on only one of them. So the content script will only work on one google.com tab. If I close the tab where the extension is running, I want this extension to work again in the google.com tab that I will open.
First of all, I find the tab id matching google by searching all open windows and tabs. If this tab id is removed, I want it to inject content.js in the tab id that matches google it will find again, but this code did not work.
Can you help me?
Background.js :
var count = 0;
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
// for the current tab, inject the "inject.js" file & execute it
chrome.windows.getCurrent(function (win) {
chrome.tabs.getAllInWindow(win.id, function (tabs) {
// Should output an array of tab objects to your dev console.
for (let i = 0; i < tabs.length; i++) {
if (tabs[i].url.match(/google/g) == "google" && tabs[i].status == "complete") {
chrome.storage.sync.set({ indexTabId: tabs[i].id }, function () {
return;
});
}else{
chrome.storage.sync.set({ indexTabId: null }, function () {
return;
});
}
}
});
});
chrome.storage.sync.set({ removed: false }, function () {
});
chrome.storage.sync.get('indexTabId', function (data) {
// removed
chrome.tabs.onRemoved.addListener(function (tabId, info) {
chrome.tabs.get(tabId, function (tabremoved) {
if (data.indexTabId == tabId) {
chrome.storage.sync.set({ removed: true }, function () {
});
}
});
});
chrome.storage.sync.get('removed', function (data) {
if(data.removed){
count = 0;
}else{
count = 1;
}
});
if (data.indexTabId == tab.id && count < 1) {
count++;
console.log(tab.id);
chrome.tabs.executeScript(tab.id, {
file: 'content.js'
});
}
});
});

Related

Content script unloads when page is not visited for a long time

I'm working on a browser extension that needs to be constantly running, even after an automatic refresh in the background. The problem is, that the page randomly automatically unloads and the script just shuts off. I need to find a way to keep the content script on at all times. Here's part of the code:
// content.js:
function run(fn) {
if(typeof(Worker) !== "undefined") {
if(typeof(w) == "undefined") {
w = new Worker(URL.createObjectURL(new Blob(['('+fn+')()'])));
}
w.onmessage = function(event) {
if (isNaN(grabbedmin) && ID) {
bump() // Note: the bump function refreshes in the page.
w.terminate();
}
if ($("[href='/server/bump/" + ID + "']").text().includes("Bump")) {
bump()
w.terminate();
}
document.getElementById("bumpcount").innerHTML = "Autobumper Enabled: " + getCurrentTimestamp();
if (numberwow == grabbedmin) {
bump()
w.terminate();
}
};
}
}
The code above basically gets run every minute by this worker:
// content.js:
const worker = run(function() {
var i = 0;
function timedCount() {
i = i + 1;
postMessage(i);
setTimeout(function(){timedCount()},1000);
}
timedCount();
});
Is there a way for background.js to detect that content.js is not running (or that the page is unloaded) when it should be and then reload it?
Note: You can find the script here: https://github.com/Theblockbuster1/disboard-auto-bump
After looking through the docs and looking at examples, I put this together:
chrome.tabs.query({
url: ["*://disboard.org/*dashboard/servers", "*://disboard.org/*dashboard/servers/"] // finds matching tabs
}, function(tabs) {
tabs.forEach(tab => {
chrome.tabs.update(tab.id,{autoDiscardable:false});
});
});
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
// checks if the browser automatically re-enabled autoDiscarding and disables it
if (changeInfo.autoDiscardable == true) chrome.tabs.update(tabId,{autoDiscardable:false});
});

Updating an existing Chrome tab instead of opening a new one

I have created a Chrome extension which upon selecting text, offers a context menu link to Salesforce using the selected text:
function doSearch (search_target, tab)
{
chrome.tabs.create( {
url : "https://my.salesforce.com/apex/BR_caseRedirectDependingLicense?number="+search_target.replace(/\D/g,''),
selected : true,
index : tab.index + 1
} );
}
function selectionHandler (info, tab)
{
doSearch( info.selectionText, tab );
}
function resetContextMenus ()
{
chrome.contextMenus.removeAll(
function()
{
var id = chrome.contextMenus.create( {
title: "Open in Salesforce",
contexts: [ "selection" ],
onclick: selectionHandler
} );
}
);
}
resetContextMenus();
The intention here is to mark ticket numbers and open them in SF quickly, and it works perfectly.
However, I was wondering if it's possible to update an open salesforce tab instead of launching a new one every time.
I have tried looking around and encountered the following sample extension:
https://chromium.googlesource.com/chromium/src/+/master/chrome/common/extensions/docs/examples/api/tabs/inspector/
But it doesn't seem to work at all (perhaps because it's outdated).
I would much appreciate any help/guidance on how to approach this.
Yes, you can do that, you can do it using the chrome.tabs.update(..) function, here is an example, this will update the tab in which your context menu item was clicked:
function selectionHandler (info, tab) {
chrome.tabs.update(tab.id, {
url : "https://my.salesforce.com/apex/BR_caseRedirectDependingLicense?number="+info.selectionText.replace(/\D/g,''),
active : true
});
}
If you want to first create a new tab and then keep updating it, you can use something like this:
let tabId = -1;
function doSearch (search_target, tab)
{
const tabDetails = {
url : "https://my.salesforce.com/apex/BR_caseRedirectDependingLicense?number="+search_target.replace(/\D/g,''),
active : true,
index : tab.index + 1
};
if (tabId == -1) {
chrome.tabs.create(tabDetails, tab => {
tabId = tab.id;
});
} else {
// check if tab is still around
chrome.tabs.get(tabId, (tab) => {
if (tab) {
chrome.tabs.update(tab.id, tabDetails);
} else {
chrome.tabs.create(tabDetails, tab => {
tabId = tab.id;
});
}
});
}
}
Here is the chrome.tabs API documentation beside this two examples, you may also want to look into chrome.tabs.query(..), you can use that to find a specific tab.`
Also, in all these examples I've used active instead of selected because selected is deprecated.

Highlight current DOM element in Chrome Extension using DebuggerApi

I'm currently building an extension for chrome (I'm a beginner) and looking for some help to some one issue. The flow of the extension is the following:
User activate the extension
User click an icon in the extension panel to start the capture
When the mouse cursor is over a DOM element it highlight it
When the user click it gets the "selector" (unique identifier/path to the element)
After step 2 I attach a new Debugger instance to the tab. it seems like you can do this action either in background.js or content-script.js. Both work so my question is which one makes more sense. I'd say content-script because it doesn't interact directly with the browser but only with my extension. Am I right?
Second question is when using the DebuggerAPI I need to send command using the DevTools Protocol Viewer. I guess the command I must send to interact with my DOM element sit under this category (https://chromedevtools.github.io/devtools-protocol/tot/DOM). Most of the command requires a NodeId parameter. My question is how would I get this NodeId when the mouse cursor is over it. I have the following event in my content-script
chrome.runtime.onMessage.addListener(function(msg, sender){
if(msg == "togglePanel"){
togglePanel();
} else if (msg == "startCaptureElement") {
console.log("- Content-Script.js: Add Mouse Listener");
document.addEventListener('mouseover', captureEvent);
} else if (msg == "stopCaptureElement") {
console.log("- Content-Script.js: Remove Mouse Listener");
document.removeEventListener('mouseover', captureEvent);
}
});
function captureEvent(el) {
//console.log("- Content-Script.js: It's moving");
console.log(el);
chrome.runtime.sendMessage("highlightElement");
}
In my background.js script
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender);
if (request == "startCaptureElement") {
console.log("- Background.js: Attach the debugger");
chrome.debugger.attach({tabId: sender.tab.id}, "1.0");
chrome.tabs.sendMessage(sender.tab.id, "startCaptureElement");
} else if (request == "stopCaptureElement") {
console.log("- Background.js: Detach the debugger");
chrome.debugger.detach({tabId: sender.tab.id});
chrome.tabs.sendMessage(sender.tab.id, "stopCaptureElement");
} else if (request == "highlightElement") {
console.log("- Background.js: Highlight Element");
chrome.debugger.sendCommand({tabId: sender.tab.id}, "DOM.enable", {});
chrome.debugger.sendCommand({tabId: sender.tab.id}, "Overlay.inspectNodeRequested", {}, function(result) {
console.log(result);
});
}
}
);
I found the similar question here How to highlight elements in a Chrome Extension similar to how DevTools does it? but the code provided confused me a little bit.
Thanks for your help
"Overlay.inspectNodeRequested" is an event that should be listened to.
you can call "Overlay.setInspectMode" to select a node.
background.js:
var version = "1.0";
//show popup page while click icon
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.debugger.attach({tabId:tab.id}, version,
onAttach.bind(null, tab.id));
});
function onAttach(tabId) {
if (chrome.runtime.lastError) {
alert(chrome.runtime.lastError.message);
return;
}
chrome.windows.create(
{url: "headers.html?" + tabId, type: "popup", width: 800, height: 600});
}
headers.html:
<html>
<head>
<meta charset="utf-8">
<script src="headers.js"></script>
</head>
<body>
<div id="container">
<button id="btn_inspect">select node</button>
</div>
</body>
</html>
headers.js:
var tabId = parseInt(window.location.search.substring(1));
var hightCfg = {
'showInfo': true, 'showStyles':true, 'contentColor':{r: 155, g: 11, b: 239, a: 0.7}
}
//listen events when page is loaded
window.addEventListener("load", function() {
chrome.debugger.sendCommand({tabId:tabId}, "DOM.enable");
chrome.debugger.sendCommand({tabId:tabId}, "Overlay.enable");
chrome.debugger.onEvent.addListener(onEvent);
document.getElementById('btn_inspect').addEventListener('click', function(){
chrome.debugger.sendCommand({tabId:tabId}, "Overlay.setInspectMode",
{'mode':'searchForNode', 'highlightConfig':hightCfg});
});
});
window.addEventListener("unload", function() {
chrome.debugger.detach({tabId:tabId});
});
var requests = {};
function onEvent(debuggeeId, message, params) {
console.log('onEvent ...'+message);
if (tabId != debuggeeId.tabId)
return;
if (message == "Network.inspectNodeRequested") {
//do something..
}
}

Chrome extensions close all tabs without certain div

i'm having a lot of trouble with Chrome Extensions, im trying to close all open tabs that do not contain a certain class.
This is the general idea of what i am trying to do, some of it is pseudo-code.
//background.js
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.tabs.query(function(tabs) {
chrome.tabs.sendMessage(tabs, {"message": "clicked_browser_action"});
});
});
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "clicked_browser_action" ) {
for (var i = 0; i < request.length; i++) {
var existsClass = request[i].getElementByClass("someClass");
if (existClass === null) {
//TODO Close tab
}
}
}
}
);
Any help or suggestions would be appreciated.
Thanks!
I'm assuming your second snippet is from a content script.
In that case, it's as simple as window.close(), because you're in that tab's context. No need for Chrome APIs.
Try this:
//background.js
chrome.browserAction.onClicked.addListener(function () { //when the extension's icon is pressed
chrome.tabs.query({},function(tabs) { // get all tabs
for (var i = tabs.length; i--;){ // loop through all tabs
chrome.tabs.executeScript(tabs[i].id,{code: //execute this code in each tab
"if (!document.querySelector(\".someClass\")) close();"});
// ^ if no element is found with the selected class, close the tab
}
});
});
You don't need a separate content script for that.

Chrome tab.create and capture screenshot of new created tab

I have an issue with capturing a newly created tab in chrome.
I create the new tab with chrome.tabs.create and pass the tabid to my callback function which captures it.
function createtab(url) {
chrome.tabs.create({'url': url,'active':false}, function(tab) {
captureWindowTab((tab.id);
});
}
function captureWindowTab(tabid) {
chrome.tabs.update(tabid, {}, function() {
chrome.tabs.captureVisibleTab(27, {format:"png"}, function(dataUrl) {
capturecallback(dataUrl);
});
});
}
function capturecallback(dataurl) {
console.log(dataurl);
}
It works ONLY when i do it on current existing tabs. i cannot get it to work on newly created tabs. always returns undefined.
I dont understand whats the issue.
Based on the documentation it seems you need the host permission (or all hosts permission) to be able to capture it. See the docuemtation at:
https://developer.chrome.com/extensions/tabs.html#method-captureVisibleTab
Do you have the host permission or all hosts permission set?
I think you might also need the "tabs" permission, if you don't already have it.
Resolved it like this:
chrome.tabs.onUpdated.addListener(function(tabid , info) {
//console.log('loading tab'+tabid);
if(info.status == "complete") {
chrome.tabs.get(tabid,function(tab) {
chrome.topSites.get(function(sites){
tab.url = NewTab.getHostFromUrl(tab.url);
console.log(tab.url);
//console.log('loaded '+tab.url);
for (var i = 8 - 1; i >= 0; i--) {
sites[i].url = NewTab.getHostFromUrl(sites[i].url);
//console.log('checking '+sites[i].url);
if(tab.url == sites[i].url && tab.url != 'newtab') {
chrome.tabs.update(tabid, {'highlighted':true,'active':true}, function(tab){
chrome.tabs.captureVisibleTab(chrome.windows.WINDOW_ID_CURRENT, {format:"jpeg","quality":30}, function(dataUrl) {
// add data URL to array
if(dataUrl) {
console.log('its a winner!');
window.localStorage['topsite_'+encodeURI(NewTab.getHostFromUrl(tab.url))+'_thumbnail'] = dataUrl;
NewTab.getTopSites();
}
});
});
}
};
});
});
}
});

Categories