Flash.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.embed.Flash"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.embed.Flash"] = true;
  8. dojo.provide("dojox.embed.Flash");
  9. (function(){
  10. /*******************************************************
  11. dojox.embed.Flash
  12. Base functionality to insert a flash movie into
  13. a document on the fly.
  14. Usage:
  15. var movie=new dojox.embed.Flash({ args }, containerNode);
  16. ******************************************************/
  17. function htmlEscape(str) {
  18. return String(str)
  19. .replace(/&/g, '&')
  20. .replace(/</g, '&lt;')
  21. .replace(/"/g, '&quot;')
  22. .replace(/'/g, '&apos;');
  23. }
  24. var fMarkup, fVersion;
  25. var minimumVersion = 9; // anything below this will throw an error (may overwrite)
  26. var keyBase = "dojox-embed-flash-", keyCount=0;
  27. var _baseKwArgs = {
  28. expressInstall: false,
  29. width: 320,
  30. height: 240,
  31. swLiveConnect: "true",
  32. allowScriptAccess: "sameDomain",
  33. allowNetworking:"all",
  34. style: null,
  35. redirect: null
  36. };
  37. function prep(kwArgs){
  38. // console.warn("KWARGS:", kwArgs)
  39. kwArgs = dojo.delegate(_baseKwArgs, kwArgs);
  40. if(!("path" in kwArgs)){
  41. console.error("dojox.embed.Flash(ctor):: no path reference to a Flash movie was provided.");
  42. return null;
  43. }
  44. if(!("id" in kwArgs)){
  45. kwArgs.id = (keyBase + keyCount++);
  46. }
  47. return kwArgs;
  48. }
  49. if(dojo.isIE){
  50. fMarkup = function(kwArgs){
  51. kwArgs = prep(kwArgs);
  52. if(!kwArgs){ return null; }
  53. var p;
  54. var path = kwArgs.path;
  55. if(kwArgs.vars){
  56. var a = [];
  57. for(p in kwArgs.vars){
  58. a.push(encodeURIComponent(p) + '=' + encodeURIComponent(kwArgs.vars[p]));
  59. }
  60. kwArgs.params.FlashVars = a.join("&");
  61. delete kwArgs.vars;
  62. }
  63. // FIXME: really? +'s?
  64. var s = '<object id="' + htmlEscape(String(kwArgs.id)) + '" '
  65. + 'classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" '
  66. + 'width="' + htmlEscape(String(kwArgs.width)) + '" '
  67. + 'height="' + htmlEscape(String(kwArgs.height)) + '"'
  68. + ((kwArgs.style)?' style="' + htmlEscape(String(kwArgs.style)) + '"':'')
  69. + '>'
  70. + '<param name="movie" value="' + htmlEscape(String(path)) + '" />';
  71. if(kwArgs.params){
  72. for(p in kwArgs.params){
  73. s += '<param name="' + htmlEscape(p) + '" value="' + htmlEscape(String(kwArgs.params[p])) + '" />';
  74. }
  75. }
  76. s += '</object>';
  77. return { id: kwArgs.id, markup: s };
  78. };
  79. fVersion = (function(){
  80. var testVersion = 10, testObj = null;
  81. while(!testObj && testVersion > 7){
  82. try {
  83. testObj = new ActiveXObject("ShockwaveFlash.ShockwaveFlash." + testVersion--);
  84. }catch(e){ }
  85. }
  86. if(testObj){
  87. var v = testObj.GetVariable("$version").split(" ")[1].split(",");
  88. return {
  89. major: (v[0]!=null) ? parseInt(v[0]) : 0,
  90. minor: (v[1]!=null) ? parseInt(v[1]) : 0,
  91. rev: (v[2]!=null) ? parseInt(v[2]) : 0
  92. };
  93. }
  94. return { major: 0, minor: 0, rev: 0 };
  95. })();
  96. // attach some cleanup for IE, thanks to deconcept :)
  97. dojo.addOnUnload(function(){
  98. var dummy = function(){};
  99. var objs = dojo.query("object").
  100. reverse().
  101. style("display", "none").
  102. forEach(function(i){
  103. for(var p in i){
  104. if((p != "FlashVars") && dojo.isFunction(i[p])){
  105. try{
  106. i[p] = dummy;
  107. }catch(e){}
  108. }
  109. }
  110. });
  111. });
  112. // TODO: ...and double check this fix; is IE really firing onbeforeunload with any kind of href="#" link?
  113. /*
  114. var beforeUnloadHandle = dojo.connect(dojo.global, "onbeforeunload", function(){
  115. try{
  116. if(__flash_unloadHandler){ __flash_unloadHandler=function(){ }; }
  117. if(__flash_savedUnloadHandler){ __flash_savedUnloadHandler=function(){ }; }
  118. } catch(e){ }
  119. dojo.disconnect(beforeUnloadHandle);
  120. });
  121. */
  122. } else {
  123. // *** Sane browsers branch ******************************************************************
  124. fMarkup = function(kwArgs){
  125. kwArgs = prep(kwArgs);
  126. if(!kwArgs){ return null; }
  127. var p;
  128. var path = kwArgs.path;
  129. if(kwArgs.vars){
  130. var a = [];
  131. for(p in kwArgs.vars){
  132. a.push(encodeURIComponent(p) + '=' + encodeURIComponent(kwArgs.vars[p]));
  133. }
  134. kwArgs.params.flashVars = a.join("&");
  135. delete kwArgs.vars;
  136. }
  137. var s = '<embed type="application/x-shockwave-flash" '
  138. + 'src="' + htmlEscape(String(path)) + '" '
  139. + 'id="' + htmlEscape(String(kwArgs.id)) + '" '
  140. + 'width="' + htmlEscape(String(kwArgs.width)) + '" '
  141. + 'height="' + htmlEscape(String(kwArgs.height)) + '"'
  142. + ((kwArgs.style)?' style="' + htmlEscape(String(kwArgs.style)) + '" ':'')
  143. + 'pluginspage="' + window.location.protocol + '//www.adobe.com/go/getflashplayer" ';
  144. if(kwArgs.params){
  145. for(p in kwArgs.params){
  146. s += ' ' + htmlEscape(p) + '="' + htmlEscape(String(kwArgs.params[p])) + '"';
  147. }
  148. }
  149. s += ' />';
  150. return { id: kwArgs.id, markup: s };
  151. };
  152. fVersion=(function(){
  153. var plugin = navigator.plugins["Shockwave Flash"];
  154. if(plugin && plugin.description){
  155. var v = plugin.description.replace(/([a-zA-Z]|\s)+/, "").replace(/(\s+r|\s+b[0-9]+)/, ".").split(".");
  156. return {
  157. major: (v[0]!=null) ? parseInt(v[0]) : 0,
  158. minor: (v[1]!=null) ? parseInt(v[1]) : 0,
  159. rev: (v[2]!=null) ? parseInt(v[2]) : 0
  160. };
  161. }
  162. return { major: 0, minor: 0, rev: 0 };
  163. })();
  164. }
  165. /*=====
  166. dojox.embed.__flashArgs = function(path, id, width, height, style, params, vars, expressInstall, redirect){
  167. // path: String
  168. // The URL of the movie to embed.
  169. // id: String?
  170. // A unique key that will be used as the id of the created markup. If you don't
  171. // provide this, a unique key will be generated.
  172. // width: Number?
  173. // The width of the embedded movie; the default value is 320px.
  174. // height: Number?
  175. // The height of the embedded movie; the default value is 240px
  176. // minimumVersion: Number ?
  177. // The minimum targeted version of the Flash Player (defaults to 9)
  178. // style: String?
  179. // Any CSS style information (i.e. style="background-color:transparent") you want
  180. // to define on the markup.
  181. // params: Object?
  182. // A set of key/value pairs that you want to define in the resultant markup.
  183. // vars: Object?
  184. // A set of key/value pairs that the Flash movie will interpret as FlashVars.
  185. // expressInstall: Boolean?
  186. // Whether or not to include any kind of expressInstall info. Default is false.
  187. // redirect: String?
  188. // A url to redirect the browser to if the current Flash version is not supported.
  189. this.id=id;
  190. this.path=path;
  191. this.width=width;
  192. this.minimumVersion=minimumVersion;
  193. this.height=height;
  194. this.style=style;
  195. this.params=params;
  196. this.vars=vars;
  197. this.expressInstall=expressInstall;
  198. this.redirect=redirect;
  199. }
  200. =====*/
  201. // the main entry point
  202. dojox.embed.Flash = function(/*dojox.embed.__flashArgs*/ kwArgs, /*DOMNode*/ node){
  203. // summary:
  204. // Create a wrapper object around a Flash movie; this is the DojoX equivilent
  205. // to SWFObject.
  206. //
  207. // description:
  208. // Creates a wrapper object around a Flash movie. Wrapper object will
  209. // insert the movie reference in node; when the browser first starts
  210. // grabbing the movie, onReady will be fired; when the movie has finished
  211. // loading, it will fire onLoad.
  212. //
  213. // If your movie uses ExternalInterface, you should use the onLoad event
  214. // to do any kind of proxy setup (see dojox.embed.Flash.proxy); this seems
  215. // to be the only consistent time calling EI methods are stable (since the
  216. // Flash movie will shoot several methods into the window object before
  217. // EI callbacks can be used properly).
  218. //
  219. // *Important note*: this code includes a workaround for the Eolas "fix" from
  220. // Microsoft; in order to work around the "click to activate this control" message
  221. // on any embedded Flash movie, this code will load a separate, non-dojo.require
  222. // javascript file in order to write the Flash movie into the document. As such
  223. // it cannot be used with Dojo's scope map techniques for working with multiple
  224. // versions of Dojo on the same page.
  225. //
  226. // kwArgs: dojox.embed.__flashArgs
  227. // The various arguments that will be used to help define the Flash movie.
  228. // node: DomNode
  229. // The node where the embed object will be placed
  230. //
  231. // example:
  232. // Embed a flash movie in a document using the new operator, and get a reference to it.
  233. // | var movie = new dojox.embed.Flash({
  234. // | path: "path/to/my/movie.swf",
  235. // | width: 400,
  236. // | height: 300
  237. // | }, myWrapperNode, "testLoaded");
  238. //
  239. // example:
  240. // Embed a flash movie in a document without using the new operator.
  241. // | var movie = dojox.embed.Flash({
  242. // | path: "path/to/my/movie.swf",
  243. // | width: 400,
  244. // | height: 300,
  245. // | style: "position:absolute;top:0;left:0"
  246. // | }, myWrapperNode, "testLoaded");
  247. //
  248. // File can only be run from a server, due to SWF dependency.
  249. if(location.href.toLowerCase().indexOf("file://")>-1){
  250. throw new Error("dojox.embed.Flash can't be run directly from a file. To instatiate the required SWF correctly it must be run from a server, like localHost.");
  251. }
  252. // available: Number
  253. // If there is a flash player available, and if so what version.
  254. this.available = dojox.embed.Flash.available;
  255. // minimumVersion: Number
  256. // The minimum version of Flash required to run this movie.
  257. this.minimumVersion = kwArgs.minimumVersion || minimumVersion;
  258. //console.log("AVAILABLE:", this);
  259. // id: String
  260. // The id of the DOMNode to be used for this movie. Can be used with dojo.byId to get a reference.
  261. this.id = null;
  262. // movie: FlashObject
  263. // A reference to the movie itself.
  264. this.movie = null;
  265. // domNode: DOMNode
  266. // A reference to the DOMNode that contains this movie.
  267. this.domNode = null;
  268. if(node){
  269. node = dojo.byId(node);
  270. }
  271. // setTimeout Fixes #8743 - creating double SWFs
  272. // also allows time for code to attach to onError
  273. setTimeout(dojo.hitch(this, function(){
  274. if(kwArgs.expressInstall || this.available && this.available >= this.minimumVersion){
  275. if(kwArgs && node){
  276. this.init(kwArgs, node);
  277. }else{
  278. this.onError("embed.Flash was not provided with the proper arguments.");
  279. }
  280. }else{
  281. if(!this.available){
  282. this.onError("Flash is not installed.");
  283. }else{
  284. this.onError("Flash version detected: "+this.available+" is out of date. Minimum required: "+this.minimumVersion);
  285. }
  286. }
  287. }), 100);
  288. };
  289. dojo.extend(dojox.embed.Flash, {
  290. onReady: function(/*HTMLObject*/ movie){
  291. console.warn("embed.Flash.movie.onReady:", movie)
  292. // summary:
  293. // Stub function for you to attach to when the movie reference is first
  294. // pushed into the document.
  295. },
  296. onLoad: function(/*HTMLObject*/ movie){
  297. console.warn("embed.Flash.movie.onLoad:", movie)
  298. // summary:
  299. // Stub function for you to attach to when the movie has finished downloading
  300. // and is ready to be manipulated.
  301. },
  302. onError: function(msg){
  303. },
  304. _onload: function(){
  305. // summary:
  306. // Internal. Cleans up before calling onLoad.
  307. clearInterval(this._poller);
  308. delete this._poller;
  309. delete this._pollCount;
  310. delete this._pollMax;
  311. this.onLoad(this.movie);
  312. },
  313. init: function(/*dojox.embed.__flashArgs*/ kwArgs, /*DOMNode?*/ node){
  314. console.log("embed.Flash.movie.init")
  315. // summary
  316. // Initialize (i.e. place and load) the movie based on kwArgs.
  317. this.destroy(); // ensure we are clean first.
  318. node = dojo.byId(node || this.domNode);
  319. if(!node){ throw new Error("dojox.embed.Flash: no domNode reference has been passed."); }
  320. // vars to help determine load status
  321. var p = 0, testLoaded=false;
  322. this._poller = null; this._pollCount = 0; this._pollMax = 15; this.pollTime = 100;
  323. if(dojox.embed.Flash.initialized){
  324. this.id = dojox.embed.Flash.place(kwArgs, node);
  325. this.domNode = node;
  326. setTimeout(dojo.hitch(this, function(){
  327. this.movie = this.byId(this.id, kwArgs.doc);
  328. this.onReady(this.movie);
  329. this._poller = setInterval(dojo.hitch(this, function(){
  330. // catch errors if not quite ready.
  331. try{
  332. p = this.movie.PercentLoaded();
  333. }catch(e){
  334. /* squelch */
  335. console.warn("this.movie.PercentLoaded() failed");
  336. }
  337. if(p == 100){
  338. // if percent = 100, movie is fully loaded and we're communicating
  339. this._onload();
  340. }else if(p==0 && this._pollCount++ > this._pollMax){
  341. // after several attempts, we're not past zero.
  342. // FIXME: What if we get stuck on 33% or something?
  343. clearInterval(this._poller);
  344. throw new Error("Building SWF failed.");
  345. }
  346. }), this.pollTime);
  347. }), 1);
  348. }
  349. },
  350. _destroy: function(){
  351. // summary
  352. // Kill the movie and reset all the properties of this object.
  353. try{
  354. this.domNode.removeChild(this.movie);
  355. }catch(e){}
  356. this.id = this.movie = this.domNode = null;
  357. },
  358. destroy: function(){
  359. // summary
  360. // Public interface for destroying all the properties in this object.
  361. // Will also clean all proxied methods.
  362. if(!this.movie){ return; }
  363. // remove any proxy functions
  364. var test = dojo.delegate({
  365. id: true,
  366. movie: true,
  367. domNode: true,
  368. onReady: true,
  369. onLoad: true
  370. });
  371. for(var p in this){
  372. if(!test[p]){
  373. delete this[p];
  374. }
  375. }
  376. // poll the movie
  377. if(this._poller){
  378. // wait until onLoad to destroy
  379. dojo.connect(this, "onLoad", this, "_destroy");
  380. } else {
  381. this._destroy();
  382. }
  383. },
  384. byId: function (movieName, doc){
  385. // summary:
  386. // Gets Flash movie by id.
  387. // description:
  388. // Probably includes methods for outdated
  389. // browsers, but this should catch all cases.
  390. // arguments:
  391. // movieName: String
  392. // The name of the SWF
  393. // doc: Object
  394. // The document, if not current window
  395. // (not fully supported)
  396. // example:
  397. // | var movie = dojox.embed.Flash.byId("myId");
  398. //
  399. doc = doc || document;
  400. if(doc.embeds[movieName]){
  401. return doc.embeds[movieName];
  402. }
  403. if(doc[movieName]){
  404. return doc[movieName];
  405. }
  406. if(window[movieName]){
  407. return window[movieName];
  408. }
  409. if(document[movieName]){
  410. return document[movieName];
  411. }
  412. return null;
  413. }
  414. });
  415. // expose information through the constructor function itself.
  416. dojo.mixin(dojox.embed.Flash, {
  417. // summary:
  418. // A singleton object used internally to get information
  419. // about the Flash player available in a browser, and
  420. // as the factory for generating and placing markup in a
  421. // document.
  422. //
  423. // minSupported: Number
  424. // The minimum supported version of the Flash Player, defaults to 8.
  425. // available: Number
  426. // Used as both a detection (i.e. if(dojox.embed.Flash.available){ })
  427. // and as a variable holding the major version of the player installed.
  428. // supported: Boolean
  429. // Whether or not the Flash Player installed is supported by dojox.embed.
  430. // version: Object
  431. // The version of the installed Flash Player; takes the form of
  432. // { major, minor, rev }. To get the major version, you'd do this:
  433. // var v=dojox.embed.Flash.version.major;
  434. // initialized: Boolean
  435. // Whether or not the Flash engine is available for use.
  436. // onInitialize: Function
  437. // A stub you can connect to if you are looking to fire code when the
  438. // engine becomes available. A note: DO NOT use this event to
  439. // place a movie in a document; it will usually fire before DOMContentLoaded
  440. // is fired, and you will get an error. Use dojo.addOnLoad instead.
  441. minSupported : 8,
  442. available: fVersion.major,
  443. supported: (fVersion.major >= fVersion.required),
  444. minimumRequired: fVersion.required,
  445. version: fVersion,
  446. initialized: false,
  447. onInitialize: function(){
  448. dojox.embed.Flash.initialized = true;
  449. },
  450. __ie_markup__: function(kwArgs){
  451. return fMarkup(kwArgs);
  452. },
  453. proxy: function(/*dojox.embed.Flash*/ obj, /*Array|String*/ methods){
  454. // summary:
  455. // Create the set of passed methods on the dojox.embed.Flash object
  456. // so that you can call that object directly, as opposed to having to
  457. // delve into the internal movie to do this. Intended to make working
  458. // with Flash movies that use ExternalInterface much easier to use.
  459. //
  460. // example:
  461. // Create "setMessage" and "getMessage" methods on foo.
  462. // | var foo = new dojox.embed.Flash(args, someNode);
  463. // | dojo.connect(foo, "onLoad", dojo.hitch(foo, function(){
  464. // | dojox.embed.Flash.proxy(this, [ "setMessage", "getMessage" ]);
  465. // | this.setMessage("dojox.embed.Flash.proxy is pretty cool...");
  466. // | console.log(this.getMessage());
  467. // | }));
  468. dojo.forEach((dojo.isArray(methods) ? methods : [ methods ]), function(item){
  469. this[item] = dojo.hitch(this, function(){
  470. return (function(){
  471. return eval(this.movie.CallFunction(
  472. '<invoke name="' + item + '" returntype="javascript">'
  473. + '<arguments>'
  474. + dojo.map(arguments, function(item){
  475. // FIXME:
  476. // investigate if __flash__toXML will
  477. // accept direct application via map()
  478. // (e.g., does it ignore args past the
  479. // first? or does it blow up?)
  480. return __flash__toXML(item);
  481. }).join("")
  482. + '</arguments>'
  483. + '</invoke>'
  484. ));
  485. }).apply(this, arguments||[]);
  486. });
  487. }, obj);
  488. }
  489. });
  490. /*if(dojo.isIE){
  491. // Ugh!
  492. if(dojo._initFired){
  493. var e = document.createElement("script");
  494. e.type = "text/javascript";
  495. e.src = dojo.moduleUrl("dojox", "embed/IE/flash.js");
  496. document.getElementsByTagName("head")[0].appendChild(e);
  497. }else{
  498. // we can use document.write. What a kludge.
  499. document.write('<scr'+'ipt type="text/javascript" src="' + dojo.moduleUrl("dojox", "embed/IE/flash.js") + '">'
  500. + '</scr'+'ipt>');
  501. }
  502. }else{*/
  503. dojox.embed.Flash.place = function(kwArgs, node){
  504. var o = fMarkup(kwArgs);
  505. node = dojo.byId(node);
  506. if(!node){
  507. node = dojo.doc.createElement("div");
  508. node.id = o.id+"-container";
  509. dojo.body().appendChild(node);
  510. }
  511. if(o){
  512. node.innerHTML = o.markup;
  513. return o.id;
  514. }
  515. return null;
  516. }
  517. dojox.embed.Flash.onInitialize();
  518. //}
  519. })();
  520. }