Cant get chrome.tabs.executeScripts to work - google-chrome-extension

I am trying to modify an existing chrome extention.
What i want is a chrome extention where i populate a popup window full of urls and then when i click OK each url opens up in a new tab 1 at a time, certain data on that tab is then copied somewhere, the tab closes and the next url in the list is called and so on untill the list is complete. the extention finally outputs all the copied data from all the tabs into a CSV file (which i can then manipulate into Excel.
I have looked everywhere but so far i have only got as far as to open the tabs up HOWEVER they all open at the same time. this i sas far as i have got.
I have tried using chrome.tabs.execute script and that seems to block the loop,
Any ideas?
EDIT - HERE IS THE FULL CODE
Many Thanks
function loadSites(e) {
var urlschemes = ['http', 'https', 'file', 'view-source'];
var urls = document.getElementById('urls')
.value.split('\n');
var lazyloading = document.getElementsByName('lazyloading')[0].checked;
for (var i = 0; i < urls.length; i++) {
theurl = urls[i].trim();
if (theurl != '') {
if (urlschemes.indexOf(theurl.split(':')[0]) == -1) {
theurl = 'http://' + theurl;
}
if (lazyloading && theurl.split(':')[0] != 'view-source' && theurl.split(':')[0] != 'file') {
chrome.tabs.create({
url: chrome.extension.getURL('lazyloading.html#') + theurl,
selected: false
});
} else {
chrome.tabs.create({
url: theurl,
selected: true,
activ
function(tab) {
chrome.tabs.executeScript(tab.id, { file: "contentscript.js" });
});
}
}
}
}

Related

Chrome Extension - Get page source when fully loaded (client side content too)

I'm developing a Chrome Extension where I need to retrieve the source code of a newly create tab.
Retrieving the source code is not a problem as such, my script below does that perfectly but what I'm looking for is to get the source code once the page has been completely loaded included dynamic content that has been inserted after page load (like with Ajax for example).
To get the source code, I'm using
chrome.tabs.executeScript(tabId,
{
file: 'test.js',
}, function(results)
{
// DO SOMETHING HERE
}
test.js contains the following:
function DOMtoString(document_root) {
var html = '',
node = document_root.firstChild;
while (node) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
html += node.outerHTML;
break;
case Node.TEXT_NODE:
html += node.nodeValue;
break;
case Node.CDATA_SECTION_NODE:
html += '<![CDATA[' + node.nodeValue + ']]>';
break;
case Node.COMMENT_NODE:
html += '<!--' + node.nodeValue + '-->';
break;
case Node.DOCUMENT_TYPE_NODE:
// (X)HTML documents are identified by public identifiers
html += "<!DOCTYPE " + node.name + (node.publicId ? ' PUBLIC "' + node.publicId + '"' : '') + (!node.publicId && node.systemId ? ' SYSTEM' : '') + (node.systemId ? ' "' + node.systemId + '"' : '') + '>\n';
break;
}
node = node.nextSibling;
}
return html;
}
chrome.runtime.sendMessage({
action: "getSource",
source: DOMtoString(document),
metadata: shop_metadata
});
What I would like to do is to retrieve the source code only when a class has been detected and if it failed after a couple of seconds, the script should skip the process. The class I'm looking for is available in the "shop_metadata" variable.
Is there a way to make that happen with SendMessage like in my script?
I have tried to do this:
function test (document)
{
var checkExist = setInterval(function()
{
if ($('.product-title').length)
{
console.log("Exists!");
source = DOMtoString(document);
console.log(source);
return source;
clearInterval(checkExist);
}
}, 5000);
}
and then modify my message:
chrome.runtime.sendMessage({
action: "getSource",
source:test(document),
metadata: shop_metadata
});
If I executed this in the console, I get the source code with the dynamic content but when I checked the content of "source" in the extension, it returns "undefined"
Thanks
Laurent

Open a new tab with a selected word in page

Is possible to create an extension for google chrome do: to select a word, click the right button and open a new tab using the word as part of a url?
Example of word: test
Go to page: http://www.example.com/test
You can simply use chrome.contextMenus.create and chrome.tabs.create in the background.js. I've created the code and it works with me.
function sendSearch(selectedText) {
var serviceCall = 'http://www.example.com/' + selectedText;
chrome.tabs.create({url: serviceCall});
}
chrome.contextMenus.create(
{
title: "Find '%s' on example.com!",
contexts:["selection"],
onclick: function(info, tab) {
sendSearch(info.selectionText);
}
});
Based on the Best practices when using event pages #Xan mentioned. You can use chrome.contextMenus.onClicked instead. Like:
function sendSearch(selectedText) {
var serviceCall = 'http://www.example.com/' + selectedText;
chrome.tabs.create({url: serviceCall});
}
chrome.contextMenus.create(
{
title: "Find '%s' on example.com!",
contexts:["selection"],
"id": "ViewSelectedLink"
});
function contextClicked(info, tab) {
if (info.menuItemId == "ViewSelectedLink" ) {
sendSearch(info.selectionText);
}
}
chrome.contextMenus.onClicked.addListener(contextClicked);

Multiple Tab Chrome Extension Issue

I've created a basic extension that searches Google if the URL/HTML content fulfill certain requirements. It works for the most part, but fails miserably when there are multiple instances of the extension. For example, if I load tab A and then tab B, but click on the page action for tab A, I will be directed to a search of tab B's content.
I don't know how to silo the script to each tab, so that clicking tab A's page action will always result in a search for tab A stuff. How can that be done? I'd appreciate your suggestions!
background.js
title = "";
luckySearchURL = "http://www.google.com/search?btnI=I%27m+Feeling+Lucky&ie=UTF-8&oe=UTF-8&q=";
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.title != "") {
title = request.title;
sendResponse({confirm: "WE GOT IT."});
}
});
chrome.tabs.onUpdated.addListener(function(tabId, change, tab) {
if (change.status === "complete" && title !== "") {
chrome.pageAction.show(tabId);
}
});
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.create({url: luckySearchURL + title})
})
contentscript.js
function getSearchContent() {
url = document.URL;
if (url.indexOf("example.com/") > -1)
return "example";
}
if (window === top) {
content = getSearchContent();
if (content !== null) {
chrome.runtime.sendMessage({title: content}, function(response) {
console.log(response.confirm); })
};
}
You could do something like store the title with its associated tabId, that way when you click on the pageAction it uses the correct title. The changes would be just these:
background.js
title= [];
[...]
chrome.runtime.onMessage.addListener(function(request,sender,sendResponse){
if (request.title != "") {
title.push({tabId:sender.tab.id, title:request.title});
sendResponse({confirm: "WE GOT IT."});
}
});
[...]
chrome.pageAction.onClicked.addListener(function(tab) {
title.forEach(function(v,i,a){
if(v.tabId == tab.id){
chrome.tabs.create({url: luckySearchURL + v.title});
// Here I am going to remove it from the array because otherwise the
// array would grow without bounds, but it would be better to remove
// it when the tab is closed so that you can use the pageAction more
// than once.
a.splice(i,1);
}
});
});
You're facing this issue because of window === top. So your title variable gets its value from the last opened tab. So if B is opened after A, title gets its value from B. Try this: Detect Tab Id which called the script, fetch the url of that tab, which then becomes your title variable. As below:
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.query({active:true},function(tabs){
//this function gets tabs details of the active tab, the tab that clicked the pageAction
var urltab = tabs[0].url;
//get the url of the tab that called this script - in your case, tab A or B.
chrome.tabs.create({url: urltab + title});
});
});

How to move a tab after the last pinned tab?

The extension is designed so that when you click a pinned tab, it moves it to the rightmost position out of all the pinned tabs. It works a few times before I keep getting the issue:
Error during tabs.move: Tabs cannot be edited right now (user may be
dragging a tab).
chromeHidden.handleResponse
When I use the debugger though, it works every single time.
Code:
chrome.tabs.onActivated.addListener(function(tab) {
chrome.windows.getAll({"populate":true}, function(windows) {
var tabs = [];
for (var i = 0; i < windows.length; i++) {
var win = windows[i];
if (win.id == tab.windowId) {
tabs = win.tabs;
for (var k = 0; k < tabs.length; k++) {
var tempTab = tabs[k];
if (tempTab.id == tab.tabId && tempTab.pinned == true) {
for (var j = k; tabs[j+1] && tabs[j+1].pinned; j++) {
chrome.tabs.move(tab.tabId, {"index":j+1});
}
break;
}
}
}
}
});
});
Your current code has some flaws:
Inefficiency: You select all windows and tabs, while only the pinned tabs in the current window are needed.
Incorrect use of the asynchronous chrome.tabs.move method: You're moving the single tab after the last pinned tab by repeatedly moving the tab to the right. As I said, chrome.tabs.move is asynchronous, so when you call chrome.tabs.move again, the previous "move request" might not have finished yet. Hence your error.
To get more efficient, use the chrome.tabs.query method with the relevant filters:
chrome.tabs.onActivated.addListener(function(activeInfo) {
var tabId = activeInfo.tabId;
chrome.tabs.query({
currentWindow: true,
pinned: true
}, function(tabs) {
// Only move the tab if at least one tab is pinned
if (tabs.length > 0) {
var lastTab = tabs[ tabs.length - 1 ];
var tabIndex = lastTab.index + 1;
for (var i=0; i<tabs.length; ++i) {
if (tabs[i].id == tabId) {
// Current tab is pinned, so decrement the tabIndex by one.
--tabIndex;
break;
}
}
chrome.tabs.move(tabId, {index: tabIndex});
}
}); // End of chrome.tabs.query
}); // End of chrome.tabs.onActivated.addListener
If you want to do something else after moving the tab, pass a callback to chrome.tabs.move:
chrome.tabs.move(tabId, {index: tabIndex}, function() {
console.log('Moved tab!');
});
Note: The tab won't move if you keep the mouse pressed. Also, always moving the tab when a tab is focused is a bit unfriendly in terms of user experience. You'd better use a browser action button to activate this feature. Yes, it's one additional click to move the tab, but at least the user will have a choice to not move tabs if they want to.
chrome.browserAction.onClicked.addListener(function(tab) {
var tabId = tab.id;
chrome.tabs.query({currentWindow: true, pinned: true}, ...);
});

When I close a window and then open a different one, the selected tab is recreated by Chrome

I am writing a Chrome extension that saves/restores your browsers window state - So, I save the state of a given window:
var properties = [ "top",
"left",
"width",
"height",
"incognito",
"focused",
"type"
];
var json = {};
var cache = chrome_window_object;
// copy only the keys we care about:
_.each(properties,function(key,value) {
json[key] = cache[key];
});
// then copy the URLs of the tabs, if they exist:
if(cache.tabs) {
json.url = [];
_.each(cache.tabs,function(tab) {
json.url.push(tab.url);
});
}
return json;
At some point in the future, I remove all windows:
closeAllWindows: function(done_callback) {
function got_all(windows) {
var index = 0;
// use a closure to only close one window at a time:
function close_next() {
if(windows.length <= index) return;
var window = windows[index++];
chrome.windows.remove(window,close_next);
}
// start closing windows:
close_next();
}
chrome.windows.getAll(got_all);
}
and then I restore the window using:
chrome.windows.create(json_from_before);
The window that is created has an extra tab in it, whatever was in the window that I just closed... I am completely floored, and I assume the problem is something that I am doing in the code that I haven't posted (it's a big extension). I've spent a few hours checking code line by line and making sure I'm not explicitly asking for this tab to be created. So - has anybody seen anything like this before?

Resources