Last active
August 29, 2015 14:07
-
-
Save lkuper/3672f5f49f431f90e912 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Components.utils.import('resource://gre/modules/Services.jsm'); | |
// Code that listens for a custom DOM event. This is how we | |
// implement communication between unprivileged (web page) and | |
// privileged (extension) JS code. | |
function load(win) { | |
let document = win.document; | |
document.addEventListener("TestExtensionCustomEvent", function(e) { | |
win.alert("Hello from privileged code! Event received!"); | |
}, false, true); | |
} | |
function unload(win) { | |
let document = win.document; | |
document.removeEventListener("TestExtensionCustomEvent", arguments.callee, false); | |
} | |
// Listener to make sure that stuff happens in future windows. Not to | |
// be confused with our custom event listener, above. | |
var listener = { | |
onOpenWindow: function(aWindow) { | |
// Wait for the window to finish loading | |
let win = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowInternal); | |
win.addEventListener("UIReady", function(aEvent) { | |
win.removeEventListener(aEvent.name, arguments.callee, false); | |
load(win); | |
}, false); | |
}, | |
// Unused: | |
onCloseWindow: function(aWindow) { }, | |
onWindowTitleChange: function(aWindow, aTitle) { } | |
}; | |
function startup(data, reason) { | |
// Load in existing windows. | |
let enumerator = Services.wm.getEnumerator("navigator:browser"); | |
while(enumerator.hasMoreElements()) { | |
let win = enumerator.getNext(); | |
load(win); | |
} | |
// Load in future windows. | |
Services.wm.addListener(listener); | |
} | |
function shutdown(data, reason) { | |
Services.wm.removeListener(listener); | |
if (reason == APP_SHUTDOWN) | |
return; | |
let enumerator = Services.wm.getEnumerator("navigator:browser"); | |
while(enumerator.hasMoreElements()) { | |
let win = enumerator.getNext(); | |
unload(win); | |
} | |
} | |
function install(data, reason) { | |
} | |
function uninstall(data, reason) { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0"?> | |
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> | |
<Description about="urn:mozilla:install-manifest"> | |
<!-- This is the extension ID. It has to be in the format of an | |
email address, but it need not actually be an email address! | |
--> | |
<em:id>test-extension@example.com</em:id> | |
<em:version>0.1</em:version> | |
<em:name>Test Extension</em:name> | |
<em:description> | |
An example extension for test purposes. | |
</em:description> | |
<em:creator>Lindsey Kuper</em:creator> | |
<em:unpack>true</em:unpack> | |
<em:type>2</em:type> | |
<em:targetApplication> | |
<Description> | |
<!-- Firefox's application ID. --> | |
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> | |
<!-- I have no idea what the correct minimum version is. 1.5 is a guess. --> | |
<em:minVersion>1.5</em:minVersion> | |
<!-- 32 is the current release of Firefox, as of today. --> | |
<em:maxVersion>32.*</em:maxVersion> | |
</Description> | |
</em:targetApplication> | |
<!-- Mark this extension as restartless. --> | |
<em:bootstrap>true</em:bootstrap> | |
</Description> | |
</RDF> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> | |
<title>Extension test page</title> | |
<script type="text/javascript"> | |
function run() { | |
alert("Hello from unprivileged code!"); | |
var element = document.createElement("TestExtensionCustomElement"); | |
// If we wanted to pass arguments, we could do so here by setting | |
// attributes on a custom element, as described in | |
// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages | |
document.documentElement.appendChild(element); | |
var evt = document.createEvent("Events"); | |
evt.initEvent("TestExtensionCustomEvent", true, false); | |
element.dispatchEvent(evt); | |
} | |
</script> | |
</head> | |
<body> | |
<div><button type="button" onclick="run();">Click me</button></div> | |
</body> | |
</html> |
You can't access document
inside of your startup
function because it isn't running in any particular window. Instead, you can use the window manager service to run a function in all current and future browser windows (example).
This is different from a XUL overlay-based add-on, which is automatically loaded once per browser window.
@mbrubeck Thanks, that makes sense. Here's a stab at doing it that way, but I'm getting the same results as before. Any idea what might be going wrong?
Cu.import('resource://gre/modules/Services.jsm');
// Code that listens for a custom DOM event. This is how we
// implement communication between unprivileged (web page) and
// privileged (extension) JS code.
function load(win) {
let document = win.document;
document.addEventListener("TestExtensionCustomEvent", function(e) {
alert("Hello from privileged code! Event received!");
}, false);
}
function unload(win) {
let document = win.document;
document.removeEventListener("TestExtensionCustomEvent", arguments.callee, false);
}
// Listener to make sure that stuff happens in future windows. Not to
// be confused with our custom event listener, above.
var listener = {
onOpenWindow: function(aWindow) {
// Wait for the window to finish loading
let win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal);
win.addEventListener("UIReady", function(aEvent) {
win.removeEventListener(aEvent.name, arguments.callee, false);
load(win);
}, false);
},
// Unused:
onCloseWindow: function(aWindow) { },
onWindowTitleChange: function(aWindow, aTitle) { }
};
function startup(data, reason) {
// Load in existing windows.
let enumerator = Services.wm.getEnumerator("navigator:browser");
while(enumerator.hasMoreElements()) {
let win = enumerator.getNext();
load(win);
}
// Load in future windows.
Services.wm.addListener(listener);
}
function shutdown(data, reason) {
Services.wm.removeListener(listener);
if (reason == APP_SHUTDOWN)
return;
let enumerator = Services.wm.getEnumerator("navigator:browser");
while(enumerator.hasMoreElements()) {
let win = enumerator.getNext();
unload(win);
}
}
function install(data, reason) {
}
function uninstall(data, reason) {
}
If there's a problem there, I haven't managed to spot it yet...
Got it working with @mbrubeck's help and updated the gist! The problems with the version in my comment above:
- can't use
Cu
andCi
, have to spell outComponents.utils
andComponents.interfaces
alert()
by itself won't work here- and, most importantly, I forgot the extra
true
argument toaddEventListener
that makes it listen for events coming from unprivileged web page code.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Who knows things about restartless Firefox extensions and wants to help me out?
What I'm trying to do is implement communication between a web page and the extension using something like the trick described on https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages . However, although that seemed to work fine when I had a traditional, non-restartless extension that used a XUL overlay, it doesn't seem to work anymore. What I see when I click the button on testpage.html is the "Hello from unprivileged code!" alert, followed by nothing. The startup() function doesn't actually seem to run at all. No errors show up in the browser console. Anyone know what's up? Is there someplace other than startup() where I should be creating the event listener?