Catch 'open link from external link-call' event - google-chrome-extension

I'm searching for an event which triggers when an external Desktop-Software like Outlook, Thunderbird, Messenger App etc. want the default browser (firefox) to open a new link. I could manage with a workaround to catch this event if firefox was closed before:
// catch page when triggered by link and browser was closed
chrome.runtime.onStartup.addListener(function () {
// search for initial tab
chrome.tabs.query({
active: true,
currentWindow: true,
}, function (tabs) {
var initialTab = tabs[0];
// catch open of files and links when browser was closed
if (initialTab.url != 'chrome://newtab/') {
handleNewUrlRequest(initialTab.id,initialTab.url);
}
});
});
But how to catch the opening of an external link when firefox is already running?
Thank you for your help and greetings!

Thanks to #wOxxOm ill made it in this way:
// catch page when triggered by link and browser is already open (firefox) step 1
var lastRequest = null;
chrome.webNavigation.onCommitted.addListener(function (details) {
if(details.url == 'about:blank' && details.frameId == 0 && details.parentFrameId == -1 && details.transitionType == 'link') {
lastRequest = details;
}
});
// catch page when triggered by link and browser is already open (firefox) step 2
chrome.webNavigation.onBeforeNavigate.addListener(function (details) {
if(lastRequest && details.frameId == 0 && details.parentFrameId == -1 && details.tabId == lastRequest.tabId && details.windowId == lastRequest.windowId) {
console.log('New Request detected: open new Link in Firefox when Firefox is already open');
lastRequest = null;
}
});

Related

Chrome extension background script sometimes does not run after install or update

I have had recent reports of a chrome extension that I develop that stops working after an update or a fresh install. The background script seems to not start at all.
There is no response to messages sent to it from the content scripts.
There is no process for it in the task manager.
Opening background page from chrome://extensions does not show any activity in the console, or show any source files.
Profiling, memory snapshot buttons are disabled.
Once this issue appears, it persists for the chrome profile even after reloading or uninstalling/reinstalling the extension.
Restarting chrome resolves the problem.
The issue has been seen on chrome v79. But I cannot say for sure that it is exclusive to this version, as the issue is difficult to reproduce and seemingly random.
Has anyone seen such an issue, or has any ideas what to look for? I am happy to update my question with any new info I have or with any info you need.
Edit:
Here is my webNavigation listener, which is used to inject content scripts. This handler is wired up in the 'root' context of the background script (not asynchronously inside an event handler)
chrome.webNavigation.onCompleted.addListener((details) ⇒ {
if(details.frameId === 0) {
injectScript(
'js/contentScript.js',
details.tabId,
details.frameId,
details.url
).catch((e) ⇒ {});
}
}
The injectScript function is as follows
export const injectScript = ƒ (scriptPath,tab,frame,tabUrl) {
return new Promise((res,rej) ⇒ {
let options = {
file : scriptPath,
allFrames : false,
frameId : frame,
matchAboutBlank: false,
runAt : 'document_idle',
};
const cb = ƒ () {
if (chrome.runtime.lastError) {
let err = new Error('Could not inject script');
capture(err,{
...options,
tabUrl,
lastError : chrome.runtime.lastError.message,
});
rej(err);
}else{
res();
}
};
if (tabUrl.indexOf('.salesforce.com') !== -1) {
window.setTimeout(() => {
chrome.tabs.executeScript(tab,options,cb);
},500);
}else{
chrome.tabs.executeScript(tab,options,cb);
}
});
};
Note above, the capture function reports the error to a backend and I cannot see it being reported there as well. Cannot add a breakpoint in code because no source appears in the background page, as noted above.
A background service worker is loaded when it is needed, and unloaded when it goes idle.
https://developer.chrome.com/docs/extensions/mv3/service_workers/
You can use the following methods:
// Keep heartbeat
let heartTimer;
const keepAlive = () => {
heartTimer && clearTimeout(heartTimer);
heartTimer = setTimeout(() => {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
console.info('[heartbeat]')
tabs.length && chrome.tabs.sendMessage(
tabs[0].id,
{ action: "heartbeat" }
);
});
keepAlive();
}, 10000);
};
keepAlive();

Correct way of sending updates from Content Script to Popup

I have an extension that has content_script, background_page and page_action with popup.
So, popup has several controls, when user presses on control the popup should send a command to start work. Content script starts work, and should send an updates to popup.
The problem is that I'm not sure I implemented updates part properly.
Content script:
function notifyProgress(thing) {
console.log('Notify progress');
chrome.runtime.sendMessage({req: 'Progress', thing: thing});
}
Background page:
var channel;
chrome.runtime.onConnect.addListener(function (port) {
if (port.name == 'service-channel') {
channel = port;
port.onMessage.addListener(function (msg) {
console.log('Background received event', msg);
...
});
}
});
...
chrome.runtime.onMessage.addListener(function (msg, sender, callback) {
console.log('On message in background', msg);
if (msg.req == '...') {
...
} else if (msg.req == 'Progress') {
console.log('Got Progress for ' + sender.tab.id);
channel.postMessage(msg);
}
});
Popup:
var channel = chrome.extension.connect({name: 'service-channel'});
channel.onMessage.addListener(function (message) {
if (message.req == '...') {
...
} else if (message.req == 'Progress') {
updateListener(message.req, {thing: message.thing}); // updates UI
} else
console.log('Ignoring', message);
});
Also I have worries about multiple working content scripts sending Progress events.
Is there a simpler or better way of doing this?
Edit.
What is best practices of implementing Popup updates from Content Script?

Can I detect fullscreen in a Chrome extension?

I have a Chrome extension (specifically, a "content script") where I'd like to detect whether the page I am monitoring/changing is in fullscreen state. I have tried several APIs, as well as the "screenfull" library, but no luck so far. Any ideas?
Thanks for your help!
If you want to detect whether the page has used the Fullscreen API to enter fullscreen mode, just check document.webkitIsFullscreen.
If you want a general method to reliably detect full screen mode, the chrome.windows API is your only option. Since this API is unavailable to content scripts, you need to use the message passing API to interact with a background or event page.
Example: content script
function isFullScreen(callback) {
chrome.runtime.sendMessage('getScreenState', function(result) {
callback(result === 'fullscreen');
});
}
// Example: Whenever you want to know the state:
isFullScreen(function(isFullScreen) {
alert('Window is ' + (isFullScreen ? '' : 'not ') + 'in full screen mode.');
});
Example: background / event page
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if (message === 'getScreenState') {
chrome.windows.get(sender.tab.windowId, function(chromeWindow) {
// "normal", "minimized", "maximized" or "fullscreen"
sendResponse(chromeWindow.state);
});
return true; // Signifies that we want to use sendResponse asynchronously
}
});
You can try something like this:
var isFullScreen = (screen.width == window.outerWidth) && (screen.height == window.outerHeight);
if(isFullScreen) {
// ...
}
The simplest way is to listen for webkitfullscreenchange event, e.g
$(document).on('webkitfullscreenchange',function(){
if (document.webkitIsFullScreen === true) {
console.log('Full screen mode is on");
} else {
console.log('Full screen mode is off");
}
});

chrome extension connection issues

I have written an extension for google chrome and I have a bug I need a help solving.
what I do is using either a text selection or an input of text search for photos on flickr and then create a results tab.
The extension works most of the times. but sometimes it creates a blank tab with no results and when I repeat the same search it then shows results. I figured that it's something to do with the html files messaging maybe something to do with them communicating. I have to say that I always receive the results from flickr so that the request/responce with flickr works ok. Sometimes the error happens when I play with other tabs or do something on other tabs while waiting for results. can you please help me figure out where's the fault?
the background file:
function searchSelection(info,tab){
var updated;
if(info.selectionText==null){
var value = prompt("Search Flickr", "Type in the value to search");
updated=makeNewString(value);
}
else{
updated=makeNewString(info.selectionText);
}
var resultHtml;
var xhReq = new XMLHttpRequest();
xhReq.open(
"GET",
"http://api.flickr.com/services/rest/?method=flickr.photos.search&text="+updated+
"&api_key=a0a60c4e0ed00af8d70800b0987cae70&content_type=7&sort=relevance&per_page=500",
true);
xhReq.onreadystatechange = function () {
if (xhReq.readyState == 4) {
if (xhReq.status == 200) {
chrome.tabs.executeScript(tab.id, {code:"document.body.style.cursor='auto';"});
var photos = xhReq.responseXML.getElementsByTagName("photo");
if(photos.length==0){
alert("No results found for this selection");
chrome.tabs.executeScript(tab.id, {code:"document.body.style.cursor='auto';"});
return;
}
var myJSPhotos=[];
for(var i=0; i<photos.length; i++){
var data={"id":photos[i].getAttribute("id"),"owner":photos[i].getAttribute("owner"),
"secret":photos[i].getAttribute("secret"),"server":photos[i].getAttribute("server"),
"farm":photos[i].getAttribute("farm"),"title":photos[i].getAttribute("title")};
myJSPhotos[i]=data;
}
chrome.tabs.create({"url":"results.html"},function(thistab){
var port= chrome.tabs.connect(thistab.id);
port.postMessage({photos:myJSPhotos});
});
}
};
};
xhReq.send(null);
chrome.tabs.executeScript(tab.id, {code:"document.body.style.cursor='wait';"});
}
var context="selection";
var id = chrome.contextMenus.create({"title": "search Flickr", "contexts":[context,'page'],"onclick":searchSelection});
results html: has only a reference to the js file res.js
res.js :
chrome.extension.onConnect.addListener(function(port) {
port.onMessage.addListener(function(msg) {
//*****//
var photos=msg.photos;
createPage(photos);
});
});
I have to mention that when the tab is empty if I put alert on the //*****// part it won't
fire.
but when I print out the photos.length at the tab create call back function part it prints out the correct result.
Try to set "run_at":"document_start" option for your res.js in the manifest.
I think callback from chrome.tabs.create is fired right away without waiting for page scripts to be loaded, so you might try something like this instead:
//global vars
var createdTabId = null;
var myJSPhotos = null;
xhReq.onreadystatechange = function () {
//assign myJSPhotos to a global var
chrome.tabs.create({"url":"results.html"},function(thistab){
createdTabId = thistab.id;
});
}
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "complete" && tab.id == createdTabId) {
createdTabId = null;
//now page is loaded and content scripts injected
var port = chrome.tabs.connect(tab.id);
port.postMessage({photos:myJSPhotos});
}
});

window.onbeforeunload not working in chrome

This is the code which i used for window.onbeforeunload
<head>
<script>
window.onbeforeunload = func;
function func()
{
var request = new XMLHttpRequest();
request.open("POST", "exit.php", true);
request.onreadystatechange = stateChanged;
request.send(null);
}
function stateChanged()
{
if (request.readyState == 4 || request.readyState == "complete")
alert("Succes!");
}
</script>
</head>
this works with IE and Mozilla but does not work with Chrome..... please help......
thanks in advance.....
It seems that the only thing you can do with onbeforeunload in recent version of Chrome is to set the warning message.
window.onbeforeunload = function () {
return "Are you sure";
};
Will work. Other code in the function seems to be ignored by Chrome
UPDATE: As of Chrome V51, the returned string will be ignored and a default message shown instead.
Know I'm late to this, but was scratching my head why my custom beforeunload message wasn't working in Chrome and was reading this. So in case anyone else does the same, Chrome from Version 51 onwards no longer supports custom messages on beforeunload. Apparently it's because the feature has been misused by various scams. Instead you get a predefined Chrome message which may or may not suit your purposes. More details at:
https://developers.google.com/web/updates/2016/04/chrome-51-deprecations?hl=en#remove-custom-messages-in-onbeforeload-dialogs
Personally do not think the message they've chosen is a great one as it mentions leaving the site and one of the most common legitimate uses for onbeforeunload is for dirty flag processing/checking on a web form so it's not a great wording as a lot of the time the user will still be on your site, just have clicked the cancel or reload button by mistake.
You should try this:
window.onbeforeunload = function(e) {
e.returnValue = 'onbeforeunload';
return 'onbeforeunload';
};
This works on latest Chrome. We had the same issue the e.returnValue with value of onbeforeunload solved my problem.
Your code should be like this:
<head>
<script>
window.onbeforeunload = function(e) {
e.returnValue = 'onbeforeunload';
func();
return ''onbeforeunload'';
};
function func()
{
var request = new XMLHttpRequest();
request.open("POST", "exit.php", true);
request.onreadystatechange = stateChanged;
request.send(null);
}
function stateChanged()
{
if (request.readyState == 4 || request.readyState == "complete")
alert("Succes!");
}
</script>
</head>
Confirmed this behavior on chrome 21.0.1180.79
this seems to work with the same restritions as XSS, if you are refreshing the page or open a page on same domain+port the the script is executed, otherwise it will only be executed if you are returning a string (or similar) and a dialog will be shown asking the user if he wants to leans or stay in the page.
this is an incredible stupid thing to do, because onunload/onbeforeunload are not only used to ask/prevent page changes.
In my case i was using it too save some changes done during page edition and i dont want to prevent the user from changing the page (at least chrome should respect a returning true or change the page without the asking if the return is not a string), script running time restrictions would be enought.
This is specially annoying in chrome because onblur event is not sent to editing elements when unloading a page, chrome simply igores the curent page and jumps to another. So the only change of saving the changes was the unload process and it now can't be done without the STUPID question if the user wants to change it... of course he wants and I didnt want to prevent that...
hope chrome resolves this in a more elegant way soon.
Try this, it worked for me:
window.onbeforeunload = function(event) {
event.returnValue = "Write something clever here..";
};
Try this. I've tried it and it works. Interesting but the Succes message doesn`t need confirmation like the other message.
window.onbeforeunload = function()
{
if ( window.XMLHttpRequest )
{
console.log("before"); //alert("before");
var request = new XMLHttpRequest();
request.open("POST", "exit.php", true);
request.onreadystatechange = function () {
if ( request.readyState == 4 && request.status == 200 )
{
console.log("Succes!"); //alert("Succes!");
}
};
request.send();
}
}
None of the above worked for me. I was sending a message from the content script -> background script in the before unload event function. What did work was when I set persistent to true (in fact you can just remove the line altogether) in the manifest:
"background": {
"scripts": [
"background.js"
],
"persistent": true
},
The logic is explained at this SO question here.
Current versions of Chrome require setting the event's returnValue property. Simply returning a string from the event handler won't trigger the alert.
addEventListener('beforeunload', function(event) {
event.returnValue = 'You have unsaved changes.';
});
I'm running Chrome on MacOS High Sierra and have an Angular 6 project whithin I handle the window.beforeunload an window.onbeforeunload events. You can do that, it's worked for me :
handleUnload(event) {
// Chrome
event.returnValue = true;
}
It show me an error when I try to put a string in event.returnValue, it want a boolean.
Don't know if it allows custom messages to display on the browser.
<script type="text/javascript">
window.addEventListener("beforeunload", function(e) {
e.preventDefault(); // firefox
e.returnValue = ''; // Chrome
});
</script>

Resources