I have written a NPAPI plugin that implements all the logic required and now I am writing an extension that is expected to use the functionality provided in the plugin. This architecture provides me an opportunity to write the same C++ code for both Mozilla Firefox and Google Chrome.
In Chrome I instantiate the object that is defined in the plugin by writing an <embed ...> construction to the separate document that is owned by my extension (it is provided automagically to my Chrome plugin). That just works. In C++ code I perform all the works required in the constructor of my plugin object.
I can't easily adapt my solution to use it in Firefox because the extension is not backed by any separate document and my extension doesn't have permissions to write to any of already rendered documents.
My main question in the most common form is how can I use the functionality provided by the plugin many times and passing an arguments list to my native function on user clicks the button or selects my entry in the drop-down menu (i.e. the method with arguments should be invoked after the specific event, not just at arbitrary time)?
"Supplementary" questions are:
How can I instantiate a plugin in Mozilla Firefox? Where can I get a document that will be "interpreted" by FF and such that the extension will be able to write to it?
I don't know how to do that myself, but here is an open source firefox extension that does it: https://github.com/kylehuff/webpg-firefox
Your Firefox extension needs to make use of a "browser overlay". There are many types of overlays, for various parts of the browser, and they are loaded (overlay'ed) within the specified document, as defined in the chrome.manifest file.
For example, the following applies an overlay to the "browser.xul" file (which is the main browser window)
overlay chrome://browser/content/browser.xul content/firefoxOverlay.xul
Now, within that overlay file you can load your plugin object and call the methods provided by the plugin.
Here is an example XUL file which does nothing more than load the NPAPI plugin of the content-type "application/x-example-plugin", and assign the plugin object to the variable "myPlugin"
<script type="text/javascript">
myPlugin = document.getElementById("myPlugin");
</script>
<?xml version="1.0" encoding="UTF-8"?>
<overlay id="myOverlay" xmlns:html="http://www.w3.org/1999/xhtml" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript">
myPlugin = document.getElementById("myPlugin");
alert(myPlugin.someFunction());
</scrpit>
<window id="main-window">
<vbox collapsed="true">
<html:object id="myPlugin" type="application/x-example-plugin" height="1" width="1" style="visibility:hidden;"></html:object>
</vbox>
</window>
</overlay>
Some important things to note
The "xmlns:html=..." declaration is critical, because the plugin object is being loaded in an html:object, and that declaration tells the XUL parser how to render the object.
The id of the window ("main-window") is important, because that is how the XUL parser will overlay the item (within the "main" window)
The object id ("myPlugin", in this example) is how you will reference the plugin object in via the JavaScript later.
Because we are not showing content with our plugin, merely calling public methods provided by it, it is important to make the CSS visibility has "hidden", and the size to 1x1 pixels. Without doing this, you could end up with large blank spaces rendered in the browser UI. Additionally, it is important to use the CSS "visibility" property, not the "display" property. If you set the display property to "none", you will have issues with your plugin actually being initialized within the overlay.
In your extension install.rdf file, you must specify the "unpack" property as "true", i.e.: <em:unpack>true</em:unpack>
Once your overlay is loaded within the context of the browser XUL, and your plugin initialized within the main browser window, you can reference your plugin from within the scope of the main window by the variable you have assigned it to ("myPlugin" in this example).
I will not go into depth here on how to obtain the context of the main window (see the links below), but you once you have a reference you can invoke the exposed methods from within content scripts, sidebars, toolbars, etc.
Reference links -
XUL Overlays
Install manifests (chrome.manifest)
Working with windows in chrome code
Interaction between privileged and non-privileged pages
Source files for one of my Firefox extensions using an NPAPI plugin
Related
I am trying to develop a firefox extension that adds a panel allowing the user to interact with the DOM of any webpage. I'd like to reuse web components that I've already built. The web components are built using libraries like jquery, angular, d3, and a bunch of others, most of which don't play nice with XUL. To deal with that, I'm including a browser element that contains a web page with my components.
<overlay id="testOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox id="browser">
<splitter></splitter>
<vbox flex="1">
<browser
src="chrome://testApp/content/index.html"
type="content"
flex="1"/>
</vbox>
</hbox>
</overlay>
This works, and shows my index.html in a panel to the side as expected. However, I cannot figure out how to debug any scripts that are included on the index.html page. The documentation for debugging extensions seems very sparse.
So the question I have is: how can I point the firefox debugger at the browser element in the pane that I've created.
Follow the instructions here for enabling the browser (as opposed to content) debugger: https://developer.mozilla.org/en-US/docs/Debugging_JavaScript#JavaScript_Debugger
Once your scripts are loaded in the browser, they should become visible in the debugger's sources pane (but not before that).
If you still can't get that to work, I would love a test case and detailed steps to reproduce, so I could try and diagnose the problem :)
I have made a custom control (round button with a fixed image) and tested that it works. However, I would like to reuse this particular control in other projects and hence thought of making a class library out of it. However, when I try to get the custom control to show in my other applications, the icons does not show even though the button responds to clicks.
I have tried to build the icon in the class library projects as Content and Resources and test but to no avail. (of course, I change the addressing of the icon in the code when I updated its build icon). At the moment, i have decided to leave the icon /icons/myimage.png to be built as Content. And, in the class library code (XAML), i am accessing it as "/icons/myimage.png".
So, would anyone have an idea on how I could get the round button to render properly in my projects? How should I build the class library project?
I would't make a graphics part of my class library, because most likely in the future you will need to customize it, so what I suggest is to make the following property in your custom module and set the image where you use it:
public ImageSource ButtonImage {get { return <button image>; } set { <set button image>; } }
I experimented a bit and found the solution. The idea is to use embedded resource to store the image in the dll. And then for loading it by the CustomControl, one can use constructs like this:
BitmapImage img = new BitmapImage();
img.SetSource(Assembly.GetExecutingAssembly().GetManifestResourceStream("MyLib.icons.my_icon.png"));
MyLib here is the name of the assembly for the class library. icons is the folder where the resource is kept in the assembly.
Have a pluggin that is installed as part of an app, the pluggin needs to use different overlays depending on what version of FF is being used as it modifies the interface.
I found https://developer.mozilla.org/en/Bundles to specify different files but this only seems to cover which OS/bitness.
Is there a way to specify that an overlay only applies to particular versions of the UI?
ie. This works for FF3.6 and earlier but breaks FF4
<overlay id="myOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<dialog id="commonDialog" onload="commonDialogOnLoad(); myLoad();"
ondialogaccept="myAccept(); return commonDialogOnAccept();">
This is aimed at the Domain Login and the FTP Login dialogs, so an idea on making it more specific could help too.
I haven't done this myself, but I think you can accomplish this effect using flags in your chrome.manifest file. See https://developer.mozilla.org/en/Chrome_Registration#Manifest_flags
Technically, the answer by MatrixFrog is correct, you can use flags in your chrome.manifest file. However, you better consider the fact that your code breaks Firefox 4 a warning - this approach should not be used, it is likely to break browser functionality. Also, what if a second extension tries to do the same thing? You should extend built-in functionality, not overwrite it. Your goal is apparently to run your own code when the common dialog loads. Please consider the following approach:
<overlay id="myOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="text/javascript"><![CDATA[
window.addEventListener("load", function()
{
// Your code here
}, false);
]]></script>
</overlay>
This solves two problems. For one, you no longer need to override the existing handler for the "load" event - addEventListener allows registering as many event handlers as you want, unlike onload attribute/property. The other problem: you were adding a function myLoad() to the global namespace of the common dialog. If Firefox code or some other extension decides to use the same function name in future there will be trouble. The code above completely avoids this problem by using an anonymous function - there can be no naming conflicts.
I have modified some code inside my Firefox. Just add on some extra functions for my isolation network. Besides that I also want to create my own FF extension for this particular purpose. I just need some information:
Can the code inside my Firefox, call any function Javascript declared in my extension?
Generally yes, but your question is not specific enough. Both Firefox and an extension can have JS and C code, code in XPCOM components, code running in a specific window, JS modules, etc.
Assuming the "Firefox code" is running in some window (e.g. you edit browser.js) and the "extension function" you want to call also exists in that window (e.g. you overlay chrome://browser/content/browser.xul, which is the URI of the main Firefox window, in which the browser.js code runs), you can just call it as you would normally do.
I understand that jQuery is the preferred Javascript framework for Firefox extensions, but I'm comfortable with Prototype and need to implement a simple Firefox extension.
Unfortunately, I'm having trouble invoking a Prototype method. Each method call is resulting in a no-op: there are no errors or other signs the method call occurred.
Here's the overlay code:
<overlay id="liteextension-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
This call to a Prototype method returns an empty array, even though there are divs in the page:
var all_divs = $$('div');
The "prototype.js" file lives in the same dir as the XUL file.
Using libraries like prototype and jquery inside a Firefox extension is a complicated thing. The problem is that the JQuery is not loaded in the same context when loaded from XUL than when loaded from a webpage. So if you are trying to manipulate stuff in a page, a library loaded in XUL will not see the page DOM where it expects it to be. With JQuery (not sure about prototype) you can solve this by pointing to the right context.
Second, importing libraries inside an extension in a browser.xul overlay will put all functions and variables defined in the library in the global namespace, potentially conflicting with other extensions and even the Firefox code. This could cause a big mess.
There is more information in this forum post, it is about JQuery, but the same problems apply... maybe the suggested solutions could be useful for you:
http://forums.mozillazine.org/viewtopic.php?f=19&t=1460255