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();
}
});
});
}
};
});
});
}
});
Related
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'
});
}
});
});
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.
i'm having difficulties trying to open up links in phonegap's (cordova's) inAppBrowser.
I need to be able to make it so the IAB can open both local phonegap links (file:///android_assets/www/example.html) and online links (https://www.google.com for instance)
I have achieved this so far by creating an object in index.js which creates an initiate IAB object, and then for every call from there onwards I was thinking that I could just open that link.
I've found a number of problems, for example when I try to use window.location = some_url it will change the index.html page to that some_url and hence my attached JS no longer works.
I've tried injecting a window.location from my index.html's JS into the IAB document however that breaks down when trying to fetch a local file
My current method is causing a memory leak because it's continuously opening IAB objects which I'm then having difficulties closing because ...
Using the .close() method on an IAB object shows (according to Chrome's Remote Devices view) that it doesn't actually delete the IAB window but rather turns it into an about:new tab
Heres my current code for the JS which is called in index.js (im sorry i know there's a lot of redundant code!)
var interceptor = {
// library dictionary object of <K,V> pairs in the form of <current page, desired page>
// insert your k,v pairs here:
library: {
'login/signup.php': 'example.html', //test data
'calendar/view.php': 'example.html',
'course/view.php?id=10': 'example.html'
},
// origin dictionary
// dictionary for redirecting from the phonegap page to the moodle page
// must be explicit in your page names and avoid duplication
// e.g. use full path notation -> full/path/to/file.html not file.html
origin: {
'current/attempt': ['example1.html', 'example2.html', 'course/index.php'] //test data
},
history_stack: [],
// stack of all current windows
browser_windows: [],
is_back: 'false',
windows: 0,
redirect_flag: false,
first: true,
currentWindow: null,
currentLocalFile: null,
get_origin: function() {
return this.origin;
},
get_library: function() {
return this.library;
},
// interceptor constructor
initialize: function(old_ref = null, default_url = config.moodleURL, android = true) {
// interval for checking our back flag
// the scope changes when you enter the anonymous closure and this changes. this is a hack for that
var self = this;
var ref;
console.log('default url: ' + default_url);
// check for android
if ((android) && (self.windows < 1)) {
// self.browser_windows[0] = cordova.InAppBrowser.open(default_url, '_blank', 'location=no,zoom=no');
ref = cordova.InAppBrowser.open(default_url, '_blank', 'location=yes,zoom=no');
self.first = false;
}
// otherwise iOS
else if ((!android) && (self.windows < 1)) {
// self.browser_windows[0] = cordova.InAppBrowser.open(default_url, '_blank', 'location=no,zoom=no,suppressesIncrementalRendering');
ref = cordova.InAppBrowser.open(default_url, '_blank', 'location=no,zoom=no,suppressesIncrementalRendering');
// self.browser_windows.push(ref);
self.first = false;
} else {
old_ref =
// old_ref = cordova.InAppBrowser.open(default_url, '_blank', 'location=yes,zoom=no');
ref = old_ref;
}
self.windows++;
var library_dictionary = this.get_library();
var origin_dictionary = this.get_origin();
var redirect_URL;
ref.addEventListener('loadstart', function(event) {
// push current page to histoy stack
self.history_stack.push(event.url);
// check to see if an element of one of our origin arrays is in the URL
for (var origin_list in origin_dictionary) {
if (event.url.includes(origin_list)) self.redirect_flag = true;
for (var elements in origin_dictionary[origin_list]) {
// if it is raise a flag and store the key that its array maps to
if ((event.url.includes(origin_dictionary[origin_list][elements])) && (self.redirect_flag)) {
redirect_URL = origin_list;
self.redirect_flag = false;
var temp_previous_pages = self.history_stack;
var temp_element;
// pop elements of stack until empty
while (temp_previous_pages.length !== 0) {
temp_element = temp_previous_pages.pop();
// if we find an element in the stack (our URL history) that matches the key that our array mapped to
if (temp_element.indexOf(redirect_URL) !== -1) {
// redirect and break from loop
self.initialize(ref, temp_element, android);
break;
}
}
}
}
}
for (var key in library_dictionary) {
if (event.url.includes(key)) {
self.initialize(ref, library_dictionary[key], android);
break;
}
}
});
ref.addEventListener('loadstop', function() {
// when we've finished loading our page set up an interval every 2.5 seconds to check
// if we've been signalled to change pages
console.log('here');
var is_back_interval = setInterval(function() {
ref.executeScript({
code: "localStorage.getItem('is_back')"
}, function(values) {
if (values[0] === 'true') {
// if we have been signalled then remove that signal from our html or moodle page
ref.executeScript({
code: "localStorage.setItem('is_back', '')"
});
// get 3rd last since the last will be the current page as will the 2nd last
prev_page = self.history_stack[self.history_stack.length - 3];
self.initialize(ref, prev_page, android);
}
});
}, 2500);
});
}
};
and heres index.js
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicitly call 'app.receivedEvent(...);'
onDeviceReady: function() {
app.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function(id) {
if (window.device.platform === "iOS"){
interceptor.initialize(config.moodleURL, false);
} else {
interceptor.initialize();
}
}
};
example.html: https://gist.github.com/anonymous/28a78ab0879878d7a9dac8eb89544cda
I've been trying to use observers for a while now, but it seems like I cannot get them to work. I put the observe function in different modules of my extension, and also different parts of my code. Registering it from everywhere but it seems like every way that I tried was just a deadened. I can't get it to work. My goal is to listen for when a user exits from Firefox so I can clear preferences objects of my addon. As of now my observer is in bootstrap.js, and this is how I implemented it. I implemented my observe function this way because it was mentioned in this stackoverflow post that this is the right way to observe for quit-application notification. On a side note observers registered gets printed in console log but "oh observing" doesn't.
function myObserver()
{
this.register();
}
myObserver.prototype = {
observe: function(subject, topic, data) {
console.log("oh observing!!");
if (topic == "app-startup" || topic == "profile-after-change") {
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.addObserver(this, "quit-application", false);
}
else if (topic == "quit-application-requested" || topic == "quit-application")
{
console.log("browser closing");
alert('hello');
myextension.Utils.prefService.clearUserPref("questionType");
myextension.Utils.prefService.clearUserPref("clickThrough");
this.unregister();
}
},
register: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.addObserver(this, "quit-application-requested",false);
observerService.addObserver(this, "quit-application",false);
observerService.addObserver(this, "app-startup", false);
observerService.addObserver(this, "profile-after-change", false);
console.log("observers registered");
},
unregister: function() {
var observerService = Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
observerService.removeObserver(this, "quit-application-requested");
console.log("unregistering obs");
}
}
This is my startup function:
function startup(data, reason) {
Components.utils.import("chrome://ext/content/commons.jsm");
let wm = Cc["#mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
let windows = wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
let domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
WindowListener.setupBrowserUI(domWindow);
}
// Wait for any new browser windows to open
wm.addListener(WindowListener);
}
and this is my setupBrowserUI function in which I register the observer:
setupBrowserUI: function(domWindow) {
extension.onLoad(domWindow.gBrowser);
observer = new myObserver();
}
The easy way:
https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Services.jsm
let observer = {
observe: function() {
dump("oh observing")
}
};
function startup(data, reason)
{
Services.obs.addObserver(observer, "*", false);
observer.observe();
}
My suggest is create a log file with the preferences; to output dump calls instead to a file, set browser.dom.window.dump.file to the file destination where the log should be created and restart the application.
https://developer.mozilla.org/en-US/docs/Mozilla/Preferences/Preference_reference/browser.dom.window.dump.file
I'm the maker of an addon called BeautifyTumblr which changes the apperance of Tumblr.
I wish for my Chrome extension to automatically detect when it has been updated and display changelog to the user. I use an event page with the chrome.runtime.onInstalled.addListener hook to detect when an update has occured, retrieve the changelog from a text file in the extension.. this all works fine, then when I want to forward it to my content script via chrome.tabs.sendmessage it just wont work, nothing ever happens, no errors no nothing. I'm stumped.
Any help would be much appreciated!
Event Page:
chrome.runtime.onInstalled.addListener(function (details) {
"use strict";
if (details.reason === "install") {
} else if (details.reason === "update") {
var thisVersion = chrome.runtime.getManifest().version, xmlDom, xmlhttp;
xmlDom = null;
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", chrome.extension.getURL("changelog.txt"), false);
xmlhttp.send(null);
xmlDom = xmlhttp.responseText;
chrome.tabs.query({'url' : 'http://www.tumblr.com/*'}, function (tabs) {
if (tabs.length > 0) {
var mTab = tabs[0].id;
chrome.tabs.update(mTab, {active: true});
setTimeout(chrome.tabs.sendMessage(mTab, {beautifyTumblrUpdate: xmlDom}), 500);
} else {
chrome.tabs.create({'url' : 'http://www.tumblr.com/dashboard'}, function (tab) {
setTimeout(chrome.tabs.sendMessage(tab.id, {beautifyTumblrUpdate: xmlDom}), 500);
});
}
});
}
});
Relevant code in Content Script:
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
"use strict";
window.alert('test');
if (request.beautifyTumblrUpdate) {
window.alert(request.beautifyTumblrUpdate);
} else if (request.beautifyTumblrInstall) {
window.alert(request.beautifyTumblrInstall);
}
}
);
I am also seeing the same thing. I am not a 100% sure but I think this happens because chrome shuts off connection between background page and "old" content scripts the moment the extension is updated. There's more info here in this bug : https://code.google.com/p/chromium/issues/detail?id=168263
simple, use the following code in background,
chrome.runtime.onInstalled.addListener(function(details){
if(details.reason == "install"){
chrome.tabs.create({ url: chrome.extension.getURL('welcome.html')});
}
});