1 /**
  2  * simplified flash bridge for yui swf
  3  * @author yiminghe@gmail.com
  4  */
  5 KISSY.add("editor/plugin/flashBridge/index", function (S, Editor, flashUtils) {
  6 
  7     var instances = {};
  8 
  9     function FlashBridge(cfg) {
 10         this._init(cfg);
 11     }
 12 
 13     S.augment(FlashBridge, S.EventTarget, {
 14         _init:function (cfg) {
 15             var self = this,
 16                 id = S.guid("flashbridge-"),
 17                 callback = "KISSY.Editor.FlashBridge.EventHandler";
 18             cfg.flashVars = cfg.flashVars || {};
 19             cfg.attrs = cfg.attrs || {};
 20             cfg.params = cfg.params || {};
 21             var flashVars = cfg.flashVars,
 22                 attrs = cfg.attrs,
 23                 params = cfg.params;
 24             S.mix(attrs, {
 25                 id:id,
 26                 //http://yiminghe.javaeye.com/blog/764872
 27                 //firefox 必须使创建的flash以及容器可见,才会触发contentReady
 28                 //默认给flash自身很大的宽高,容器小点就可以了,
 29                 width:'100%',
 30                 height:'100%'
 31             }, false);
 32             //这几个要放在 param 里面,主要是允许 flash js沟通
 33             S.mix(params, {
 34                 allowScriptAccess:'always',
 35                 allowNetworking:'all',
 36                 scale:'noScale'
 37             }, false);
 38             S.mix(flashVars, {
 39                 shareData:false,
 40                 useCompression:false
 41             }, false);
 42             var swfCore = {
 43                 YUISwfId:id,
 44                 YUIBridgeCallback:callback
 45             };
 46             if (cfg.ajbridge) {
 47                 swfCore = {
 48                     swfID:id,
 49                     jsEntry:callback
 50                 };
 51             }
 52             S.mix(flashVars, swfCore);
 53             instances[id] = self;
 54             self.id = id;
 55             self.swf = flashUtils.createSWFRuntime(cfg.movie, cfg);
 56             self._expose(cfg.methods);
 57         },
 58         _expose:function (methods) {
 59             var self = this;
 60             for (var i = 0; i < methods.length; i++) {
 61                 var m = methods[i];
 62                 (function (m) {
 63                     self[m] = function () {
 64                         return self._callSWF(m, S.makeArray(arguments));
 65                     };
 66                 })(m);
 67             }
 68         },
 69         /**
 70          * Calls a specific function exposed by the SWF's ExternalInterface.
 71          * @param func {String} the name of the function to call
 72          * @param args {Array} the set of arguments to pass to the function.
 73          */
 74         _callSWF:function (func, args) {
 75             var self = this;
 76             args = args || [];
 77             try {
 78                 if (self.swf[func]) {
 79                     return self.swf[func].apply(self.swf, args);
 80                 }
 81             }
 82                 // some version flash function is odd in ie: property or method not supported by object
 83             catch (e) {
 84                 var params = "";
 85                 if (args.length !== 0) {
 86                     params = "'" + args.join("', '") + "'";
 87                 }
 88                 //avoid eval for compressiong
 89                 return (new Function('self', 'return self.swf.' + func + '(' + params + ');'))(self);
 90             }
 91         },
 92         _eventHandler:function (event) {
 93             var self = this,
 94                 type = event.type;
 95 
 96             if (type === 'log') {
 97                 S.log(event.message);
 98             } else if (type) {
 99                 self.fire(type, event);
100             }
101         },
102         ready:function (fn) {
103             var self = this;
104             if (self._ready) {
105                 fn.call(this);
106             } else {
107                 self.on("contentReady", fn);
108             }
109         },
110         destroy:function () {
111             delete instances[this.id];
112         }
113     });
114 
115     FlashBridge.EventHandler = function (id, event) {
116         S.log("flash fire event : " + event.type);
117         var instance = instances[id];
118         if (instance) {
119             //防止ie同步触发事件,后面还没on呢,另外给 swf 喘息机会
120             //否则同步后触发事件,立即调用swf方法会出错
121             setTimeout(function () {
122                 instance._eventHandler.call(instance, event);
123             }, 100);
124         }
125     };
126 
127     Editor.FlashBridge = FlashBridge;
128 
129     var UA = S.UA, fpv, fpvF, firstRun = true;
130 
131     /*
132      获取 Flash 版本号
133      返回数据 [M, S, R] 若未安装,则返回 undefined
134      */
135     function getFlashVersion() {
136         var ver, SF = 'ShockwaveFlash';
137 
138         // for NPAPI see: http://en.wikipedia.org/wiki/NPAPI
139         if (navigator.plugins && navigator.mimeTypes.length) {
140             ver = (navigator.plugins['Shockwave Flash'] || {})['description'];
141         }
142         // for ActiveX see:	http://en.wikipedia.org/wiki/ActiveX
143         else if (window.ActiveXObject) {
144             try {
145                 ver = new ActiveXObject(SF + '.' + SF)['GetVariable']('$version');
146             } catch (ex) {
147                 //S.log('getFlashVersion failed via ActiveXObject');
148                 // nothing to do, just return undefined
149             }
150         }
151 
152         // 插件没安装或有问题时,ver 为 undefined
153         if (!ver) return undefined;
154 
155         // 插件安装正常时,ver 为 "Shockwave Flash 10.1 r53" or "WIN 10,1,53,64"
156         return arrify(ver);
157     }
158 
159     /*
160      arrify("10.1.r53") => ["10", "1", "53"]
161      */
162     function arrify(ver) {
163         return ver.match(/(\d)+/g);
164     }
165 
166     /*
167      格式:主版本号Major.次版本号Minor(小数点后3位,占3位)修正版本号Revision(小数点后第4至第8位,占5位)
168      ver 参数不符合预期时,返回 0
169      numerify("10.1 r53") => 10.00100053
170      numerify(["10", "1", "53"]) => 10.00100053
171      numerify(12.2) => 12.2
172      */
173     function numerify(ver) {
174         var arr = S.isString(ver) ? arrify(ver) : ver, ret = ver;
175         if (S.isArray(arr)) {
176             ret = parseFloat(arr[0] + '.' + pad(arr[1], 3) + pad(arr[2], 5));
177         }
178         return ret || 0;
179     }
180 
181     /*
182      pad(12, 5) => "00012"
183      ref: http://lifesinger.org/blog/2009/08/the-harm-of-tricky-code/
184      */
185     function pad(num, n) {
186         var len = (num + '').length;
187         while (len++ < n) {
188             num = '0' + num;
189         }
190         return num;
191     }
192 
193     /*
194      返回数据 [M, S, R] 若未安装,则返回 undefined
195      fpv 全称是 flash player version
196      */
197     UA.fpv = function (force) {
198         // 考虑 new ActiveX 和 try catch 的 性能损耗,延迟初始化到第一次调用时
199         if (force || firstRun) {
200             firstRun = false;
201             fpv = getFlashVersion();
202             fpvF = numerify(fpv);
203         }
204         return fpv;
205     };
206 
207     /*
208      Checks fpv is greater than or equal the specific version.
209      普通的 flash 版本检测推荐使用该方法
210      @param ver eg. "10.1.53"
211      <code>
212      if(S.UA.fpvGEQ('9.9.2')) { ... }
213      </code>
214      */
215     UA.fpvGEQ = function (ver, force) {
216         if (firstRun) UA.fpv(force);
217         return !!fpvF && (fpvF >= numerify(ver));
218     };
219 
220     return FlashBridge;
221 
222 }, {
223     requires:['editor', '../flashCommon/utils']
224 });