Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
/**
2
	A wrapper around Flash 8's ExternalInterface; DojoExternalInterface is needed so that we
3
	can do a Flash 6 implementation of ExternalInterface, and be able
4
	to support having a single codebase that uses DojoExternalInterface
5
	across Flash versions rather than having two seperate source bases,
6
	where one uses ExternalInterface and the other uses DojoExternalInterface.
7
 
8
	DojoExternalInterface class does a variety of optimizations to bypass ExternalInterface's
9
	unbelievably bad performance so that we can have good performance
10
	on Safari; see the blog post
11
	http://codinginparadise.org/weblog/2006/02/how-to-speed-up-flash-8s.html
12
	for details.
13
 
14
	@author Brad Neuberg, bkn3@columbia.edu
15
*/
16
import flash.external.ExternalInterface;
17
 
18
class DojoExternalInterface{
19
	public static var available:Boolean;
20
	public static var dojoPath = "";
21
 
22
	private static var flashMethods:Array = new Array();
23
	private static var numArgs:Number;
24
	private static var argData:Array;
25
	private static var resultData = null;
26
 
27
	public static function initialize(){
28
		// extract the dojo base path
29
		DojoExternalInterface.dojoPath = DojoExternalInterface.getDojoPath();
30
 
31
		// see if we need to do an express install
32
		var install:ExpressInstall = new ExpressInstall();
33
		if(install.needsUpdate){
34
			install.init();
35
		}
36
 
37
		// register our callback functions
38
		ExternalInterface.addCallback("startExec", DojoExternalInterface, startExec);
39
		ExternalInterface.addCallback("setNumberArguments", DojoExternalInterface,
40
																	setNumberArguments);
41
		ExternalInterface.addCallback("chunkArgumentData", DojoExternalInterface,
42
																	chunkArgumentData);
43
		ExternalInterface.addCallback("exec", DojoExternalInterface, exec);
44
		ExternalInterface.addCallback("getReturnLength", DojoExternalInterface,
45
																	getReturnLength);
46
		ExternalInterface.addCallback("chunkReturnData", DojoExternalInterface,
47
																	chunkReturnData);
48
		ExternalInterface.addCallback("endExec", DojoExternalInterface, endExec);
49
 
50
		// set whether communication is available
51
		DojoExternalInterface.available = ExternalInterface.available;
52
		DojoExternalInterface.call("loaded");
53
	}
54
 
55
	public static function addCallback(methodName:String, instance:Object,
56
										 								 method:Function) : Boolean{
57
		// register DojoExternalInterface methodName with it's instance
58
		DojoExternalInterface.flashMethods[methodName] = instance;
59
 
60
		// tell JavaScript about DojoExternalInterface new method so we can create a proxy
61
		ExternalInterface.call("dojox.flash.comm._addExternalInterfaceCallback",
62
													 methodName);
63
 
64
		return true;
65
	}
66
 
67
	public static function call(methodName:String,
68
								resultsCallback:Function) : Void{
69
		// we might have any number of optional arguments, so we have to
70
		// pass them in dynamically; strip out the results callback
71
		var parameters = new Array();
72
		for(var i = 0; i < arguments.length; i++){
73
			if(i != 1){ // skip the callback
74
				parameters.push(arguments[i]);
75
			}
76
		}
77
 
78
		var results = ExternalInterface.call.apply(ExternalInterface, parameters);
79
 
80
		// immediately give the results back, since ExternalInterface is
81
		// synchronous
82
		if(resultsCallback != null && typeof resultsCallback != "undefined"){
83
			resultsCallback.call(null, results);
84
		}
85
	}
86
 
87
	/**
88
			Called by Flash to indicate to JavaScript that we are ready to have
89
			our Flash functions called. Calling loaded()
90
			will fire the dojox.flash.loaded() event, so that JavaScript can know that
91
			Flash has finished loading and adding its callbacks, and can begin to
92
			interact with the Flash file.
93
	*/
94
	public static function loaded(){
95
		DojoExternalInterface.call("dojox.flash.loaded");
96
	}
97
 
98
	public static function startExec():Void{
99
		DojoExternalInterface.numArgs = null;
100
		DojoExternalInterface.argData = null;
101
		DojoExternalInterface.resultData = null;
102
	}
103
 
104
	public static function setNumberArguments(numArgs):Void{
105
		DojoExternalInterface.numArgs = numArgs;
106
		DojoExternalInterface.argData = new Array(DojoExternalInterface.numArgs);
107
	}
108
 
109
	public static function chunkArgumentData(value, argIndex:Number):Void{
110
		//getURL("javascript:console.debug('FLASH: chunkArgumentData, value="+value+", argIndex="+argIndex+"')");
111
		var currentValue = DojoExternalInterface.argData[argIndex];
112
		if(currentValue == null || typeof currentValue == "undefined"){
113
			DojoExternalInterface.argData[argIndex] = value;
114
		}else{
115
			DojoExternalInterface.argData[argIndex] += value;
116
		}
117
	}
118
 
119
	public static function exec(methodName):Void{
120
		// decode all of the arguments that were passed in
121
		for(var i = 0; i < DojoExternalInterface.argData.length; i++){
122
			DojoExternalInterface.argData[i] =
123
				DojoExternalInterface.decodeData(DojoExternalInterface.argData[i]);
124
		}
125
 
126
		var instance = DojoExternalInterface.flashMethods[methodName];
127
		DojoExternalInterface.resultData = instance[methodName].apply(
128
																			instance, DojoExternalInterface.argData);
129
		// encode the result data
130
		DojoExternalInterface.resultData =
131
			DojoExternalInterface.encodeData(DojoExternalInterface.resultData);
132
 
133
		//getURL("javascript:console.debug('FLASH: encoded result data="+DojoExternalInterface.resultData+"')");
134
	}
135
 
136
	public static function getReturnLength():Number{
137
	 if(DojoExternalInterface.resultData == null ||
138
	 					typeof DojoExternalInterface.resultData == "undefined"){
139
	 	return 0;
140
	 }
141
	 var segments = Math.ceil(DojoExternalInterface.resultData.length / 1024);
142
	 return segments;
143
	}
144
 
145
	public static function chunkReturnData(segment:Number):String{
146
		var numSegments = DojoExternalInterface.getReturnLength();
147
		var startCut = segment * 1024;
148
		var endCut = segment * 1024 + 1024;
149
		if(segment == (numSegments - 1)){
150
			endCut = segment * 1024 + DojoExternalInterface.resultData.length;
151
		}
152
 
153
		var piece = DojoExternalInterface.resultData.substring(startCut, endCut);
154
 
155
		//getURL("javascript:console.debug('FLASH: chunking return piece="+piece+"')");
156
 
157
		return piece;
158
	}
159
 
160
	public static function endExec():Void{
161
	}
162
 
163
	private static function decodeData(data):String{
164
		// we have to use custom encodings for certain characters when passing
165
		// them over; for example, passing a backslash over as //// from JavaScript
166
		// to Flash doesn't work
167
		data = DojoExternalInterface.replaceStr(data, "&custom_backslash;", "\\");
168
 
169
		data = DojoExternalInterface.replaceStr(data, "\\\'", "\'");
170
		data = DojoExternalInterface.replaceStr(data, "\\\"", "\"");
171
 
172
		return data;
173
	}
174
 
175
	private static function encodeData(data){
176
		//getURL("javascript:console.debug('inside flash, data before="+data+"')");
177
 
178
		// double encode all entity values, or they will be mis-decoded
179
		// by Flash when returned
180
		data = DojoExternalInterface.replaceStr(data, "&", "&amp;");
181
 
182
		// certain XMLish characters break Flash's wire serialization for
183
		// ExternalInterface; encode these into a custom encoding, rather than
184
		// the standard entity encoding, because otherwise we won't be able to
185
		// differentiate between our own encoding and any entity characters
186
		// that are being used in the string itself
187
		data = DojoExternalInterface.replaceStr(data, '<', '&custom_lt;');
188
		data = DojoExternalInterface.replaceStr(data, '>', '&custom_gt;');
189
 
190
		// encode control characters and JavaScript delimiters
191
		data = DojoExternalInterface.replaceStr(data, "\n", "\\n");
192
		data = DojoExternalInterface.replaceStr(data, "\r", "\\r");
193
		data = DojoExternalInterface.replaceStr(data, "\f", "\\f");
194
		data = DojoExternalInterface.replaceStr(data, "'", "\\'");
195
		data = DojoExternalInterface.replaceStr(data, '"', '\"');
196
 
197
		//getURL("javascript:console.debug('inside flash, data after="+data+"')");
198
		return data;
199
	}
200
 
201
	/**
202
			Flash ActionScript has no String.replace method or support for
203
			Regular Expressions! We roll our own very simple one.
204
	*/
205
	private static function replaceStr(inputStr:String, replaceThis:String,
206
																		 withThis:String):String {
207
		var splitStr = inputStr.split(replaceThis)
208
		inputStr = splitStr.join(withThis)
209
		return inputStr;
210
	}
211
 
212
	private static function getDojoPath(){
213
		var url = _root._url;
214
		var start = url.indexOf("baseRelativePath=") + "baseRelativePath=".length;
215
		var path = url.substring(start);
216
		var end = path.indexOf("&");
217
		if(end != -1){
218
			path = path.substring(0, end);
219
		}
220
		return path;
221
	}
222
}
223
 
224
// vim:ts=4:noet:tw=0: