I'm trying to write an extension to Firefox that would allow me to access internal functions/classes/objects of it from my webpage. I want them to be visible and accesible in DOM. It worked when extension was loaded as a component from chrome.manifest file but it doesn't seem that it's possible in e10s (multiprocess Firefox) anymore.
So I was trying and trying and the best option I have found so far seems to be using exportFunction, createObjectIn and cloneInto functions. They work fine when expected to make objects visible from pages loaded by the extension itself but not from remote ones.
I'm using Addon-SDK now and my code is
And then
function injectTest(event) {
let domWindow = event.subject;
//This creates and object that is always visible but never accesible from page not loaded by the extension
foo = Cu.createObjectIn(domWindow.wrappedJSObject, {defineAs: "testSDK"});
//This exports my function fine but I can export it only into an existing object
//That's why I'm using "crypto" here
Cu.exportFunction(test.bind(this, domWindow),
domWindow.crypto.wrappedJSObject,
{ defineAs: "test" });
//This exports my function to my object but only on pages loaded by the extension
Cu.exportFunction(test.bind(this, domWindow),
foo,
{ defineAs: "test2" });
//Same here, cloned_var seems to be not accesible from remote webpage
var to_be_cloned = {"greet" : "hey"};
foo.cloned_var = Cu.cloneInto(to_be_cloned, foo);
}
exports.main = function(options, callbacks) {
if (!gInitialized &&
(options.loadReason == "startup" ||
options.loadReason == "install" ||
options.loadReason == "enable")) {
log("initializing - " + options.loadReason);
try {
events.on("content-document-global-created", injectTest);
} catch (error) {
log(error);
}
gInitialized = true;
}
};
I'm totally new to javascript and Firefox extensions so I have no idea how to make it work. What I'm doing wrong? Is there any better idea to access extension's objects?
Thank you in advance for help.
#edit 19.05.15
Tried using page-mod. It does work but not as well as I need.
main.js file
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
include: "mywebsite",
contentScriptFile: [data.url("cscript.js")],
contentScript: 'window.alert("Page matches ruleset");'
});
cscript.js file (in data folder)
var contentScriptObject = {
"greeting" : "hello from add-on",
b: 1,
powitaj: function(){
return(this.greeting);
}, //when called from console returns "hello from add-on"
is_b: function(){
if(b){
return true;
}else{
return false;
}
}, //undefined
is_thisb: function(){
if(this.b){
return true;
}else{
return false;
}
}, //returns 1
func: function(){
console.log("ok")
}, //returns "ok"
is_func: function(){
func();
}, //undefined
is_thisfunc:function(){
this.func();
} //undefined
};
So from my website I can access inner variables (actually variables defined globally too and modify them as well), I can access inner functions (not outer - not included in the code) but my inner functions cannot call each other and I'd like to be able to do that.
To run chrome-privileged code in a e10s-content process you'll need framescripts
The SDK has some wrapper modules to simplify the communication and module loading between parent and child process
If you only need exportFunction/cloneInto/createObjectIn then using the page-mod module may be sufficient, if i recall correctly those helpers are made available in its context.
Related
I would like to use WebAssembly within a web worker.
From my main application, I launch it like this:
let w = new Worker('test.js');
w.onmessage = (event) => { console.log(event); };
w.onerror = (event) => { console.error(event); };
w.postMessage({ message: "Hello World" });
Then, I created a file test.js as follows:
self.Module = {
locateFile: function (s) {
console.log(s);
return s;
}
};
self.importScripts("main.js");
// note: `main.js` is the JavaScript glue file created by emcc
self.onmessage = function(messageEvent) {
console.log(messageEvent); // works!
console.log(self.Module); // works!
console.log(self.Module.ccall("test")); // crashes!
}
I get an error: Uncaught TypeError: Cannot read property 'apply' of undefined. I don't understand why self.Module is undefined, how is that possible?
I have the feeling there is something about the scope of the web worker and WebAssembly that does not work well together.
Thanks for your input!
The problem is that console.log() does not reveal the true state of the object at execution time. Further digging revealed that in fact the object Module was not ready yet.
I cite from: https://kripken.github.io/emscripten-site/docs/getting_started/FAQ.html
How can I tell when the page is fully loaded and it is safe to call compiled functions?
Calling a compiled function before a page has fully loaded can result
in an error, if the function relies on files that may not be present
[...]
Another option is to define an
onRuntimeInitialized function:
Module['onRuntimeInitialized'] = function() { ... };
That method will be called when the runtime is ready and it is ok for you to call compiled code.
Adjusting my test.js (worker) file fixes the issue:
self.Module = {
locateFile: function (s) {
console.log(s);
return s;
}
// Add this function
onRuntimeInitialized: function() {
test();
}
};
self.importScripts("main.js");
// note: `main.js` is the JavaScript glue file created by emcc
self.data = {};
// to pass data from the main JS file
self.onmessage = function(messageEvent) {
console.log(messageEvent); // works!
self.data = messageEvent; // save the data
}
// gets executed when everything is ready.
self.test = function() {
// we may safely use self.data and self.Module now!
console.log(self.Module.ccall("test")); // works!
}
if i have the below code , how can i change the isHTML property at any time while the application running ,i have tried the below and tried many javascript access ways and it fails also.
obj = new ss({
something: {
ishtml: myfunction(true),
},
});
document.getElementbyId("#id").onclick = function() {
myfunction(false);
}
function myfunction(bool) {
return bool;
}
after all of that when i use the application again it uses the intial values i send via the function
I am a total beginner at dojo and am trying to move some of my interface code into a class just to keep the methods out of my main file.
My problem - I am unable to use internal class functions as part of other functions.
After I create an interface object in an external file as shown, I am able to sucessfully:
appInterface = new (interface)
appInterface.showGraphWindow()
appInterface.hideGraphWindow()
However I am unable to work out how to use these functions inside of the toggleGraphWindow function. (Due to context ?)
If I attempt to call:
on(registry.byId("graphBtn"),"click", appInterface.toggleGraphWindow);
It crashes on the line:
this.showGraphWindow()
or
this.hideGraphWindow()
With: "Undefined is a not a function"
How do I code the toggleGraphWindow function?
Iterface.js
define([
"dojo/_base/declare",
"dojo/on",
"dijit/registry"
],
function(
declare,
on,
registry
){
return declare (null, {
hideGraphWindow : function () {
dijit.byId("graphWindowMain").domNode.style.display = 'none';
dijit.byId("applicationWindow").resize();
},
showGraphWindow : function () {
dijit.byId("graphWindowMain").domNode.style.display = 'block';
dijit.byId("applicationWindow").resize();
},
toggleGraphWindow : function (){
if (dijit.byId("graphBtn").checked == true)
{this.showGraphWindow()}
else
{this.hideGraphWindow()}
}
});
});
What's wrong with
toggleGraphWindow : function (){
if (dijit.byId("graphBtn").checked == true) {
this.showGraphWindow();
}
else {
this.hideGraphWindow();
}
}
?
Thanks to you both, you were indeed correct Ken, I had read this similar post a lot of times, and somehow didnt understand the answer within:
Calling object methods internally in dojo
After reading what you have posted, I have somehow understood the answer linked above and now understand what my problem was! Thanks to all.
I fixed it by altering my code in the main application as follows:
var appInterface = new Interface();
on(registry.byId("graphBtn"),"click", appInterface.toggleGraphWindow);
changed to:
var appInterface = new Interface();
var graphToggle = dojo.hitch(appInterface, "toggleGraphWindow");
on(registry.byId("graphBtn"),"click", graphToggle);
I believe the reason for the error, was that the "this" object at runtime, was actually the "graphBtn" instead of the appInterface.
I am very new to JavaScript, and when working with my object's prototype I try to call the current object to extend a method but it is not working. So I google'd my problem but didn't really get anywhere as it is practically impossible to phrase. However, I found the this keyword which I thought should work but didn't. Here's what I have:
(function( window, document, undefined ) {
var myObj = function ( ) { }; // not a noop
var ua = function() { return navigator.userAgent.toLowerCase(); }
function noop() { }; // empty noop function
myObj.prototype = {
constructor: myObj,
renderizr: {
presto: ua().match(/(opera|presto)/i),
trident: ua().match(/trident/i), // don't parse "msie" as opera uses this sometimes
webkit: ua().match(/(chrome|safari|webkit)/i),
gecko: ua().match(/(firefox|gecko)/i), // don't parse "netscape" as a lot of strings use this
val: '' // keep empty for now
}
};
// renderizr.val extension
// use this so the user can print the value of
// the rendering engine instead of using multiple
// conditional statements.
if(this.renderizr.presto) { this.renderizr.val = "Presto" }
else if(this.renderizr.trident) { this.renderizr.val = "Trident") }
else if(this.renderizr.webkit) { this.renderizr.val = "Webkit") }
else if(this.renderizr.gecko) { this.renderizr.val = "Gecko") }
window.myObj = new myObj();
}( window, document ));
This way, you can do alert(myObj.renderizr.val); instead of doing monotonous conditional statements.
I don't want to do generic browser name detection because you're only supposed to test for the features which you need, not the browser. However, some rendering engines have different habits for rendering web pages, so I do want to include engine detection in my script. (However, I don't suggest using this, like I said, I just want to get to know javascript and how it works, and it's not working!).
So my question is, what am I doing wrong here and how can I fix it? Why doesn't the this keyword work?
You are using this in a context where you are not in the instance of a myObj object. this will be the global scope (ie. window).
Also, all your code is running immediately, you are not defining any functions in your prototype.
I believe you want those checks inside your constructor:
var myObj = function () {
// renderizr.val extension
// use this so the user can print the value of
// the rendering engine instead of using multiple
// conditional statements.
if(this.renderizr.presto) { this.renderizr.val = "Presto" }
else if(this.renderizr.trident) { this.renderizr.val = "Trident" }
else if(this.renderizr.webkit) { this.renderizr.val = "Webkit" }
else if(this.renderizr.gecko) { this.renderizr.val = "Gecko" }
};
Also, you have some extra ) inside your else if statements, causing syntax errors. Check a working version here: http://jsfiddle.net/SnKSB/.
I have and external JS scripts file with all my objects in that runs once the document is ready something like this...
jQuery(function($) {
var Main = {
run: function () {
myFunction.setup();
}
}
var myFunction = {
setup: function() {
//Do some stuff here
}
}
Main.run();
});
I want to be able to run myFunction.setup() only if im on a certain page though otherwise I get errors if that method is looking for elements on the page that don't exist e.g a slideshow, menus etc.
At the moment I have got round this by checking if the element exists with .length and if it does then running the rest of the method but I was wondering if there was a nicer way? Maybe like if it was possible to send variables to the scripts file when it loads based on the page im on so it knows what to methods run?
Any help would be really appreciated.
Thanks
Giles
Paul Irish has a great way of doing exactly this, using ID and classes from the body tag to execute certain blocks of code:
http://paulirish.com/2009/markup-based-unobtrusive-comprehensive-dom-ready-execution/
This kind of thing might help:
Page specific
var page_config = {
setup_allowed: true
// ... more config
};
Generic
var Main,
myFunction;
(function ($, _config) {
myFunction = (function () {
var _public = {};
if (_config.setup_allowed === true) {
_public.setup = function () {
};
}
return _public;
})();
Main = (function () {
var _public = {};
if (typeof myFunction.setup !== "undefined") {
_public.run = function () {
myFunction.setup();
};
// Run it as we had Main.run() before
_public.run();
}
return _public;
})();
})(jQuery, page_config);
This way Main.run() and myFunction.setup() are only available if specified in page_config.
Here's a working example you can have a play with. This may be a bit verbose for your particular requirement but hopefully it'll help in some way :-)