Telling JS when AS's ExternalInterface is ready - javascript

SOLVED: I should have added more detail. Even though the External Interface was set up the NetConnection/NetStream objects were not connected to the server. As a result, I couldn't make any calls thru. A very important detail I left out, apologies.
I know that it's proper to have Flash call back to JavaScript when External Interface is ready so I make the call. The JS method gets called correctly but I am unable to then trigger a successful call back to the Flash file. I have to manually set a 1-second timeout to get it to work and I don't understand why. If the External Interface is ready then I should be able to call back to Flash right away, right?
By the way, I'm using SWFObject.embedSWF() to place the Flash file on the page. I've given the file an id and name attributes.
Here's my flash code:
private function init():void // onCreationComplete handler
{
this.setupExternalInterface();
}
private function setupExternalInterface():void
{
if (ExternalInterface.available)
{
ExternalInterface.call("swfIsReady");
ExternalInterface.addCallback("call", makeACall);
}
}
And here's the JSP page:
function swfIsReady(){
setTimeout(flexCall,1000);
}
function flexCall(){
var theApp = getFlexApp(attributes.name);
theApp.call();
}
function getFlexApp(appName)
{
if (navigator.appName.indexOf ("Microsoft") !=-1)
{
return window[appName];
}
else
{
return document[appName];
}
}
This is the only way it works. I thought I could just remove the timeout and call flexCall() directly.

I think you have two little problems in your code :
The first problem is using the call() method which is used in JavaScript to invoke a function.
Try this (I'm not sure that's working but to more see the problem) :
swf_obj.call.call();
but the solution is simply to use another name of your callback function :
swf_obj.make_call();
The second one, is calling ExternalInterface.addCallback() after ExternalInterface.call() which you can just inverse their order to get it working.
So your code can be like this for example :
ActionScript :
private function init(event:FlexEvent):void
{
setupExternalInterface();
}
private function setupExternalInterface():void
{
if (ExternalInterface.available)
{
ExternalInterface.addCallback("make_call", makeACall);
ExternalInterface.call("swfIsReady");
}
}
JavaScript :
function swfIsReady()
{
var swf_obj= swfobject.getObjectById(attributes.name);
if (swf_obj) {
swf_obj.make_call();
}
}
Hope that can help.

Related

Unity - communicating with clientside Javascript and ajax. How to pass data back to the webpage from unity?

What I am really asking is this; if there are dependencies which are impossible to compile into the unity build, is there a way of still calling them from within the unity and simply using the scripts loaded into the browser from the website and communicating with them?
Relevant documentation does not address this deeply:
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html
I am creating a website wrapper for a unity application. The buttons for the experience are located within the website, as the buttons affect the rest of the site, not just the unity application.
When certain content is loaded in the unity game play however, the app needs to be able to affect the website. Is there a way to pass the data back to the website in a creative way? Currently, I am including all my javascript code for the website in the unity compile, and it is erroring out on:
gameInstance = UnityLoader.instantiate("gameContainer", "/Build/DomumProto16_Web.json", {
onProgress: UnityProgress
});
Sending data to the gameplay from the website:
gameInstance.SendMessage('Manager','Filter', JSON.stringify(filterActive));
Need to call this function from the unity gameplay. However, ajax.ajax_url is undefined due to it being localized using wp_localize_script() on the backend.
function showStudentWork(studentIndex){
//make sure to remove all the
var x = document.getElementById("studentWork");
var studentID = studentWork[studentIndex];
console.log(studentID);
$.ajax({
url: ajax.ajax_url,
type: "POST",
data: {
action: 'getStudentPost',
currentStudent: studentID
},
success: function (data) {
x.innerHTML = "";
x.innerHTML = data;
x.style.display = "grid";
},
error: function (error) {
console.log(`Error ${error}`);
}
});
return false;
}
What I am really asking is this; if there are dependencies which are impossible to compile into the unity build, is there a way of still calling them from within the unity and simply using the scripts loaded into the browser from the website and communicating with them?
Here are two methods. One is, in my opinion, easier, but it is deprecated and you should ~not~ use it. Options two is the 'corrrect' way, but it is kinda ugly imo.
Option 1: Application.ExternalCall
Documentation
This option allows you to call browser javascript directly, but Unity has deprecated support for it and is probably a bad idea for anything long term.
In a given browser with a Unity web player working, consider the following:
In browser source, define a javascript function
<other html>
<script>
function foo(msg) {
alert(msg);
}
</script>
In Unity, whenever it is nessecary:
Application.ExternalCall( "foo", "The game says hello!" );
This allows Javascript to be called from Unity.
There is similar functionality for communication in the opposite direction.
Option 2: jslibs
Documentation
This is the unity-endorsed way of doing things. It involved packaging javascript libraries into your games.
First, create a javascript file that will be packaged with your game. Here is an example file:
// Unity syntactic sugar
mergeInto(LibraryManager.library, {
// Declare all your functions that can be called from c# here
alert_user: function (msg) {
window.alert(msg);
},
other_func: function () {
// does something else
// etc.
// put as many functions as you'd like in here
}
}
Place that file, with extension .jslib in your Plugins folder on your project.
Then, in your c# files, you need to:
// Declare a monobehavior, whatever
using UnityEngine;
using System.Runtime.InteropServices;
public class NewBehaviourScript : MonoBehaviour {
// IMPORTANT
// You have to declare the javascript functions you'll be calling
// as private external function in your c# file. Additionally,
// They need a special function decorator [DllImport("__Internal")]
// Example:
[DllImport("__Internal")]
private static extern void alert_user(string msg);
// With that unpleasantness over with, you can now call the function
void Start() {
alert_user("Hello, I am a bad person and I deserve to write c#");
}
}
Et viola. You can call other javascript from your c# javascript, and interact with the dom, but I will leave all those decisions up to you.
The other direction
In both cases, communication in the opposite direction (browser saying something to Unity) is the same format.
In javascript, create a UnityInstance (the way of this is a little two long-winded to put into this answer, check either docs). Then, just .sendMessage.
e.g.:
c#
...
void DoSomething (string msg) {
// this is a c# function that does something in the game
// use your imagination
}
...
javascript:
let game = UnityLoader // Actually load the game here
game.SendMessage('TheNameOfMyGameObject', 'DoSomething', 'This is my message');
If I understand it can be done using WWW call function
This is not a proper code okay . This will be just an idea for you.
Send a variable to the PHP function like this
string url = "" // add your URL here;
WWWForm form = new WWWForm ();
form.AddField("YourFunctionName", "SampleFunction");
WWW www = new WWW(url, form);
yield return www;
Now in your PHP do it something like this
function YourFunctionName()
{
// your function code here
}
and now on
$YourFunctionName = $_POST["functionName"];
switch ($functionName){
case "SampleFunction":
SampleFunction();
break;
}
So the idea here is still you will need a PHP and from that PHP call your ajax :)

multiple functions onClick() not working

Below is the code that I used for multiple java scripts on a single button. But only any one is working when I disable the second one. Please let me know: how do I change my code to make it to work fine?
function invoke(but)
{
if(but==0)
{
function move(){
document.getElementById('tgt1').value =
document.getElementById('Allocation').value;
document.getElementById('Allocation').value="";
document.getElementById("Send").disabled=true;
}document.myform.action="Alloc_Insert.do";
}
else if(but==1)
{
document.myform.action="";
}
else if(but==2){ document.myform.action="WL_Verif.do";}
else if(but==3){ document.myform.action="Add_Query.do";}
document.myform.submit();
}
And the html is as below:
<input type="Submit" value="Allocate" id="Send" name="submit" onClick="invoke(0);move();"/><br/>
change the name of the button to something else than "submit"
To explain what happens:
When you assign the name-attribute "submit" to the button(or any other form-element), this element will be accessible via
document.myform.submit
but there is also the build-in method of a form: submit(), you also may access it by using
document.myform.submit
What happens now when you call document.myform.submit()
I'll write the code a little bit different, and you will see trouble:
document.myform['submit']()
Instead of accessing the built-in method, the code points first to the form-element, and then tries to execute the method. But a form-element is not a method, it all ends up in an error and the rest of the script(including the call of move() ) will not get executed.
It's the same with "reset", you never should use the name of a built-in property/method of the form-element as name for form-elements.
notice the 'move' function is not declared outside the 'invoke' function.
Then;
either wrap them in a self invoking function:
onclick="(function(){ invoke(0);move(); })();"
or attach event handlers (preferred usually)
div.attachEventListener('click', function () { ... }); // DOM 3
div.attachEvent('click', function () { ... }); // IE
Your functions are declared in a weird way. You're defining move inside of invoke, which I don't think you want. If you want to have two functions, put move outside of invoke, like this:
function move(){
document.getElementById('tgt1').value =
document.getElementById('Allocation').value;
document.getElementById('Allocation').value="";
document.getElementById("Send").disabled=true;
}
function invoke(but)
{
if(but==0)
{
move();
document.myform.action="Alloc_Insert.do";
}
else if(but==1)
{
document.myform.action="";
}
else if(but==2){ document.myform.action="WL_Verif.do";}
else if(but==3){ document.myform.action="Add_Query.do";}
document.myform.submit();
}
A note: it's generally not a good idea to use onClick in your HTML -- it's better to put that in your JavaScript.
I think the problem is the scope of the move() function. Try defining move outside of invoke.
function invoke (but) {
if(but==0) {
document.myform.action="Alloc_Insert.do";
// I don't know if you meant to call move() here or not
}
else if (but==2) { document.myform.action="WL_Verif.do"; }
else if (but==3) { document.myform.action="Add_Query.do"; }
document.myform.submit();
}
function move(){
document.getElementById('tgt1').value =
document.getElementById('Allocation').value;
document.getElementById('Allocation').value="";
document.getElementById("Send").disabled=true;
}
Also, properly formatting your code will do wonders to the legibility of it.
NOTE: Firefox seems to be quite happy to execute the onClick="invoke(0);move();" even if move is defined inside invoke. Chrome however won't execute move because it can't find it. So be sure to test your script in multiple browsers as well.

Override/Rewrite a javascript library function

I am using an open source javascript library timeline.verite.co
It's a timeline library which works great on page load. But when I try to repaint the timeline on certain condition, it starts giving out weird errors
I would like to modify the init function in the library. But instead of changing it in the original library itself, I would like to rewrite/override this function in another separate .js file so that when this function is called, instead of going to the original function, it must use my modified function.
I'm not sure whether to use prototype/ inheritance and how to use it to solve this problem?
You only need to assign the new value for it. Here is an example:
obj = {
myFunction : function() {
alert('originalValue');
}
}
obj.myFunction();
obj.myFunction = function() {
alert('newValue');
}
obj.myFunction();

Unable to re-define a function in my javascript object

I have an object defined using literal notation as follows (example code used). This is in an external script file.
if (RF == null) var RF = {};
RF.Example= {
onDoSomething: function () { alert('Original Definition');} ,
method1 : function(){ RF.Example.onDoSomething(); }
}
In my .aspx page I have the following ..
$(document).ready(function () {
RF.Example.onDoSomething = function(){ alert('New Definition'); };
RF.Example.method1();
});
When the page loads the document.ready is called but the alert('Original Definition'); is only ever shown. Can someone point me in the right direction. I basically want to redefine the onDoSomething function. Thanks, Ben.
Edit
Thanks for the comments, I can see that is working. Would it matter that method1 is actually calling another method that takes the onDoSomething() function as a callback parameter? e.g.
method1 : function(){
RF.Example2.callbackFunction(function() {RF.Example.onDoSomething();});
}
Your code as quoted should work (and does: http://jsbin.com/uguva4), so something other than what's in your question is causing this behavior. For instance, if you're using any kind of JavaScript compiler (like Closure) or minifier or something, the names may be being changed, which case you're adding a new onDoSomething when the old one has been renamed. Alternately, perhaps the alert is being triggered by something else, not what you think is triggering it. Or something else may have grabbed a reference to the old onDoSomething (elsewhere in the external script, perhaps) and be using it directly, like this: http://jsbin.com/uguva4/2.
Thanks for the response .. in the end the answer was unrelated to the code posted. Cheers for verifying I wasn't going bonkers.

Detect availability of Javascript from Actionscript?

I would like to open external URLs from within my Flash project. I typically use something like this:
getURL("javascript:newwin=window.open('http://someurl.com','','');");
But, if Javascript isn't available (in cases where the SWF is not embedded in HTML) then this will fail. How can I detect whether Javascript is available? If it isn't available, I'd probably just use getURL and give it the direct URL, although I only want to do this if using the Javascript method isn't possible. Thanks!
To accomplish what you're describing, the best way is to have Flash invoke a JavaScript function called "pingJavaScript". If JavaScript is running, that JavaScript function will then call a function on the Flash movie called "receiveJSNotification". So in your Flash movie, if that method gets called, you know JS is running.
To enable robust communication between a Flash movie and JavaScript, include this at the top of an Actionscript on the first frame of your movie:
import flash.external.ExternalInterface;
import flash.events.Event;
Add a function to receive a "yes, I'm alive" from JavaScript:
var js_available = false;
function receiveJSNotification(str:String):void {
_root.js_available = true;
}
ExternalInterface.addCallback("notifyFlash", receiveJSNotification);
ExternalInterface.call("pingJavaScript", null);
In JavaScript:
function pingJavaScript()
{
var movie = getFlash();
movie.notifyFlash();
}
function getFlash()
{
var movie = null;
if (navigator.appName.indexOf('Microsoft') != -1) {
movie = window['flashmovie'];
} else {
movie = document['flashmovie'];
}
return movie;
}
I find that there is actually a much easier way to accomplish this:
public function isThereJavaScript():Boolean{
return Boolean(ExternalInterface.call("window.location.href.toString"));
}
This requires no JavaScript back-end. It just works consistently. If there is the ability to call JavaScript, that means that there has to be a window property, which will have a non-null location.href. ExternalInterface is also available for both AS2 and AS3.

Categories