I need to be able to make an event such that every time a user loads a new page and closes firefox, I need it to call a method in my C# application that takes care of maintaining the user model. I know for sure I need to create some type of firefox extension where I use javascript to check such an event. However, I have no idea how I am going to integrate my C# application with the firefox extension. Can someone provide me with some guidance?
I'll help you out with the parts of the question that I'm familiar with (Javascript based add-ons), and offer some suggestions for the other parts. Here goes nothing!
Add-ons
Firefox add-ons easily provide the tools you need to detect page loads and opening / closing firefox.
To detect page loads you can register a listener to the DOMContentLoaded event in window.
window.addEventListener("DOMContentLoaded", function(event){
var url = event.originalTarget.location.href;
alert("Oh yeah, a document is loading: " + url);
}, false);
Alternatively, you can register a nsIWebProgressListener to listen for location changes. This probably closer to what you want, since DOMContentLoaded is also triggered for iframes.
var listener = {
//unimplemented methods (just give functions which do nothing)
onLocationChange: function(aWebProgress, aRequest, aLocation){
var url = aLocation.asciiSpec;
alert("Oh yeah, a the location changed: " + url);
}
};
gBrowser.addTabsProgressListener(listener);
To detect firefox open / close you need to first understand how firefox add-ons work with respect to multiple windows. When a new window of firefox is launched, you basically have 2 separate copies of your code running. So, if you care about firefox windows being opened and closed you can simply do:
window.addEventListener("load", function(event){
alert("Looks like you just opened up a new window");
}, false);
window.addEventListener("unload", function(event){
alert("Awh, you closed a window");
}, false);
But, most likely you want to detect opening / closing firefox as an entire application. This is achieved using a code-sharing mechanism called Javascript Modules. Javascript modules are loaded just once for the lifetime of the application. So, they enable you to share information between windows. Simply counting the number of windows opened and closed should be sufficient for this functionality.
var EXPORTED_SYMBOLS = ["windowOpened", "windowClosed"];
var windowsOpened = 0;
function windowOpened(){
if( windowsOpened === 0) {
alert("The first window has been opened!");
}
windowsOpened++;
}
function windowClosed(){
windowsOpened++;
if( windowsOpened === 0) {
alert("The last window has been closed!");
}
}
Then you can simply attach the aforementioned event handlers to call these 2 methods from their corresponding load and unload events.
So, this is all great and everything, but now you have to twiddle with the details of getting a baseline Firefox add-on setup. Fortunately, Mozilla has provided a handy Addon Builder to ease this. All the code about (except the Javascript module) should be placed in the ff-overlay.js file (assuming you use the linked builder).
C# communication
I'm a little less knowledgeable about the interprocess communication with C#. However, maybe I can point you in the right direction and let the smart people at SO fill in the rest.
I believe COM Objects are a method of communication between processes on Windows. So, you could build in a Binary Component to your add-on to perform the communication. However, as far as I understand it, setting up binary components is much more difficult than a standard javascript-based add-on. Either way, Mozilla provides a guide for setting it up in Visual Studio.
If you want to stay away from binary components you are left with the javascript enabled components of the SDK. This includes socket communication, files, pipes, a sqlite database etc. This SO question addresses exactly the question you're asking. If it were me, I would choose them in this order.
Sqlite Database
Named Pipes
Sockets
(1) because there is a lot of code samples available for this, and would be easy to implement on both sides. (2) because this would be the way I'd implement IPC if I were given full control of both sides of the application. (3) is last because I hate that crap (maybe I'm biased from Distributed Systems in college).
tl;dr
The page load stuff should be pretty simple. Check out the Addon Builder to get going with a FF addon, and here to see about detecting page loads.
The C# communication is doable, and addressed in this SO Question. I'd do it with a sqlite database for ease if it were me.
Related
Well here's a problem.
I've got a website with large javascript backend. This backend talks to a server over a socket with a socket bridge using http://blog.deconcept.com/swfobject/
The socket "bridge" is a Flex/Flash .swf application/executable/plugin/thing for which the source is missing.
I've got to change it.
More facts:
file appExePluginThing.swf
appExePluginThing.swf Macromedia Flash data (compressed), version 9
I've used https://www.free-decompiler.com/flash/ to decompile the .swf file and I think I've sorted out what's the original code vs the libraries and things Flash/Flex built into it.
I've used FDT (the free version) to rebuild the decompiled code into MYappExePluginThing.swf so I can run it with the javascript code and see what happens.
I'm here because what happens isn't good. Basically, my javascript code (MYjavascript.js) gets to the point where it does
window.log("init()");
var so = new SWFObject("flash/MYappExePluginThing.swf"", socketObjectId, "0", "0", "9", "#FFFFFF");
window.log("init() created MYappExecPluginThing!!!");
so.addParam("allowScriptAccess", "always");
log("init() added Param!!");
so.write(elId);
log("init() wrote!");
IE9's console (yeah, you read that right) shows
init()
created MYappExecPluginThing!!!
init() added Param!!
init() wrote!
but none of the debugging i've got in MYappExePluginThing.as displays and nothing else happens.
I'm trying to figure out what I've screwed up/what's going on? Is MYappExePluginThing.as running? Is it waiting on something? Did it fail? Why aren't the log messages in MYappExePluginThing.as showing up?
The first most obvious thing is I'm using FDT which, I suspect, was not used to build the original. Is there some kind of magic "build javascript accessible swf thing" in FlashBuilder or some other IDE?
First noteworthy thing I find is:
file MYappExePluginThing.swf
MYappExePluginThing.swf Macromedia Flash data (compressed), version 14
I'm using Flex 4.6 which, for all I know, may have a completely different mechanism for allowing javascript communication than was used in appExePluginThing.swf
Does anyone know if that's true?
For example, when FDT runs this thing (I can compile but FDT does not create a .swf unless i run it) I get a warning in the following method:
private function init() : void
{
Log.log("console.log", "MYappExePluginThing init()");
//var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
try
{
ExternalInterface.addCallback("method1Callback",method1);
ExternalInterface.addCallback("method2Callback",method2);
ExternalInterface.call(initCallback);
}
catch(err:Error)
{
Log.log("console.log", "MYappExePluginThing init() ERROR err="+err);
}
}
I got a warning that Application.application was deprecated and I should change:
var initCallback:String = Application.application.parameters.initCallback?Application.application.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
to:
var initCallback:String = FlexGlobals.topLevelApplication.parameters.initCallback?FlexGlobals.topLevelApplication.parameters.initCallback:"MYjavascript.MYappExePluginThing_init";
which I did but which had no effect on making the thing work.
(FYI Log.log() is something I added:
public class Log{
public static function log(dest:String, mssg:String):void{
if(ExternalInterface.available){
try{
ExternalInterface.call(dest, mssg);
}
catch(se:SecurityError){
}
catch(e:Error){
}
}
trace(mssg);
}
}
)
Additionally, in MYjavascript.js MYappExePluginThing_init looks like this:
this.MYappExePluginThing_init = function () {
log("MYjavascript.js - MYappExePluginThing_init:");
};
Its supposed to be executed when MYappExePluginThing finishes initializing itself.
Except its not. The message is NOT displaying on the console.
Unfortunately, I cannot find any references explaining how you allow javascript communication in Flex 4.6 so I can check if I've got this structured correctly.
Is it a built in kind of thing all Flex/Flash apps can do? Is my swf getting accessed? Is it having some kind of error? Is it unable to communicate back to my javascript?
Does anyone have any links to references?
If this was YOUR problem, what would you do next?
(Not a full solution but I ran out of room in the comment section.)
To answer your basic question, there's nothing special you should need to do to allow AS3-to-JS communication beyond what you've shown. However, you may have sandbox security issues on localhost; to avoid problems, set your SWFs as local-trusted (right-click Flash Player > Global Settings > Advanced > Trusted Location Settings). I'm guessing this not your problem, though, because you'd normally get a sandbox violation error.
More likely IMO is that something is broken due to decompilation and recompilation. SWFs aren't meant to do that, it's basically a hack made mostly possible due to SWF being an open format.
What I suggest is that you debug your running SWF. Using break-points and stepping through the code you should be able to narrow down where things are going wrong. You can also more easily see any errors your SWF is throwing.
Not really an answer, but an idea to get you started is to start logging everything on the Flash side to see where the breakage is.
Since you're using IE, I recommend getting the Debug flash player, installing it, then running Vizzy along side to show your traces.
Should give you a good idea of where the app is breaking down.
Vizzy
Debug Player
Goal: making a standalone modular JavaScript debuggin-utility (includes custom dom and event manipulation methods) to be used in the console (preferably Chrome) on any random sites of interests (with no backend access).
Usage: initially include module script directly via copy-paste to console or by creating a new script element pointing at myhomepage.com/shortandeasytoremember.js and call methods on the namespace from there on.
Problem: how to best make it persistent throughout the session on that webpage (so that I wouldn't need to reinclude it after every refresh) ?
Note: any additional browser compatibility is not required - as long as it works in the latest Chrome, it's all fine by me (but any effort in the compatibility department is always much appreciated for the sake of others). IF YOU READ THIS IN A FAR FUTURE and by then there exists a better solution than what is written down below, please take a moment to contribute with your superior knowledge.
What I currently have is an event listener on window.unload to save any state data to localStorage and a string to make it easier to reinclude the module after page reload using eval(localStorage.getItem('loadMyNS'));.
(function(ns, undefined){
'use strict';
//util methods on ns and few monkey patches for debugging ...
var store = 'if(!window.MyNS){' +
'var xyz9=document.createElement("script");' +
'xyz9.src="http://myhomepage.com/shortandeasytoremember.js";' +
'document.head.appendChild(xyz9);}';
localStorage.setItem('loadMyNS', store);
ns.save = function () {
// and use localStorage for some more data
// to be used by other methods after page reload
};
window.addEventListener('unload', ns.save, false);
}(window.MyNS = window.MyNS || {}));
(browsers with no localStorage or addEventListener may benifit from this article)
I've also concidered using the same schema with window.name instead of localStorage (as long as this still seems legid) just because writing eval(window.name) would take less typing ^^.
The trouble (one of them) I have with the "eval-script-tag-inclusion" is on the sites which block external non-https script sources. An ideal solution would be a globally accessible module which would live with state and methods included (and no initialization required after refresh) at least until I close the the window (or overwrite the ref ofc).
If that is currently absolutely not possible, a lesser solution yet still superior to my current code would suffice.
I'd like to run some external JavaScript with a time restriction, so that if it takes more than N seconds it will be stopped.
Some browsers, e.g. Firefox, already do this with a dialog that asks if you want to allow a script to keep running. However, I'm looking for a bit more:
I want to set my own time limit rather than use the browser's default (e.g., I believe Chrome's is much longer than Firefox's).
I want to be able to do this on a per-script basis, not per-page. One page may contain multiple scripts that I want to restrict in this way (hence my idea to use <iframe> elements).
I was thinking it would be very convenient if there were simply an attribute I could attach to an <iframe>—e.g., something like js-time-limit="5000" (I just made that up)—but I haven't been able to find anything like that.
Is this possible? To put a configurable time limit on JavaScript execution in a browser?
If the iframe is doing computation work and doesn't need to access the DOM, then use web workers: https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers
Here is also a library that can abstract away the hard parts for you! http://adambom.github.io/parallel.js
Important parts:
Dedicated Web Workers provide a simple means for web content to run scripts in background threads.
If you need to immediately terminate a running worker, you can do so by calling the worker's terminate() method: myWorker.terminate();
Browser compatibility
Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
3 3.5 (1.9.1) 10 10.60 4
For posterity: my original goal was to allow users of a website to submit JS code and run it in the background with a time limit so that, e.g., infinite loops don't wreak havoc on the CPU.
I created a library called Lemming.js using the approach Joe suggested. You use it like this:
var lemming = new Lemming('code to eval');
lemming.onTimeout(function() {
alert('Timed out!');
});
lemming.onResult(function(result) {
alert('Result: ' + result);
});
lemming.run({ timeout: 5000 });
You can check out the GitHub repo for more details.
I have a requirement where I need to communicate with native code to perform some operations. I have been successful by using JS-Ctypes and things are panning out as expected. Since the communication from my web application with the native code takes some time, thus blocking the main JS thread consequently freezing the UI.
Thus I need to create a separate thread to be delegated with the communication with the native code and post back results to the main thread which will give the appropriate feedback to the user. Firefox ChromeWorker are exactly what I need to use, since they are independent threads with access to JS-Ctypes.
My problem is that for the life of me, I can't seem to load a script using that approach. This is what I currently have:
main.js
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
Components.utils.import("resource://gre/modules/Services.jsm");
var worker = new ChromeWorker("js/fpman/myworker.js");
worker.onmessage = function(e){
console.log(e.data);
};
worker.postMessage('start');
myworker.js
self.onmessage = function(e){
var sum = 1 + 1;
postMessage("Sum is " + sum);
};
When that code runs in the main JS, I get this error on firebug console
Failed to load script: http://localhost:8080/myapp/js/fpman/myworker.js (nsresult = 0x805303f4)
Point to note, when I use a normal worker thread i.e
var worker = new Worker("js/fpman/myworker.js");
the js file (myworker.js) is loaded fine and I get the expected result, but of course that doesn't suffice my needs since a normal worker doesn't have access to JS-Ctypes. So it seems the problem is how am creating the ChromeWorker. Could someone please enlighten me on how to appropriately instantiate and use the ChromeWorker Object from an application. I have seen a lot of reference of usage of ChromeWorker in extensions, but that is not what I want, I want to use the ChromeWorker in my web application.
Thanks.
That particular error is NS_ERROR_DOM_BAD_URI
I don't believe what you are doing will work, and I know it won't work very soon in Firefox because enablePrivilege is going away completely.
I am using a JavaScript to track the activities of users on my page upon unloading that very page. Consider the following simplified dummie-script to simulate what I am doing on unload:
$(window).unload(function() {
$.get("http://www.google.de/images/srpr/logo3w.png");
});
The image URL in that case serves as a holder for tracking data.
The image is requested in some browsers (e.g. Firefox 3) and isn't loaded in others (e.g. Firefox 6) when closing the browser window.
Probably isn't the way it should be done; anyhow I would like to hold on to it as long as I could make a statement on how reliable the unload-event is.
Any experiences on this?
I have some experience with that and I would recommend a slightly different approach like this:
$(window).unload(function() {
new Image().src = "http://www.google.de/images/srpr/logo3w.png?timestamp="
+ new Date().getTime();
});
The challenge is that if you are making an AJAX-call at unload, you should use synchronous mode. With normal async-mode, it may not succeed at all (for instance in Chrome).
But in this case, a trick using image is just as reliable because the communication is one way only. That works for GET but if you need to POST something then sync-mode is the only option.