Firefox Extension keeps running in background - javascript

I have created a Firefox extension, which has iframe in the popup.html.
To pass messages between iframe and main.js, I'm using postMessage method.
The popup is behaving weird when receiving message. I used console.log to get the message which is being received. The message gets console.log that many times, the times extension was clicked.
For e.g. if I had open the extension 4 times, the iframe passes the message only once, but the message gets receied 4 times.
To make you understand I'm writing step by step process:
Open a tab, and click on extension.
A message is passed from iframe to the main.js, which after receiving message, console.logs the same message. Now this message appears once.
Click anywhere to close extension. Click on extension again > message is passed > console.logs the same message twice.
Repeat this process, and it logs the message those many times, the extension is clicked.
Is this a bug with Firefox? Or I'm doing something wrong?
EDITED:
Here is some snippet from my main.js:
if (self.port !== undefined){
self.port.on("show", function(a,b) {
myApp.initialize(a,b);
});
}
var myApp = {
initialize: function (a,b){
window.addEventListener ("message" , receiveMessage, false);
function receiveMessage(event){
console.log("event.data - - - - - - ",event.data);
}
},
goAbc : function(){
self.port.emit("close");
}
}
The code in iframe is:
$(document).ready(function(){
parent.postMessage("getData", "*");
});
EDITED: One more question:
If I'm calling "myApp.goAbc()" somewhere in the code, it says, self.port is undefined. What's the issue here? Should I use something else in place of self.port?

With each "show", you call myApp.initialize, which addEventListener a new event listener. So the first time, there is one, the next time there will be another, additional one (as you call addEventListener again) for a total of two, and so on.
Instead, you need to call addEventListener exactly once and not on each "show".

Related

Asynchronously call faceapi.detectAllFaces()

I am using face-api.js to detect faces in a given image. Everything is configured as mentioned on Github and detection is working.
But I want to call faceapi.detectAllFaces() asynchronously, I means I don't want to wait for its result, so I can't call await faceapi.detectAllFaces(). I tried below code:
In cam.js
async function detectFace()
{
document.getElementById('camPic').src = getCurrentImageAsBase64(); //getCurrentImageAsBase64() gets the image in base64 format from canvas
return faceapi.detectAllFaces(document.getElementById('camPic'), new faceapi.SsdMobilenetv1Options());
}
In index.jsp
$('#camPrcd').click(function(e)
{
e.preventDefault();
detectFace().then((arr) => console.log(arr));
console.log('detection called');
});
After button click, on console I can see message "detection called" and after sometime detection result gets logged from then() block.
But my observation is when detectFace() is called the html page feels like hanged (not able to click on any button) and when arr gets printed on console then I can able to click on page.
Looks like even though "detection called" message gets printed immediately before detection happens but faceapi.detectAllFaces() is not doing work asynchronously.
Note: This happens only for first call of faceapi.detectAllFaces() as per author of face-api.js during first call model for face detection get compiled and so detection time is more at first call as compare to subsequent call to function.
So is there any way that, I can call for detection and still web page is accessible and when it's finished a callback function will handle the detection result.

window.onbeforeunload: not assigned unless I set a breakpoint

I am attempting to set a fairly generic OnBeforeUnload handler:
console.log("WCW - Setting browser warning message");
window.onbeforeunload = function(e) {
e.returnValue = "confirmationMessage";
return e.returnValue;
};
console.log("WCW - onbeforeunload is " +
((window.onbeforeunload ? "set":"still null")));
I understand all I can do is signal the browser to issue a fairly generic warning. In a future iteration I may attempt some self-cleanup before issuing the return.
My problem is that window.onbeforeunload always returns null in the console log after this code runs UNLESS I set a breakpoint on any line (e.g., the first log message) and then just 'continue' when it stops. THEN, it works.
I'm quite sure a "what is wrong" question is pointless, so I'm asking, "do you have any advice on how I can look for what might be the problem?".
I wonder if it's a scope issue? The 2nd log message always says onbeforeunload is non-null... But window is a global, isn't it, and how would a debugger pause fix that?
NOTES:
jQuery is available but using $(window).on('beforeunload' is subject to the same issues as this code
adding a delay (setTimeout) to set the handler does not help; tried 2, 4 & 9 seconds
adding a recursive call to add the handler every 4 seconds while the page is open does not result in the handler being set: window.onbeforeunload returns NULL in the console all the time
periodically, I've seen a jQuery core method attached to the event, but it's rare

Chrome window onunload event

I'm trying to execute the following code
window.onunload = function () {
var sTag = document.createElement('script');
sTag.src = 'mysrc';
document.getElementsByTagName('head')[0].appendChild(sTag);
return false; };
}
Itseems to work fine in FF but in chrome I'm getting the download status as cancelled as soon as the unload event is fired. I saw some posts in SO with ajax solutions but I'm executing this script inside a cross domain iframe. Im just trying to log the time for which my api was live in a page per visitor. So, I'm sending some time log information on unload of the page. Is there any work around for the above?
For the purpose of what you described, you can have that script loaded in your page or parent window (you are saying it is an iframe right?) and run a function on window.unload:
window.onunload = function(){
window.top.logtime(); // if it is in the parent, or
window.logtime() //if it is in the same window
};
and don't return false, unload event cannot be cancelled. (in best cases, the user gets an alert dialog that will override the return false statement.)
I think what makes this different is how fast it carries out a new function, before the body gets unloaded. Manipulating the DOM is definitely much slower than making a call.

IE9 not running javascript onload

For some reason, IE9 is not running my JavaScript code onload when the browser is launched for the first time that session. It seems to only run onload after the user refreshes the page. It will also run the JavaScript when the debug console is open.
How do I make it so the JavaScript runs onload after the browser is open? Is this just a bug of IE9?
I'll restate this so you understand: The code DOESN'T run if you go to the site after launching a new browser session. The code DOES run if you open the site in a new tab, or reload the page, or open the debug console
Here is the function I use to run my script onload (which works fine in NORMAL browsers):
(function (i) {
var u = navigator.userAgent;
var e = /*#cc_on!#*/
false;
var st = setTimeout;
if (/webkit/i.test(u)) {
st(function () {
var dr = document.readyState;
if (dr == "loaded" || dr == "complete") {
i()
} else {
st(arguments.callee, 10);
}
}, 10);
} else if ((/mozilla/i.test(u) && !/(compati)/.test(u)) || (/opera/i.test(u))) {
document.addEventListener("DOMContentLoaded", i, false);
} else if (e) {
(function () {
var t = document.createElement('doc:rdy');
try {
t.doScroll('left');
i();
t = null;
} catch (e) {
st(arguments.callee, 0);
}
})();
} else {
window.onload = i;
}
})(init); //init is the function to call onload
I had the exact same issue that you had. I had a set of images that I wanted to ensure were preloaded before I began starting a slideshow. I was making use of
$(window).load(function(){
//All my code
});
And this is exactly what I was facing.
When I copied and pasted the URL in IE, the onload event did not seem to fire.
If I open the console using F12 and then past the URL in the browser and pressed enter, the everything seemed to be working.
Now that I opened the console at least once,
If I closeed the console and then reloaded the page, the onload was firing.
If I typed the URL and then pressed enter, the onload was firing.
It took me a couple of days to actually figure out what I was doing wrong.
The issue was with the console.log statements. At a lot of places in my code, I had done a lot of console logging. Even one of the plugins that I was using - jplayer has a an uncommented console message somewhere in the code.
The issue was that, unless you open the console at least once in IE, the console object is not available. Which means that the code will fail at the first console.log that it encounters.
Now, I was in no mood to comment out all my console.log statements just for the sake of testing it in IE. So, this is what I did instead. Right at the top of my document.ready jquery function, I wrote this small snippet of code.
if(!window.console){
console={};
console.log = function(){};
}
What it basically does is creates a dummy console.log function placeholder so that the code can run in IE but it will work only as long as console.log is the only console function that you are making use of in your code or in your plugins.
Just my 2 cents. Been pulling my hair over this issue for longer than I care to admit. I hope this is useful to at least someone.
You need to figure out if the code doesn't run at all, I.e. never enters your function, or if it fails on some specific line inside your function. Does IE9 show any warnings or js errors?
The easiest thing to do is stick a bunch of alert() statements in the code to see where it stops and narrow down to that line.
If it never enters your function then you need to look higher, where the call is being made.
Just a small note; When you use any debugging keywords (like console.log) or anything related, IE9 will escape this JS function if and only if the debugger is not on (with F12)
Actually I don't know what else cause a problem, but for me, my problem was the word "console.log" while debugger not on in IE9 ... I know this is already an answered question, but I felt it needs to be be known.
Okay, I figured it out. It has to do with some weird way IE handles IF statements.
In my init function I had two IF statements, one which checked if a variable existed and then logged the value of that variable. The other which checked to see if the value of the same variable was equal to an arbitrary string.
After removing the first IF statement, everything seems to work properly. I also decided to use a different onload function which can be seen below:
if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', init, true);
} else if (document.all && !window.opera){ //Crude test for IE
//Define a "blank" external JavaScript tag
document.write('<script type="text/javascript" id="contentloadtag" defer="defer" src="javascript:void(0)"><\/script>');
var contentloadtag=document.getElementById("contentloadtag");
contentloadtag.onreadystatechange=function(){
if (this.readyState=="complete") {
init();
//ie('open');
}
}
}

How can I capture a click on the browser page without any possible effect on the site's robustness?

My javascript code is added to random websites. I would like to be able to report to my server when a (specific) link/button on the a website is clicked. However I want to do it without any possible interruption to the website execution under any circumstances (such as error in my code, or my server id down etc.). In other words I want the site to do its default action regardless of my code.
The simple way to do it is adding event listener to the click event, calling the server synchronously to make sure the call is registered and then to execute the click. But I don't want my site and code to be able to cause the click not to complete.
Any other ideas on how to do that?
As long as you don't return false; inside your callback and your AJAX is asynchronous I don't think you'll have any problems with your links not working.
$("a.track").mousedown(function(){ $.post("/tools/track.php") })
I would also suggest you encapsulating this whole logyc inside a try{} catch() block so that any errors encauntered will not prevent the normal click behaviour to continue.
Perhaps something like this? I haven't tested it so it may contain some typo's but the idea is the same...
<script type="text/javascript">
function mylinkwasclicked(id){
try{
//this function is called asynchronously
setTimeOut('handlingfunctionname('+id+');',10);
}catch(e){
//on whatever error occured nothing was interrupted
}
//always return true to allow the execution of the link
return true;
}
</script>
then your link could look like this:
<a id="linkidentifier" href="somelink.html" onclick="mylinkwasclicked(5)" >click me!</a>
or you could add the onclick dynamically:
<script type="text/javascript">
var link = document.getElementById('linkidentifier');
link.onclick=function(){mylinkwasclicked(5);};
</script>
Attach this function:
(new Image()).src = 'http://example.com/track?url=' + escape(this.href)
+ '&' + Math.random();
It is asynchronous (the 'pseudo image' is loaded in the background)
It can be cross domain (unlike ajax)
It uses the most basic Javascript functionalities
It can, however, miss some clicks, due to site unloading before the image request is done.
The click should be processed normally.
1) If your javascript code has an error, the page might show an error icon in the status bar but it will continue the processing, it won't hang.
2) If your ajax request is asynchronous, the page will make that request and process the click simultaneously. If your server was down and the ajax request happening in the background timed out, it won't cause the click event to not get processed.
If you do the request to your server synchronously, you'll block the execution of the original event handler until the response is received, if you do it asynchronously, the original behaviour of the link or button may be doing a form post or changing the url of the document, which will interrupt your asynchronous request.
Delay the page exit just long enough to ping your server url
function link_clicked(el)
{
try {
var img = new Image();
img.src = 'http://you?url=' + escape(el.href) + '&rand=' + math.random();
window.onbeforeunload = wait;
}catch(e){}
return true;
}
function wait()
{
for (var a=0; a<100000000; a++){}
// do not return anything or a message window will appear
}
so what we've done is add a small delay to the page exit to give the outbound ping enough time to register. You could also just call wait() in the click handler but that would add an unnecessary delay to links that don't exit the page. Set the delay to whatever gives good results without slowing down the user noticeably. Anything more than a second would be rude but a second is a long time for a request roundtrip that returns no data. Just make sure your server doesn't need any longer to process the request or simply dump to a log and process that later.

Categories