I have a page with multiple flash objects which are written by a third party and thus can't be changed. They call a JS function but don't seem to pass any identifying parameters. Is there any way to determine inside the function which flash object called it?
This may not be cross-browser compatible, and in the end you may find only that "Flash" is calling the function, rather than a specific movie, but this is the only way I can think of:
function myFunction() {
if (myFunction.caller) {
console.log("This function's caller is " + myFunction.caller);
}
else {
console.log("This function was called directly");
}
/* rest of function */
}
This should run in Firefox and will log to the console.
Unfortunately the only information a function gets from the place that called it is whatever parameters are passed in with the call.
Related
What I want looks like this:
function bindFunctions(bindFunction, callbackFunction) {
// Add binding so that I can call the callbackFunction if the bindFunction is called
}
function log(message) {
console.log(message);
}
function notifyUser() {
alert('Something');
}
bindFunctions(log, notifyUser);
log('Error'); // Now the notifyUser-functions should be called and "Something" printed to the alert-box
bindFunctions($('.element').click, function() {/* CODE */}); // Or this: but I don't know if this is even possible because this is not the event-function but the binding-function of the click-event
Important: I have no influence on the bindFunction so it's not possible to implement a trigger there.
It's an attachment of a callback on any kind of existing function. Do you know how or if this is possible?
I believe you're looking at it the wrong way. What you need is some good old dependency inversion. Whatever code needs log has to receive it from a higher-level component (e.g. the composition root of your application). You're then free to implement a straightforward wrapper that calls notifyUser and inject it instead of the actual log.
I've linked some articles taking an OO perspective, but feel free to translate to a more functional model (the approaches are equivalent). In your case, you're using closures (which are, under a certain light, "equivalent" to objects with a single anonymous method).
The way you have to do to add a callback to a function is this:
var foo = function(number, callback){
number += 2;
callback(number);
}
foo(2, function(result){
window.alert(result)
});
https://jsfiddle.net/6dpz88md/
Good luck
When trying this simple code:
function create_folder(name, parent_ID) {
var BM_folder = "";
chrome.bookmarks.create({title : name, parent_id : parent_ID }, function (new_folder) {
BM_folder = new_folder;
});
console.log("create folder in id : " + BM_folder.id);
return BM_folder.id;
}
I get undefined as output, but when I debug it works fine and I get the real bookmark ID. I have similar problems in more functions, I guess it's the same problem.
EDIT #1: fixed the vars, my real function has full strings, I simply can't post that way.
EDIT #2: thanks Marco Bonelli, is there a way to turn this into sync, so that I'll be able to use normal oop?
There are several problems in your code:
First of all, that function cannot work... you're using a hypen (-), and variable/function names cannot contain hypens in JavaScript, so change it in something else, maybe create_folder or createFolder. That's the same for your variable BM-folder, and parent-ID. Call them BMFolder and parentID.
Secondly, you are creating the object to pass to chrome.bookmarks.create() in the wrong way: parent-ID is both wrong and undefined. You should do: chrome.bookmarks.create({title: name, parentID: parentid}).
Inside your function, you're calling the chrome.bookmarks.create() method, which is asynchronous: this means that the code is processed separately from the body of your function, and when the method has finished working, it will call the callback function, which you provide as second argument. Basically when calling chrome.bookmarks.create() you have to wait until it's finished to continue, because if you try to access the BMfolder.id variable before the callback gets called it will obviously be undefined.
Now, to summarize what I said above, I'll show the right code for to achieve you're trying to:
function createFolder(name, parentid) {
chrome.bookmarks.create({title: name, parentID: parentid }, function (newFolder) {
console.log("Created the folder with ID: " + newFolder.id);
goOn(newFolder);
});
}
function goOn(BMFolder) {
console.log('Here is the folder: ', BMFolder);
// do something...
}
You cannot use return BMFolder.id, because your function is asynchronous, so the only thing you can do to know that the bookmark folder has been created is to call another function to continue. For example, you can name it goOn().
EDIT:
Is there a way to turn this into sync, so that I'll be able to use normal oop?
Unfortunately you cannot turn an asynchronous function into a synchronous one. Chrome extensions' methods are only asynchronous, therefore you have to work on that. By the way, working asynchronously is much more efficient than working synchronously, and you should get used to this programming style, because (as said before) Chrome extensions only work asynchronously, and so do many other JS frameworks and APIs.
Ok hopefully this come across correctly. I am building a universal javascript function that will build a menu and then also build the functions that each menu item would call. To do this, I need to pass a list of the commands to be called for each option.
So for example:
var thecall = 'alert("hi, this works");';
function myfunction(thecall)
{
//In here I want to excute whatever commands is listed in variable thecall
.....
}
I'm sure doing it this way is completely stupid, but I don't know how else to do this.
Basically, I need my function to perform other functions on a variable basis.
Thanks!!
I made it a bit fancier to show you how you can use it.
var thecall = function(name){alert("hi " + name + ", this works");};
function myFunction(function_ref)
{
function_ref('Mark');
}
myFunction(thecall);
You can execute arbitrary strings of JavaScript using eval(), but that is not the best solution for you here (it's almost never the best solution).
Functions in JavaScript are themselves objects which means you can store multiple references to the same function in multiple variables, or pass function references as parameters, etc. So:
var thecall = function() {
alert("hi, this works");
};
function myfunction(someFunc) {
someFunc(); // call the function that was passed
}
myfunction(thecall); // pass reference to thecall
Note that when passing the reference to the thecall function there are no parentheses, i.e., you say thecall not thecall(): if you said myfunction(thecall()) that would immediately call thecall and pass whatever it returned to myfunction. Without the parentheses it passes a reference to thecall that can then be executed from within myfunction.
In your case where you are talking about a list of menu items where each item should call a particular function you can do something like this:
var menuItems = [];
function addMenuItem(menuText, menuFunction) {
menuItems.push({ "menuText" : menuText, "menuFunction" : menuFunction });
}
function test1() {
// do something
}
addMenuItem("Test 1", test1);
addMenuItem("Test 2", function() { alert("Menu 2"); });
// and to actually call the function associated with a menu item:
menuItems[1].menuFunction();
Notice the second menu item I'm adding has an anonymous function defined right at the point where it is passed as a parameter to addMenuItem().
(Obviously this is an oversimplified example, but I hope you can see how it would work for your real requirement.)
I think your looking for the eval function.
var code= 'alert("hi, this works");';
eval(code);
I want to call a Javascript function from Flash, which I can do with ExternalInterface, but the Javascript function takes a callback. Is there a way to give it a Flash callback?
I've thought of something like this:
ExternalInterface.addCallback("foo", function(){...});
ExternalInterface.call("theFunction", "foo");
But that wouldn't work since theFunction would attempt to do foo(), while it should really do swfObject.foo(). The problem is the page and its Javascript are not under my control (though I can request changes if really needed).
This is closely related to the first question in the related questions section.
Along the same lines as the answer to that question, you can do:
ExternalInterface.addCallback("foo", function() { /* ... */ }); // The callback
ExternalInterface.call("theFunction(function() { swfObject.foo(); })");
You're misunderstanding the documentation, I think. callback in this instance is just a reference to a function inside Flash, not a callback to something you call.
Basically, you use .call() to call a JS function from AS; and you use .addCallback() to tell the Flash Player which AS function should be called based on the name.
On your example, theFunction would get one parameter as being 'foo', which is the name that references your anonymous AS function. Not sure why you would want to pass the function like that, but if you need, you could just call it from JavaScript with
function theFunction(callback) {
// .. do something...
swfObject[callback]();
}
Now, if you don't have control over the JS/HTML side, I'm not sure if you can do that. Not sure why you'd need, anyway - JS calls are synchronous, as if they were running on the same thread, meaning the Flash Player will execute the JS code and only then return to the Flash Player... you don't have to wait for execution or anything.
Also, if you really need to control the page without touching the JS/HTML side, remember you can inject entire pieces of JS code via .call - it doesn't need to be a simple function call. You can create your entire functions from inside the SWF. For example,
var js:XML = <script><![CDATA[
// Javascript code...
]]></script>;
ExternalInterface.call(js);
Or, if you need the return data, you don't need a callback either - just do a simple call as in
// JS
function isNumberZero(__num) {
return __num == 0;
}
// AS
trace ("Is number zero = " + ExternalInterface.call("isNumberZero", 10));
Not sure if this helps at all. If not, it'd be good to have more information on what exactly you're trying to do.
I'm just curious if it's possible that Flash objects can access the DOM of the document that has embedded it.
Yes, through the ExternalInterface class.
You can make calls to Javascript from within the Flash movie and get back any public information about the page that your heart desires.
Addendum
Looking at this a year and a half later, i decided to add some examples:
Say you have a JS function on your client page like this:
function foo(bar,type) {
// do something with bar and type
}
You call it from Flash (using AS3) like so:
ExternalInterface.call(foo, bar, type);
Note that the function name is the first object and the arguments are listed sequentially thereafter.
To expose a method of the Flash movie to outside Javascript, you would do this in your Flash or Flex (again, AS3):
application1_applicationCompleteHandler(event:Event) {
// the app has finished loading, so do whatever we
// have to do on load, plus add that callback
ExternalInterface.addCallback(foo, bar);
}
public function bar(arg1, arg2) : void {
// do something with arg1 and arg2
}
In the Javascript on the page you invoke it like this (where myMovie is the ID of the SWF):
myMovie.foo(anArg, anotherArg);
In the addCallback method, the first argument is the external name of the function, and the second argument is the closure that will get called.
Yes.
An example: http://livedocs.adobe.com/flex/3/html/help.html?content=ProgrammingHTMLAndJavaScript_07.html
Not that I know of, but they can execute javascript in the containing document, which obviously can then access the DOM itself.