Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
/**
2
		An implementation of Flash 8's ExternalInterface that works with Flash 6
3
		and which is source-compatible with Flash 8.
4
 
5
		@author Brad Neuberg, bkn3@columbia.edu
6
*/
7
 
8
class DojoExternalInterface{
9
	public static var available:Boolean;
10
	public static var dojoPath = "";
11
 
12
	public static var _fscommandReady = false;
13
	public static var _callbacks = new Array();
14
 
15
	public static function initialize(){
16
		//getURL("javascript:console.debug('FLASH:DojoExternalInterface initialize')");
17
		// FIXME: Set available variable by testing for capabilities
18
		DojoExternalInterface.available = true;
19
 
20
		// extract the dojo base path
21
		DojoExternalInterface.dojoPath = DojoExternalInterface.getDojoPath();
22
		//getURL("javascript:console.debug('FLASH:dojoPath="+DojoExternalInterface.dojoPath+"')");
23
 
24
		// Sometimes, on IE, the fscommand infrastructure can take a few hundred
25
		// milliseconds the first time a page loads. Set a timer to keep checking
26
		// to make sure we can issue fscommands; otherwise, our calls to fscommand
27
		// for setCallback() and loaded() will just "disappear"
28
		_root.fscommandReady = false;
29
		var fsChecker = function(){
30
			// issue a test fscommand
31
			fscommand("fscommandReady");
32
 
33
			// JavaScript should set _root.fscommandReady if it got the call
34
			if(_root.fscommandReady == "true"){
35
				DojoExternalInterface._fscommandReady = true;
36
				clearInterval(_root.fsTimer);
37
			}
38
		};
39
		_root.fsTimer = setInterval(fsChecker, 100);
40
	}
41
 
42
	public static function addCallback(methodName:String, instance:Object,
43
											method:Function) : Boolean{
44
		// A variable that indicates whether the call below succeeded
45
		_root._succeeded = null;
46
 
47
		// Callbacks are registered with the JavaScript side as follows.
48
		// On the Flash side, we maintain a lookup table that associates
49
		// the methodName with the actual instance and method that are
50
		// associated with this method.
51
		// Using fscommand, we send over the action "addCallback", with the
52
		// argument being the methodName to add, such as "foobar".
53
		// The JavaScript takes these values and registers the existence of
54
		// this callback point.
55
 
56
		// precede the method name with a _ character in case it starts
57
		// with a number
58
		_callbacks["_" + methodName] = {_instance: instance, _method: method};
59
		_callbacks[_callbacks.length] = methodName;
60
 
61
		// The API for ExternalInterface says we have to make sure the call
62
		// succeeded; check to see if there is a value
63
		// for _succeeded, which is set by the JavaScript side
64
		if(_root._succeeded == null){
65
			return false;
66
		}else{
67
			return true;
68
		}
69
	}
70
 
71
	public static function call(methodName:String,
72
								resultsCallback:Function) : Void{
73
		// FIXME: support full JSON serialization
74
 
75
		// First, we pack up all of the arguments to this call and set them
76
		// as Flash variables, which the JavaScript side will unpack using
77
		// plugin.GetVariable(). We set the number of arguments as "_numArgs",
78
		// and add each argument as a variable, such as "_1", "_2", etc., starting
79
		// from 0.
80
		// We then execute an fscommand with the action "call" and the
81
		// argument being the method name. JavaScript takes the method name,
82
		// retrieves the arguments using GetVariable, executes the method,
83
		// and then places the return result in a Flash variable
84
		// named "_returnResult".
85
		_root._numArgs = arguments.length - 2;
86
		for(var i = 2; i < arguments.length; i++){
87
			var argIndex = i - 2;
88
			_root["_" + argIndex] = arguments[i];
89
		}
90
 
91
		_root._returnResult = undefined;
92
		fscommand("call", methodName);
93
 
94
		// immediately return if the caller is not waiting for return results
95
		if(resultsCallback == undefined || resultsCallback == null){
96
			return;
97
		}
98
 
99
		// check at regular intervals for return results
100
		var resultsChecker = function(){
101
			if((typeof _root._returnResult != "undefined")&&
102
				(_root._returnResult != "undefined")){
103
				clearInterval(_root._callbackID);
104
				resultsCallback.call(null, _root._returnResult);
105
			}
106
		};
107
		_root._callbackID = setInterval(resultsChecker, 100);
108
	}
109
 
110
	/**
111
			Called by Flash to indicate to JavaScript that we are ready to have
112
			our Flash functions called. Calling loaded()
113
			will fire the dojox.flash.loaded() event, so that JavaScript can know that
114
			Flash has finished loading and adding its callbacks, and can begin to
115
			interact with the Flash file.
116
	*/
117
	public static function loaded(){
118
		//getURL("javascript:console.debug('FLASH:loaded')");
119
 
120
		// one more step: see if fscommands are ready to be executed; if not,
121
		// set an interval that will keep running until fscommands are ready;
122
		// make sure the gateway is loaded as well
123
		var execLoaded = function(){
124
			if(DojoExternalInterface._fscommandReady == true){
125
				clearInterval(_root.loadedInterval);
126
 
127
				// initialize the small Flash file that helps gateway JS to Flash
128
				// calls
129
				DojoExternalInterface._initializeFlashRunner();
130
			}
131
		};
132
 
133
		if(_fscommandReady == true){
134
			execLoaded();
135
		}else{
136
			_root.loadedInterval = setInterval(execLoaded, 50);
137
		}
138
	}
139
 
140
	/**
141
			Handles and executes a JavaScript to Flash method call. Used by
142
			initializeFlashRunner.
143
	*/
144
	public static function _handleJSCall(){
145
		// get our parameters
146
		var numArgs = parseInt(_root._numArgs);
147
		var jsArgs = new Array();
148
		for(var i = 0; i < numArgs; i++){
149
			var currentValue = _root["_" + i];
150
			jsArgs.push(currentValue);
151
		}
152
 
153
		// get our function name
154
		var functionName = _root._functionName;
155
 
156
		// now get the actual instance and method object to execute on,
157
		// using our lookup table that was constructed by calls to
158
		// addCallback on initialization
159
		var instance = _callbacks["_" + functionName]._instance;
160
		var method = _callbacks["_" + functionName]._method;
161
 
162
		// execute it
163
		var results = method.apply(instance, jsArgs);
164
 
165
		// return the results
166
		_root._returnResult = results;
167
	}
168
 
169
	/** Called by the flash6_gateway.swf to indicate that it is loaded. */
170
	public static function _gatewayReady(){
171
		for(var i = 0; i < _callbacks.length; i++){
172
			fscommand("addCallback", _callbacks[i]);
173
		}
174
		call("dojox.flash.loaded");
175
	}
176
 
177
	/**
178
			When JavaScript wants to communicate with Flash it simply sets
179
			the Flash variable "_execute" to true; this method creates the
180
			internal Movie Clip, called the Flash Runner, that makes this
181
			magic happen.
182
	*/
183
	public static function _initializeFlashRunner(){
184
		// figure out where our Flash movie is
185
		var swfLoc = DojoExternalInterface.dojoPath + "flash6_gateway.swf";
186
 
187
		// load our gateway helper file
188
		_root.createEmptyMovieClip("_flashRunner", 5000);
189
		_root._flashRunner._lockroot = true;
190
		_root._flashRunner.loadMovie(swfLoc);
191
	}
192
 
193
	private static function getDojoPath(){
194
		var url = _root._url;
195
		var start = url.indexOf("baseRelativePath=") + "baseRelativePath=".length;
196
		var path = url.substring(start);
197
		var end = path.indexOf("&");
198
		if(end != -1){
199
			path = path.substring(0, end);
200
		}
201
		return path;
202
	}
203
}
204
 
205
// vim:ts=4:noet:tw=0: