my first time on here.
My problem is with AS3, Javascript and possibly the browsers Firefox and IE.
I have done so much searching for an answer so i will print my code:
i am using this line to call the flash application and in all browsers its combatible and actually traces in firebug to hold an OBJECT->FLASH_ID so thats not the problem.
var obj = document.getElementById('test');
then i use addcallback:
obj.sendStatus(loggedIn);
now whats weird is that i trace all individual elments in chrome and
-obj = flash object
-sendStatus = flash->function
-loggedIn = either false or true;
everything works great but when i am on firefox or ie
it traces differently
-obj = flash object
-sendStatus = undefined
-loggedIn = either true or false;
now what am i missing??????????
i tried embedding rather than object insertion
i made sure that the id's were all unique
i checked to make sure i had the right flash object selected with getElementById
im so confused.. and it feels like something simple.
I know about some browser - dependent timing problems, making the interface of the flash object available...
A timer could help, try this:
var obj = document.getElementById('test');
setTimeout(function(){obj.sendStatus(loggedIn);}, 500);
500 is a bit to long, but just to be sure. If it works you can try to lower it to 200 - 300.
make sure you declared allowScriptAccess = sameDomain both in embed tag and object tag
in case you don't use swfObject
Maybe the way you get a reference to the swf is wrong, try this
function thisMovie(movieName) {
if (navigator.appName.indexOf("Microsoft") != -1) {
return window[movieName];
} else {
return document[movieName];
}
}
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html
The problem is that using ExternalInterface requires both parties (browser and flash) to be ready.
You can have the flash poll a method in the page which just returns true so that you know its ready to receive calls from flash.
On the flip side if the page is cached, it can sometimes happen that the page wants to send to flash before flash is ready, so I use a callback to the page telling it flash is ready, so its like a handshake, once both parties are ready, then we can start sending data back and forth.
This has been my approach since Firefox 3.
Related
I have a classic asp project. In one of my pages i have to call a javascript function. That call does not have any problem and works fine on my test server (not localhost, just a server to test he project). But when i deploy it to the actual server, that function does not work. I call this function in onload event.
That function has this type of lines (i cannot write the whole code, because of the company that i work for, does not allow it)
document.getElementById("R6C2_1").style.display = 'block'
document.getElementById("R6C2_2").style.display = 'none'
....
When I try to debug it on IE10, i got "Unable to get property 'style' of undefined or null reference" error. After that, the elements in javascript function are not load. They are not seen on the page.
My main problem is, as i mentioned before differences between servers. I do not understand why it works on one server, but not on another server.
While it's not possible to determine the issue from this information alone, you should look into:
Whether the elements you're looking for actually exist when the code is invoked (use browser debug / breakpoints to look at the page the moment the code is invoked).
If they exist, check if they have the ID you expect (e.g R6C2_1) - if not, why? who creates these IDs? could be a server configuration issue.
Do a debug using the app from each server, and look at the page / DOM, see if there are differences or check if the code is invoked at different times.
These could lead you to pinpoint the issue. Good luck!
In case the elements just take time to be created, you can just wait until they are present:
function ExecuteWhenExists() {
var R6C2_1 = document.getElementById("R6C2_1");
var R6C2_2 = document.getElementById("R6C2_2");
if (R6C2_1 && R6C2_2) {
R6C2_1.style.display = 'block';
R6C2_2.style.display = 'none';
} else {
window.setTimeout(ExecuteWhenExists, 100);
}
}
ExecuteWhenExists();
This will not crash when the elements do not exist, and will just keep trying to execute in a non-blocking way (polling every 0.1 seconds) until they exist.
I have this tiny little script that I run inside Chrome using Tampermonkey and works great.
However, when I use it in Firefox with Greasemonkey, it shows up on the active list, meaning its matching the page but it doesn't actually execute the code. I know it has to be a simple something I am overlooking but its not hitting me.
var myVar=setInterval(function(){myTimer();},100);
function myStopFunction()
{
clearInterval(myVar);
}
function myTimer()
{
var p1 = "Login";
var p2 = "mode=login";
var x = document.body.innerHTML;
if (x.match(p1) && x.match(p2)){
document.documentURI = "/ucp.php?mode=login";
}
myStopFunction();
}
Script Logic/Function
I am using a timer to prevent the script from triggering over and over in a permanent loop.
It simply detects if I am logged into a phpBB forum or not, if not send me to the login page so I can log in.
I am using document URI so that the location of the original is preserved so upon login, it takes me right back to it.
Often phpBB when you log in, it will take you back to the index page so this preserves my original intent of going to the actual link.
This script works perfectly and as expected on Chrome using TM but on Firefox using GM it doesn't trigger, am I missing something here?
From the Firefox spec:
(document.documentURI)
Returns the document location as string. It is read-only per DOM4 specification.
And, indeed, the latest spec still specifies that this attribute must be read only.
If Chrome lets you write this property, then that is non-standard behavior and maybe a bug.
Use location.assign(), or location.replace(), or just programmatically click the login button -- which often preserves the target page.
I've been all over here and can't find an answer. I have a .swf sitting in an HTML page and I am trying to call a function inside of it from javascript. I can talk out from flash to the javascript but I can't get it to talk back in. I know I am targeting the object properly because I use console.log() on it and confirms what it is targeting.
I'm triggering the test from flash, calling a javascript function from inside the .swf, and having that function call the internal Flash function.
Flash Code:
//adds callback
ExternalInterface.addCallback("sendToFlash", flashTalkedTo);
//function called by the callback
public function flashTalkedTo():void{
//runs another function in javascript to log a string
ExternalInterface.call("callMe")
}
//calls javascript that tries to talk to Flash
ExternalInterface.call("catchFromFlash")
Javascript Code:
//function called by Flash that initiates
function catchFromFlash(){
talkToFlash()
}
//function that tries to talk to flash
function talkToFlash(){
document.getElementById('Noodleverse').sendToFlash()
}
//function called by Flash in the end to confirm call made
function callMe(){
console.log("Call Me")
}
Any help works, thanks!
Flash, and plugins in general, are a little bit fiddly. They don't behave quite like normal elements, and their functions don't behave quite like normal functions. For example, you can't save the element into a value and call a function from that. You also need to be careful because in some browsers the object is used and in others the embed is used.
The best way to call a function is to use swfobject (https://code.google.com/p/swfobject/) to abstract everything. Personally though, I use this (based on experience, maybe somebody can offer improvements):
HTML:
<object id="myplugin" ...>
...
<embed name="myplugin" ... />
</object>
JavaScript:
var o1=document.myplugin;
if(o1&&!!o1.myFlashFunction){
return document.myplugin.myFlashFunction(); // DO NOT USE o1 here. It will fail.
}
var o2=window.myplugin;
if(o2&&!!o2.myFlashFunction){
return window.myplugin.myFlashFunction(); // DO NOT USE o2 here
}
The first case (document) is for most new browsers. For example, Chrome will find the embed object. The second (window) is for IE and finds the object (IE, at least old IE, ignores embed). I'm not 100% sure the second is needed, because IE might also work with document, so call that voodoo code. Also window.myplugin will give an array of all matching elements in Chrome, FireFox, etc. (but we expect those to already be taken care of)
I'm looking for a neat way to detect whether postMessage in the browser supports the sending and receiving of objects or just strings. I figure that someone out there must have wrote something that does this but I have not managed to find a solution.
I'm using postMessage to send data to/from a WebWorker. Whilst detecting whether the browser supports workers is straight-forward, detecting whether objects can be send via postMessage has proved more difficult.
I'd like to write a simple detection function. So, if the browser supports the sending of objects to use that. If only strings are allowed I can fallback to using JSON.stringify(). I'll probably assign the function to a dojo/has test (although this is not relevant to the question/answer).
What have other people done to solve this problem? Any advice would be great, I'm new to both WebWorkers and postMessage. Thanks in advance.
I found an even easier way to detect if postMessage only supports strings or if it supports other types. Simply add a custom toString-method on the object. When trying to send an object with postMessage in IE8 and IE9 they will be converted to a string with the toString-method on the object. Since browsers that support sending objects doesn't call toString we can use this to our advantage. This test is not async, so you'll get the result instantly. Haven't tested this with web-workers, but I suppose you can use the same technique.
var onlyStrings = false;
try{window.postMessage({toString:function(){onlyStrings=true;}},"*");}catch(e){}
console.log("Browser only supports postMessage with strings? " + onlyStrings);
Tested in IE8, IE9, IE10 and latest version of Chrome, Firefox, Safari and Opera:
http://jsbin.com/igowoFaj/1/edit?js,console
Update: Did a BrowserScope test with many more tests and browsers. Conclusion is that it's safe to send clonable objects, arrays, numbers, pixel data and array buffers if onlyStrings is false. In theory all browsers that allow sending objects should use the structured clone algorithm, but the Android browser and Opera Mobile has quirks. The BrowserScope test result is a bit hard to read, because a 0 for send_xxx is only problematic if the browser actually has support for that type, so check supports_xxx too. If they are equal it's ok, but it's a bug if the browser has support but can't send (when onlyStrings is false).
You could try to perform an action BEFORE resuming your script. You could try this:
dummy_task.js
self.onmessage = function(event) {
self.postMessage(event.data);
};
javascript
workerSupportObject(callback);
function workerSupportObject(callback) {
var callbackIsCalled = false; // to make sure callback isn't run twice
var worker = new Worker('dummy_task.js'); // create a worker
// create event
worker.onmessage = function(event) {
// if the value is the same as we sent, it probably works
if(!callbackIsCalled) callback.call(null, event.data.value === 'dummy');
callbackIsCalled = true;
};
try {
// send dummy JSON data
worker.postMessage({'value': 'dummy'});
} catch(e) {
// oh... an error... clearly that's a no.
if(!callbackIsCalled) callback(null, false);
callbackIsCalled = true;
}
}
function callback(objectSupported) {
console.log('Worker supports objects: ', objectSupported);
}
I wanted to know the same thing. I created this script to detect if an object could be passed in postMessage by a simple callback to the current window. You will see IE 9 return false, IE 10 returns true.
http://jsfiddle.net/milesplit/DvqqH/
var supportsPostObject = false;
(function(){
var callback = function(e) {
supportsPostObject = (typeof(e.data)!='string');
};
(window.addEventListener) ?
window.addEventListener('message', callback) :
window.attachEvent('onmessage', callback);
('postMessage' in window) && window.postMessage({}, '*');
})();
setTimeout(function(){
alert(supportsPostObject);
}, 0);
postMessage also works between iframes; assuming that the behavior is the same between workers and frames, you should try the following or something like it:
<html>
<body>
<iframe id='if'>
</iframe>
<script>
var iframe = document.getElementById('if');
var iframeScript = iframe.contentDocument.createElement("script");
iframeScript.appendChild(
iframe.contentDocument.createTextNode(
'window.addEventListener("message", function(e) {console.log(e.data);}); console.log("listener attached");'));
iframe.contentDocument.body.appendChild(iframeScript);
iframe.contentWindow.postMessage("asdf", "*");
iframe.contentWindow.postMessage({'whatAmI': 'an object, maybe?'}, "*");
</script>
</body>
</html>
You may need to replace console or console.log to be able to see results, but on Chrome, this gets me
listener attached about:blank (1):1
asdf about:blank (1):1
Object {whatAmI: "an object, maybe?"} about:blank (1):1
when I save it to a local file and open it up.
The jsfiddle version (and the version which uses an actual worker) are left as an exercise for the reader. :)
Is there a way to get a list of the exposed functions from a Flash object? For example, you could get a list of all methods in an object by executing:
for (var i in object) {
if (typeof object[i] == "function") {
console.log(i);
}
}
The only issue is that this won't expose any methods registered through the ExternalInterfaces API. I can try and see if the function exists (object['method']) and it tells me it is a function, but I would have to guess every existing method in this manner.
NOTE: Obviously, I don't have access to the actionscript.
Just hit this question, a tad to late it seems, but I'll post an answer anyways ;)
Using IE10 (windows 7) it worked perfectly fine for me to list all my methods like so:
var obj = document.getElementById('flashObj');
for(var prop in obj){
var fx = obj[prop];
if(obj.hasOwnProperty(prop) && (typeof fx == 'function') && /eval\(instance/.test(fx)){
console.log(prop)
}
}
Note that this did not work in Chrome or Firefox and only with the exact regexp since IE10 does not report "native code" as the other browsers do.
The problem is even worse: the information is neither available in ActionScript. You register a new function as ExternalInterface.addCallback('foo', foo) and you can not list already registered callbacks.
Just a guess but see if it works. All the ExternalInterface functions should be defined in the global namespace. Try embedding the SWF in an HTML page and get all the Javascript functions defined for the page after the page has loaded. List of global user defined functions in JavaScript?
The list of functions should be those defined in the SWF file.
I guess the only way to go is to parse the SWF file bytecode and try to gather the calls to ExternalInterface.addCallback method.
http://www.google.com/search?q=parse+avm2
My instinct is no, ExternalInterface is essentially a black box, or black letter box, you poke things through and sometimes things come back, but you can't open the door to see what's inside.
Without documentation as to what's been exposed in the SWF, the only other suggestion is decompiling the swf to have a look at the source.