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, "&", "&");
|
|
|
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:
|