Bug 20489 Configure illegal file characters https://bugzilla.wikimedia.org/show_bug...
[mediawiki.git] / js2 / mwEmbed / binPlayers / flowplayer / flowplayer-3.0.0-rc2.js
blob52f27807648317cb876b90977bd9ad3a11c1aafb
1 /**
2  * flowplayer.js 3.0.0-rc2. The Flowplayer API.
3  * 
4  * This file is part of Flowplayer, http://flowplayer.org
5  *
6  * Author: Tero Piirainen, <support@flowplayer.org>
7  * Copyright (c) 2008 Flowplayer Ltd
8  *
9  * Released under the MIT License:
10  * http://www.opensource.org/licenses/mit-license.php
11  * 
12  * Version: 3.0.0-rc2 - Fri Nov 07 2008 16:50:59 GMT-0000 (GMT+00:00)
13  */
14 (function() {
16 /* 
17         FEATURES 
18         --------
19         - handling multiple instances 
20         - Flowplayer programming API 
21         - Flowplayer event model        
22         - player loading / unloading
23         - $f() function
24         - jQuery support
25 */ 
28 /*jslint glovar: true, browser: true */
29 /*global flowplayer, $f */
31 // {{{ private utility methods
32         
33         function log(args) {
34                 
35                 // write into opera console
36                 if (typeof opera == 'object') {
37                         opera.postError("$f.fireEvent: " + args.join(" | "));   
39                         
40                 } else if (typeof console == 'object') {
41                         console.log("$f.fireEvent", [].slice.call(args));       
42                 }
43         }
45                 
46         // thanks: http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
47         function clone(obj) {   
48                 if (!obj || typeof obj != 'object') { return obj; }             
49                 var temp = new obj.constructor();       
50                 for (var key in obj) {  
51                         if (obj.hasOwnProperty(key)) {
52                                 temp[key] = clone(obj[key]);
53                         }
54                 }               
55                 return temp;
56         }
58         // stripped from jQuery, thanks John Resig 
59         function each(obj, fn) {
60                 if (!obj) { return; }
61                 
62                 var name, i = 0, length = obj.length;
63         
64                 // object
65                 if (length === undefined) {
66                         for (name in obj) {
67                                 if (fn.call(obj[name], name, obj[name]) === false) { break; }
68                         }
69                         
70                 // array
71                 } else {
72                         for (var value = obj[0];
73                                 i < length && fn.call( value, i, value ) !== false; value = obj[++i]) {                         
74                         }
75                 }
76         
77                 return obj;
78         }
80         
81         // convenience
82         function el(id) {
83                 return document.getElementById(id);     
84         }       
86         
87         // used extensively. a very simple implementation. 
88         function extend(to, from, skipFuncs) {
89                 if (to && from) {                       
90                         each(from, function(name, value) {
91                                 if (!skipFuncs || typeof value != 'function') {
92                                         to[name] = value;               
93                                 }
94                         });
95                 }
96         }
97         
98         // var arr = select("elem.className"); 
99         function select(query) {
100                 var index = query.indexOf("."); 
101                 if (index != -1) {
102                         var tag = query.substring(0, index) || "*";
103                         var klass = query.substring(index + 1, query.length);
104                         var els = [];
105                         each(document.getElementsByTagName(tag), function() {
106                                 if (this.className && this.className.indexOf(klass) != -1) {
107                                         els.push(this);         
108                                 }
109                         });
110                         return els;
111                 }
112         }
113         
114         // fix event inconsistencies across browsers
115         function stopEvent(e) {
116                 e = e || window.event;
117                 
118                 if (e.preventDefault) {
119                         e.stopPropagation();
120                         e.preventDefault();
121                         
122                 } else {
123                         e.returnValue = false;  
124                         e.cancelBubble = true;
125                 } 
126                 return false;
127         }
129         // push an event listener into existing array of listeners
130         function bind(to, evt, fn) {
131                 to[evt] = to[evt] || [];
132                 to[evt].push(fn);               
133         }
134         
135         
136         // generates an unique id
137    function makeId() {
138           return "_" + ("" + Math.random()).substring(2, 10);   
139    }
140         
141 //}}}   
142         
144 // {{{ Clip
146         var Clip = function(json, index, player) {
147                 
148                 // private variables
149                 var self = this;
150                 var cuepoints = {};
151                 var listeners = {}; 
152                 this.index = index;
153                 
154                 // instance variables
155                 if (typeof json == 'string') {
156                         json = {url:json};      
157                 }
158         
159                 extend(this, json, true);       
160                 
161                 // event handling 
162                 each(("Start*,MetaData,Pause*,Resume*,Seek*,Stop*,Finish,LastSecond,Update,BufferFull,BufferEmpty").split(","),
163                         function() {
164                         
165                         var evt = "on" + this;
166                                 
167                         // before event
168                         if (evt.indexOf("*") != -1) {
169                                 evt = evt.substring(0, evt.length -1); 
170                                 var before = "onBefore" + evt.substring(2); 
171                                 
172                                 self[before] = function(fn) {
173                                         bind(listeners, before, fn);
174                                         return self;
175                                 };                              
176                         }  
177                         
178                         self[evt] = function(fn) {
179                                 bind(listeners, evt, fn);
180                                 return self;
181                         };
182                         
183                         
184                         // set common clip event listeners to player level
185                         if (index == -1) {
186                                 if (self[before]) {
187                                         player[before] = self[before];          
188                                 }                               
189                                 if (self[evt])  {
190                                         player[evt] = self[evt];                
191                                 }
192                         }
193                         
194                 });                       
195                 
196                 extend(this, {
197                         
198                          
199                         onCuepoint: function(points, fn) {
200                                 
201                                 // embedded cuepoints
202                                 if (arguments.length == 1) {
203                                         cuepoints.embedded = [null, points];
204                                         return self;
205                                 }
206                                 
207                                 if (typeof points == 'number') {
208                                         points = [points];      
209                                 }
210                                 
211                                 var fnId = makeId();  
212                                 cuepoints[fnId] = [points, fn]; 
213                                 
214                                 if (player.isLoaded()) {
215                                         player._api().fp_addCuepoints(points, index, fnId);     
216                                 }  
217                                 
218                                 return self;
219                         },
220                         
221                         update: function(json) {
222                                 extend(self, json);
224                                 if (player.isLoaded()) {
225                                         player._api().fp_updateClip(json, index);       
226                                 }
227                                 var conf = player._config(); 
228                                 var clip = (index == -1) ? conf.clip : conf.playlist[index];
229                                 extend(clip, json, true);
230                         },
231                         
232                         
233                         // internal event for performing clip tasks. should be made private someday
234                         _fireEvent: function(evt, arg1, arg2, target) {                                 
235                                 
236                                 if (evt == 'onLoad') { 
237                                         each(cuepoints, function(key, val) {
238                                                 player._api().fp_addCuepoints(val[0], index, key);              
239                                         }); 
240                                         return false;
241                                 }                                       
242                                 
243                                 // target clip we are working against
244                                 if (index != -1) {
245                                         target = self;  
246                                 }
247                                 
248                                 if (evt == 'onCuepoint') {
249                                         var fn = cuepoints[arg1];
250                                         if (fn) {
251                                                 return fn[1].call(player, target, arg2);
252                                         }
253                                 }  
254         
255                                 if (evt == 'onMetaData' || evt == 'onUpdate') {
256                                         
257                                         extend(target, arg1);                                   
258                                         
259                                         if (!target.duration) {
260                                                 target.duration = arg1.metaData.duration;       
261                                         } else {
262                                                 target.fullDuration = arg1.metaData.duration;   
263                                         }                                       
264                                 }  
265                                 
266                                 var ret = true;
267                                 each(listeners[evt], function() {
268                                         ret = this.call(player, target, arg1);          
269                                 }); 
270                                 return ret;                             
271                         }                       
272                         
273                 });
274                 
275                 
276                 // get cuepoints from config
277                 if (json.onCuepoint) {
278                         self.onCuepoint.apply(self, json.onCuepoint);
279                         delete json.onCuepoint;
280                 } 
281                 
282                 // get other events
283                 each(json, function(key, val) {
284                         if (typeof val == 'function') {
285                                 bind(listeners, key, val);
286                                 delete json[key];       
287                         }
288                 });
290                 
291                 // setup common clip event callbacks for Player object too (shortcuts)
292                 if (index == -1) {
293                         player.onCuepoint = this.onCuepoint;    
294                 }
295         
296         };
298 //}}}
301 // {{{ Plugin
302                 
303         var Plugin = function(name, json, player, fn) {
304         
305                 var listeners = {};
306                 var self = this;   
307                 var hasMethods = false;
308         
309                 if (fn) {
310                         extend(listeners, fn);  
311                 }   
312                 
313                 // custom callback functions in configuration
314                 each(json, function(key, val) {
315                         if (typeof val == 'function') {
316                                 listeners[key] = val;
317                                 delete json[key];       
318                         }
319                 });  
320                 
321                 // core plugin methods          
322                 extend(this, {
323   
324                         animate: function(props, speed, fn) { 
325                                 if (!props) {
326                                         return self;    
327                                 }
328                                 
329                                 if (typeof speed == 'function') { 
330                                         fn = speed; 
331                                         speed = 500;
332                                 }
333                                 
334                                 if (typeof props == 'string') {
335                                         var key = props;
336                                         props = {};
337                                         props[key] = speed;
338                                         speed = 500; 
339                                 }
340                                 
341                                 if (fn) {
342                                         var fnId = makeId();
343                                         listeners[fnId] = fn;
344                                 }
345                 
346                                 if (speed === undefined) { speed = 500; }
347                                 json = player._api().fp_animate(name, props, speed, fnId);      
348                                 return self;
349                         },
350                         
351                         css: function(props, val) {
352                                 if (val !== undefined) {
353                                         var css = {};
354                                         css[props] = val;
355                                         props = css;                                    
356                                 }
357                                 json = player._api().fp_css(name, props);
358                                 extend(self, json);
359                                 return self;
360                         },
361                         
362                         show: function() {
363                                 this.display = 'block';
364                                 player._api().fp_showPlugin(name);
365                                 return self;
366                         },
367                         
368                         hide: function() {
369                                 this.display = 'none';
370                                 player._api().fp_hidePlugin(name);
371                                 return self;
372                         },
373                         
374                         toggle: function() {
375                                 this.display = player._api().fp_togglePlugin(name);
376                                 return self;
377                         },                      
378                         
379                         fadeTo: function(o, speed, fn) {
380                                 
381                                 if (typeof speed == 'function') { 
382                                         fn = speed; 
383                                         speed = 500;
384                                 }
385                                 
386                                 if (fn) {
387                                         var fnId = makeId();
388                                         listeners[fnId] = fn;
389                                 }                               
390                                 this.display = player._api().fp_fadeTo(name, o, speed, fnId);
391                                 this.opacity = o;
392                                 return self;
393                         },
394                         
395                         fadeIn: function(speed, fn) { 
396                                 return self.fadeTo(1, speed, fn);                               
397                         },
398         
399                         fadeOut: function(speed, fn) {
400                                 return self.fadeTo(0, speed, fn);       
401                         },
402                         
403                         getName: function() {
404                                 return name;    
405                         },
406                         
407                         
408                         // internal method not meant to be used by clients
409                  _fireEvent: function(evt, arg) {
411                                 
412                         // update plugins properties & methods
413                         if (evt == 'onUpdate') {
414                            var json = arg || player._api().fp_getPlugin(name); 
415                                         if (!json) { return;    }                                       
416                                         
417                            extend(self, json);
418                            delete self.methods;
419                                         
420                            if (!hasMethods) {
421                                   each(json.methods, function() {
422                                          var method = "" + this;           
423                                                         
424                                          self[method] = function() {
425                                                 var a = [].slice.call(arguments);
426                                                 var ret = player._api().fp_invoke(name, method, a); 
427                                                 return ret == 'undefined' ? self : ret;
428                                          };
429                                   });
430                                   hasMethods = true;             
431                            }
432                         }
433                         
434                         // plugin callbacks
435                         var fn = listeners[evt];
437                                 if (fn) {
438                                         
439                                         fn.call(self, arg);
440                                         
441                                         // "one-shot" callback
442                                         if (evt.substring(0, 1) == "_") {
443                                                 delete listeners[evt];  
444                                         } 
445                         }                
446                  }                                      
447                         
448                 });
450         };
453 //}}}
456 function Player(wrapper, params, conf) {   
457                 
458         // private variables (+ arguments)
459         var 
460                 self = this, 
461                 api = null, 
462                 html, 
463                 commonClip, 
464                 playlist = [], 
465                 plugins = {},
466                 listeners = {},
467                 playerId,
468                 apiId,
469                 activeIndex,
470                 swfHeight;      
472   
473 // {{{ public methods 
474         
475         extend(self, {
476                         
477                 id: function() {
478                         return playerId;        
479                 }, 
480                 
481                 isLoaded: function() {
482                         return (api !== null);  
483                 },
484                 
485                 getParent: function() {
486                         return wrapper; 
487                 },
488                 
489                 hide: function() {
490                         if (api) { api.style.height = "0px"; } 
491                         return self;
492                 },
494                 show: function() {
495                         if (api) { api.style.height = swfHeight + "px"; }
496                         return self;
497                 }, 
498                                         
499                 isHidden: function() {
500                         return api && parseInt(api.style.height, 10) === 0;
501                 },
502                 
503                 
504                 load: function(fn) { 
505                         
506                         if (!api && self._fireEvent("onBeforeLoad") !== false) {
507                                 
508                                 // unload all instances
509                                 each(players, function()  {
510                                         this.unload();          
511                                 });
512                                 
513                                 html = wrapper.innerHTML; 
514                                 flashembed(wrapper, params, {config: conf});
515                                 
516                                 // function argument
517                                 if (fn) {
518                                         fn.cached = true;
519                                         bind(listeners, "onLoad", fn);  
520                                 }
521                         }
522                         
523                         return self;    
524                 },
525                 
526                 unload: function() {  
527                         
528                  if (api && html.replace(/\s/g, '') !== '' && !api.fp_isFullscreen() && 
529                         self._fireEvent("onBeforeUnload") !== false) { 
530                                 api.fp_close();
531                                 wrapper.innerHTML = html; 
532                                 self._fireEvent("onUnload");
533                                 api = null;
534                         }
535                         
536                         return self;
537                 },
539                 getClip: function(index) {
540                         if (index === undefined) {
541                                 index = activeIndex;    
542                         }
543                         return playlist[index];
544                 },
545                 
546                 
547                 getCommonClip: function() {
548                         return commonClip;      
549                 },              
550                 
551                 getPlaylist: function() {
552                         return playlist; 
553                 },
554                 
555           getPlugin: function(name) {  
556                  var plugin = plugins[name];
557                  
558                         // create plugin if nessessary
559                  if (!plugin && self.isLoaded()) {
560                                 var json = self._api().fp_getPlugin(name);
561                                 if (json) {
562                                         plugin = new Plugin(name, json, self);
563                                         plugins[name] = plugin;                                                 
564                                 } 
565                  }              
566                  return plugin; 
567           },
568                 
569                 getScreen: function() { 
570                         return self.getPlugin("screen");
571                 }, 
572                 
573                 getControls: function() { 
574                         return self.getPlugin("controls");
575                 }, 
577                 getConfig: function() { 
578                         return clone(conf);
579                 },
580                 
581                 getFlashParams: function() { 
582                         return params;
583                 },              
584                 
585                 loadPlugin: function(name, url, props, fn) { 
587                         // properties not supplied                      
588                         if (typeof props == 'function') { 
589                                 fn = props; 
590                                 props = {};
591                         } 
592                         
593                         // if fn not given, make a fake id so that plugin's onUpdate get's fired
594                         var fnId = fn ? makeId() : "_"; 
595                         self._api().fp_loadPlugin(name, url, props, fnId); 
596                         
597                         // create new plugin
598                         var arg = {};
599                         arg[fnId] = fn;
600                         var p = new Plugin(name, null, self, arg);
601                         plugins[name] = p;
602                         return p;                       
603                 },
604                 
605                 
606                 getState: function() {
607                         return api ? api.fp_getState() : -1;
608                 },
609                 
610                 // "lazy" play
611                 play: function(clip) {
612                         
613                         function play() {
614                                 if (clip !== undefined) {
615                                         self._api().fp_play(clip);
616                                 } else {
617                                         self._api().fp_play();  
618                                 }
619                         }
620                         
621                         if (api) {
622                                 play();
623                                 
624                         } else {
625                                 self.load(function() { 
626                                         play();
627                                 });
628                         }
629                         
630                         return self;
631                 },
632                 
633                 getVersion: function() {
634                         var js = "flowplayer.js 3.0.0-rc2";
635                         if (api) {
636                                 var ver = api.fp_getVersion();
637                                 ver.push(js);
638                                 return ver;
639                         }
640                         return js; 
641                 },
642                 
643                 _api: function() {
644                         if (!api) {
645                                 throw "Flowplayer " +self.id()+ " not loaded. Try moving your call to player's onLoad event";
646                         }
647                         return api;                             
648                 },
649                 
650                 _config: function() {
651                         return conf;    
652                 }
653                 
654         }); 
655         
656         
657         // event handlers
658         each(("Click*,Load*,Unload*,Keypress*,Volume*,Mute*,Unmute*,PlaylistReplace,Fullscreen*,FullscreenExit,Error").split(","),
659                 function() {             
660                         var name = "on" + this;
661                         
662                         // before event
663                         if (name.indexOf("*") != -1) {
664                                 name = name.substring(0, name.length -1); 
665                                 var name2 = "onBefore" + name.substring(2);
666                                 self[name2] = function(fn) {
667                                         bind(listeners, name2, fn);     
668                                         return self;
669                                 };                                              
670                         }
671                         
672                         // normal event
673                         self[name] = function(fn) {
674                                 bind(listeners, name, fn);      
675                                 return self;
676                         };                       
677                 }
678         ); 
679         
680         
681         // core API methods
682         each(("pause,resume,mute,unmute,stop,toggle,seek,getStatus,getVolume,setVolume,getTime,isPaused,isPlaying,startBuffering,stopBuffering,isFullscreen,reset").split(","),         
683                 function() {             
684                         var name = this;
685                         
686                         self[name] = function(arg) {
687                                 if (!api) { return self; }
688                                 var ret = (arg === undefined) ? api["fp_" + name]() : api["fp_" + name](arg);
689                                 return ret == 'undefined' ? self : ret;
690                         };                       
691                 }
692         );              
693         
694 //}}}
697 // {{{ public method: _fireEvent
698                 
699         self._fireEvent = function(evt, arg0, arg1, arg2) {             
700                                 
701                 if (conf.debug) {
702                         log(arguments);         
703                 }                               
704                 
705                 // internal onLoad
706                 if (evt == 'onLoad' && !api) {  
707                         
708                         api = api || el(apiId); 
709                         swfHeight = api.clientHeight;
710                         
711                         each(playlist, function() {
712                                 this._fireEvent("onLoad");              
713                         });
714                         
715                         each(plugins, function(name, p) {
716                                 p._fireEvent("onUpdate");               
717                         });
718                         
719                         
720                         commonClip._fireEvent("onLoad");  
721                 }
722                 
723           if (evt == 'onContextMenu') {
724                  each(conf.contextMenu[arg0], function(key, fn)  {
725                         fn.call(self);
726                  });
727                  return;
728           }
730                 if (evt == 'onPluginEvent') {
731                         var name = arg0.name || arg0;
732                         var p = plugins[name];
733                         if (p) {
734                                 if (arg0.name) {
735                                         p._fireEvent("onUpdate", arg0);         
736                                 }
737                                 p._fireEvent(arg1);             
738                         }
739                         return;
740                 }               
742                 // onPlaylistReplace
743                 if (evt == 'onPlaylistReplace') {
744                         playlist = [];
745                         var index = 0;
746                         each(arg0, function() {
747                                 playlist.push(new Clip(this, index++));
748                         });             
749                 }
750                 
751                 var ret = true;
752                 
753                 // clip event
754                 if (arg0 === 0 || (arg0 && arg0 >= 0)) {
755                         
756                         activeIndex = arg0;
757                         var clip = playlist[arg0];                      
758                         
759                         if (!clip || clip._fireEvent(evt, arg1, arg2) !== false) {
760                                 
761                                 // clip argument is given for common clip, because it behaves as the target
762                                 ret = commonClip._fireEvent(evt, arg1, arg2, clip);     
763                         }  
764                 } 
765                 
766                 // player event 
767                 var i = 0;
768                 each(listeners[evt], function() {
769                         ret = this.call(self, arg0);            
770                         
771                         // remove cached entry
772                         if (this.cached) {
773                                 listeners[evt].splice(i, 1);    
774                         }
775                         
776                         // break loop
777                         if (ret === false) { return false;       }
778                         i++;
779                         
780                 }); 
782                 return ret;
783         };
785 //}}}
788 // {{{ init
789         
790    function init() {
791                 
792                 if ($f(wrapper)) {
793                         return null;    
794                 }               
795                 
796                 // register this player into global array of instances
797                 players.push(self);  
798                 
799                 
800                 // flashembed parameters
801                 if (typeof params == 'string') {
802                         params = {src: params}; 
803                 }       
804                 
805                 // playerId     
806                 playerId = wrapper.id || "fp" + makeId();
807                 apiId = params.id || playerId + "_api";                 
808                 params.id = apiId;
809                 conf.playerId = playerId;
810                 
811                 
812                 // plain url is given as config
813                 if (typeof conf == 'string') {
814                         conf = {clip:{url:conf}};       
815                 } 
816                 
817                 // common clip is always there
818                 conf.clip = conf.clip || {};
819                 commonClip = new Clip(conf.clip, -1, self);  
820                 
821                 
822                 // wrapper href as playlist
823                 if (wrapper.getAttribute("href")) { 
824                         conf.playlist = [{url:wrapper.getAttribute("href", 2)}];                        
825                 } 
826                 
827                 // playlist
828                 conf.playlist = conf.playlist || [conf.clip]; 
829                 
830                 var index = 0;
831                 each(conf.playlist, function() {
833                         var clip = this;
834                         
835                         // clip is an array, we don't allow that
836                         if (typeof clip == 'object' && clip.length)  {
837                                 clip = "" + clip;       
838                         }
839                         
840                         if (!clip.url && typeof clip == 'string') {                             
841                                 clip = {url: clip};                             
842                         } 
843                         
844                         // populate common clip properties to each clip
845                         extend(clip, conf.clip, true);          
846                         
847                         // modify configuration playlist
848                         conf.playlist[index] = clip;                    
849                         
850                         // populate playlist array
851                         clip = new Clip(clip, index, self);
852                         playlist.push(clip);                                            
853                         index++;                        
854                 });
855                         
856                 
857                 // event listeners
858                 each(conf, function(key, val) {
859                         if (typeof val == 'function') {
860                                 bind(listeners, key, val);
861                                 delete conf[key];       
862                         }
863                 });              
864                 
865                 
866                 // plugins
867                 each(conf.plugins, function(name, val) {
868                         if (val) {
869                                 plugins[name] = new Plugin(name, val, self);
870                         }
871                 });
872                 
873                 
874                 // setup controlbar plugin if not explicitly defined
875                 if (!conf.plugins || conf.plugins.controls === undefined) {
876                         plugins.controls = new Plugin("controls", null, self);  
877                 } 
878                 
879                 // Flowplayer uses black background by default
880                 params.bgcolor = params.bgcolor || "#000000";
881                 
882                 
883                 // setup default settings for express install
884                 params.version = params.version || [9,0];               
885                 params.expressInstall = 'http://www.flowplayer.org/swf/expressinstall.swf';
886                 
887                 
888                 // click function
889                 function doClick(e) {
890                         if (self._fireEvent("onBeforeClick") !== false) {
891                                 self.load();            
892                         } 
893                         return stopEvent(e);                                    
894                 }
895                 
896                 // defer loading upon click
897                 html = wrapper.innerHTML;
898                 if (html.replace(/\s/g, '') !== '') {    
899                         
900                         if (wrapper.addEventListener) {
901                                 wrapper.addEventListener("click", doClick, false);      
902                                 
903                         } else if (wrapper.attachEvent) {
904                                 wrapper.attachEvent("onclick", doClick);        
905                         }
906                         
907                 // player is loaded upon page load 
908                 } else {
909                         
910                         // prevent default action from wrapper (safari problem) loaded
911                         if (wrapper.addEventListener) {
912                                 wrapper.addEventListener("click", stopEvent, false);    
913                         }
914                         
915                         // load player
916                         self.load();
917                 }
918                 
919         }
921         // possibly defer initialization until DOM get's loaded
922         if (typeof wrapper == 'string') { 
923                 flashembed.domReady(function() {
924                         var node = el(wrapper); 
925                         
926                         if (!node) {
927                                 throw "Flowplayer cannot access element: " + wrapper;   
928                         } else {
929                                 wrapper = node; 
930                                 init();                                 
931                         } 
932                 });
933                 
934         // we have a DOM element so page is already loaded
935         } else {                
936                 init();
937         }
938         
939         
940 //}}}
946 // {{{ flowplayer() & statics 
948 // container for player instances
949 var players = [];
952 // this object is returned when multiple player's are requested 
953 function Iterator(arr) {
954         
955         this.length = arr.length;
956         
957         this.each = function(fn)  {
958                 each(arr, fn);  
959         };
960         
961         this.size = function() {
962                 return arr.length;      
963         };      
966 // these two variables are the only global variables
967 window.flowplayer = window.$f = function() {
968         
969         var instance = null;
970         var arg = arguments[0]; 
971         
972         
973         // $f()
974         if (!arguments.length) {
975                 each(players, function() {
976                         if (this.isLoaded())  {
977                                 instance = this;        
978                                 return false;
979                         }
980                 });
981                 
982                 return instance || players[0];
983         } 
984         
985         if (arguments.length == 1) {
986                 
987                 // $f(index);
988                 if (typeof arg == 'number') { 
989                         return players[arg];    
990         
991                         
992                 // $f(wrapper || 'containerId' || '*');
993                 } else {
994                         
995                         // $f("*");
996                         if (arg == '*') {
997                                 return new Iterator(players);   
998                         }
999                         
1000                         // $f(wrapper || 'containerId');
1001                         each(players, function() {
1002                                 if (this.id() == arg.id || this.id() == arg || this.getParent() == arg)  {
1003                                         instance = this;        
1004                                         return false;
1005                                 }
1006                         });
1007                         
1008                         return instance;                                        
1009                 }
1010         }                       
1012         // instance builder 
1013         if (arguments.length > 1) {             
1015                 var swf = arguments[1];
1016                 var conf = (arguments.length == 3) ? arguments[2] : {};
1017                                                 
1018                 if (typeof arg == 'string') {
1019                         
1020                         // select arg by classname
1021                         if (arg.indexOf(".") != -1) {
1022                                 var instances = [];
1023                                 
1024                                 each(select(arg), function() { 
1025                                         instances.push(new Player(this, clone(swf), clone(conf)));              
1026                                 });     
1027                                 
1028                                 return new Iterator(instances);
1029                                 
1030                         // select node by id
1031                         } else {                
1032                                 var node = el(arg);
1033                                 return new Player(node !== null ? node : arg, swf, conf);       
1034                         } 
1035                         
1036                         
1037                 // arg is a DOM element
1038                 } else if (arg) {
1039                         return new Player(arg, swf, conf);                                              
1040                 }
1041                 
1042         } 
1043         
1044         return null; 
1046         
1047 extend(window.$f, {
1049         // called by Flash External Interface           
1050         fireEvent: function(id, evt, a0, a1, a2) {              
1051                 var p = $f(id);         
1052                 return p ? p._fireEvent(evt, a0, a1, a2) : null;
1053         },
1054         
1055         
1056         // create plugins by modifying Player's prototype
1057         addPlugin: function(name, fn) {
1058                 Player.prototype[name] = fn;
1059                 return $f;
1060         },
1061         
1062         // utility methods for plugin developers
1063         each: each,
1064         
1065         extend: extend
1066         
1068         
1069 //}}}
1072 //{{{ jQuery support
1074 if (typeof jQuery == 'function') {
1075         
1076         jQuery.prototype.flowplayer = function(params, conf) {  
1077                 
1078                 // select instances
1079                 if (!arguments.length || typeof arguments[0] == 'number') {
1080                         var arr = [];
1081                         this.each(function()  {
1082                                 var p = $f(this);
1083                                 if (p) {
1084                                         arr.push(p);    
1085                                 }
1086                         });
1087                         return arguments.length ? arr[arguments[0]] : new Iterator(arr);
1088                 }
1089                 
1090                 // create flowplayer instances
1091                 return this.each(function() { 
1092                         $f(this, clone(params), conf ? clone(conf) : {});       
1093                 }); 
1094                 
1095         };
1096         
1099 //}}}
1102 })();
1103 /** 
1104  * flashembed 0.33. Adobe Flash embedding script
1105  * 
1106  * http://flowplayer.org/tools/flash-embed.html
1108  * Copyright (c) 2008 Tero Piirainen (support@flowplayer.org)
1110  * Released under the MIT License:
1111  * http://www.opensource.org/licenses/mit-license.php
1112  * 
1113  * >> Basically you can do anything you want but leave this header as is <<
1115  * first version 0.01 - 03/11/2008 
1116  * version 0.33 - Mon Nov 03 2008 15:37:15 GMT-0000 (GMT+00:00)
1117  */
1118 (function() { 
1120 //{{{ utility functions 
1121                 
1122 var jQ = typeof jQuery == 'function';
1125 // from "Pro JavaScript techniques" by John Resig
1126 function isDomReady() {
1127         if (domReady.done)  { return false; }
1128         
1129         var d = document;
1130         if (d && d.getElementsByTagName && d.getElementById && d.body) {
1131                 clearInterval(domReady.timer);
1132                 domReady.timer = null;
1133                 
1134                 for (var i = 0; i < domReady.ready.length; i++) {
1135                         domReady.ready[i].call();       
1136                 }
1137                 
1138                 domReady.ready = null;
1139                 domReady.done = true;
1140         } 
1143 // if jQuery is present, use it's more effective domReady method
1144 var domReady = jQ ? jQuery : function(f) {
1145         
1146         if (domReady.done) {
1147                 return f();     
1148         }
1149         
1150         if (domReady.timer) {
1151                 domReady.ready.push(f); 
1152                 
1153         } else {
1154                 domReady.ready = [f];
1155                 domReady.timer = setInterval(isDomReady, 13);
1156         } 
1157 };      
1160 // override extend params function 
1161 function extend(to, from) {
1162         if (from) {
1163                 for (key in from) {
1164                         if (from.hasOwnProperty(key)) {
1165                                 to[key] = from[key];
1166                         }
1167                 }
1168         }
1169 }       
1172 function concatVars(vars) {             
1173         var out = "";
1174         
1175         for (var key in vars) { 
1176                 if (vars[key]) {
1177                         out += [key] + '=' + toString(vars[key]) + '&';
1178                 }
1179         }                       
1180         return out.substring(0, out.length -1);                         
1181 }  
1185 // JSON.toString() function
1186 function toString(obj) {
1188         switch (typeOf(obj)){
1189                 case 'string':
1190                         obj = obj.replace(new RegExp('(["\\\\])', 'g'), '\\$1');
1191                         
1192                         // flash does not handle %- characters well. transforms "50%" to "50pct" (a dirty hack, I admit)
1193                         obj = obj.replace(/^\s?(\d+)%/, "$1pct");
1194                         return '"' +obj+ '"';
1195                         
1196                 case 'array':
1197                         return '['+ map(obj, function(el) {
1198                                 return toString(el);
1199                         }).join(',') +']'; 
1200                         
1201                 case 'function':
1202                         return '"function()"';
1203                         
1204                 case 'object':
1205                         var str = [];
1206                         for (var prop in obj) {
1207                                 if (obj.hasOwnProperty(prop)) {
1208                                         str.push('"'+prop+'":'+ toString(obj[prop]));
1209                                 }
1210                         }
1211                         return '{'+str.join(',')+'}';
1212         }
1213         
1214         // replace ' --> "  and remove spaces
1215         return String(obj).replace(/\s/g, " ").replace(/\'/g, "\"");
1219 // private functions
1220 function typeOf(obj) {
1221         if (obj === null || obj === undefined) { return false; }
1222         var type = typeof obj;
1223         return (type == 'object' && obj.push) ? 'array' : type;
1227 // version 9 bugfix: (http://blog.deconcept.com/2006/07/28/swfobject-143-released/)
1228 if (window.attachEvent) {
1229         window.attachEvent("onbeforeunload", function() {
1230                 __flash_unloadHandler = function() {};
1231                 __flash_savedUnloadHandler = function() {};
1232         });
1235 function map(arr, func) {
1236         var newArr = []; 
1237         for (var i in arr) {
1238                 if (arr.hasOwnProperty(i)) {
1239                         newArr[i] = func(arr[i]);
1240                 }
1241         }
1242         return newArr;
1244         
1245 //}}}
1247         
1248 window.flashembed = function(root, userParams, flashvars) {     
1249         
1250         
1251 //{{{ getHTML 
1252                 
1253         function getHTML() {
1254                 
1255                 var html = "";
1256                 if (typeof flashvars == 'function') { flashvars = flashvars(); }
1257                 
1258                 
1259                 // sometimes ie fails to load flash if it's on cache
1260                 params.src += ((params.src.indexOf("?") != -1 ? "&" : "?") + Math.random());
1261                 
1262                 
1263                 // mozilla
1264                 if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) {  
1266                         html = '<embed type="application/x-shockwave-flash" ';
1268                         if (params.id) {
1269                                 extend(params, {name:params.id});
1270                         }
1271                         
1272                         for (var key in params) { 
1273                                 if (params[key] !== null) { 
1274                                         html += [key] + '="' +params[key]+ '"\n\t';
1275                                 }
1276                         }
1278                         if (flashvars) {
1279                                  html += 'flashvars=\'' + concatVars(flashvars) + '\'';
1280                         }
1281                         
1282                         // thanks Tom Price (07/17/2008)
1283                         html += '/>';
1284                         
1285                 // ie
1286                 } else { 
1288                         html = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ';
1289                         html += 'width="' + params.width + '" height="' + params.height + '"'; 
1290                         
1291                         // force id for IE. otherwise embedded Flash object cannot be returned
1292                         if (!params.id && document.all) {
1293                                 params.id = "_" + ("" + Math.random()).substring(5);
1294                         } 
1295                         
1296                         if (params.id) {
1297                                 html += ' id="' + params.id + '"';
1298                         }
1299                         
1300                         html += '>';  
1301                         html += '\n\t<param name="movie" value="'+ params.src +'" />';
1302                         
1303                         params.id = params.src = params.width = params.height = null;
1304                         
1305                         for (var k in params) {
1306                                 if (params[k] !== null) {
1307                                         html += '\n\t<param name="'+ k +'" value="'+ params[k] +'" />';
1308                                 }
1309                         }
1310                         
1311                         if (flashvars) {
1312                                 html += '\n\t<param name="flashvars" value=\'' + concatVars(flashvars) + '\' />';
1313                         }
1314                          
1315                         html += "</object>";
1316                         if (debug) { 
1317                                 alert(html);
1318                         }
1319                         
1320                 }  
1322                 return html;
1323         }
1325         //}}}
1327         
1328 //{{{ construction
1329                 
1330         // setup params
1331         var params = {
1332                 
1333                 // very common params
1334                 src: '#',
1335                 width: '100%',
1336                 height: '100%',         
1337                 
1338                 // flashembed specific options
1339                 version:null,
1340                 onFail:null,
1341                 expressInstall:null,  
1342                 debug: false,
1343                 
1344                 // flashembed defaults
1345                 // bgcolor: 'transparent',
1346                 allowfullscreen: true,
1347                 allowscriptaccess: 'always',
1348                 quality: 'high',
1349                 type: 'application/x-shockwave-flash',
1350                 pluginspage: 'http://www.adobe.com/go/getflashplayer'
1351         };
1352         
1353         
1354         if (typeof userParams == 'string') {
1355                 userParams = {src: userParams}; 
1356         }
1357         
1358         extend(params, userParams);                      
1359                 
1360         var version = flashembed.getVersion(); 
1361         var required = params.version; 
1362         var express = params.expressInstall;             
1363         var debug = params.debug;
1365         
1366         if (typeof root == 'string') {
1367                 var el = document.getElementById(root);
1368                 if (el) {
1369                         root = el;      
1370                 } else {
1371                         domReady(function() {
1372                                 flashembed(root, userParams, flashvars);
1373                         });
1374                         return;                 
1375                 } 
1376         }
1377         
1378         if (!root) { return; }
1380         
1381         // is supported 
1382         if (!required || flashembed.isSupported(required)) {
1383                 params.onFail = params.version = params.expressInstall = params.debug = null;
1384                 
1385                 // root.innerHTML may cause broplems: http://domscripting.com/blog/display/99
1386                 // thanks to: Ryan Rud
1387                 // var tmp = document.createElement("extradiv");
1388                 // tmp.innerHTML = getHTML();
1389                 // root.appendChild(tmp);
1390                 
1391                 root.innerHTML = getHTML();
1392                 
1393                 // return our API                       
1394                 return root.firstChild;
1395                 
1396         // custom fail event
1397         } else if (params.onFail) {
1398                 var ret = params.onFail.call(params, flashembed.getVersion(), flashvars);
1399                 if (ret === true) { root.innerHTML = ret; }             
1400                 
1402         // express install
1403         } else if (required && express && flashembed.isSupported([6,65])) {
1404                 
1405                 extend(params, {src: express});
1406                 
1407                 flashvars = {
1408                         MMredirectURL: location.href,
1409                         MMplayerType: 'PlugIn',
1410                         MMdoctitle: document.title
1411                 };
1412                 
1413                 root.innerHTML = getHTML();     
1414                 
1415         // not supported
1416         } else {
1418                 // minor bug fixed here 08.04.2008 (thanks JRodman)
1419                 
1420                 if (root.innerHTML.replace(/\s/g, '') !== '') {
1421                         // custom content was supplied
1422                 
1423                 } else {
1424                         root.innerHTML = 
1425                                 "<h2>Flash version " + required + " or greater is required</h2>" + 
1426                                 "<h3>" + 
1427                                         (version[0] > 0 ? "Your version is " + version : "You have no flash plugin installed") +
1428                                 "</h3>" + 
1429                                 "<p>Download latest version from <a href='" + params.pluginspage + "'>here</a></p>";
1430                 }
1431         }
1433         return root;
1434         
1435 //}}}
1436         
1437         
1441 //{{{ static methods
1443 extend(window.flashembed, {
1445         // arr[major, minor, fix]
1446         getVersion: function() {
1447         
1448                 var version = [0, 0];
1449                 
1450                 if (navigator.plugins && typeof navigator.plugins["Shockwave Flash"] == "object") {
1451                         var _d = navigator.plugins["Shockwave Flash"].description;
1452                         if (typeof _d != "undefined") {
1453                                 _d = _d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
1454                                 var _m = parseInt(_d.replace(/^(.*)\..*$/, "$1"), 10);
1455                                 var _r = /r/.test(_d) ? parseInt(_d.replace(/^.*r(.*)$/, "$1"), 10) : 0;
1456                                 version = [_m, _r];
1457                         }
1458                         
1459                 } else if (window.ActiveXObject) {
1460                         
1461                         try { // avoid fp 6 crashes
1462                                 var _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
1463                                 
1464                         } catch(e) {
1465                                 try { 
1466                                         _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");
1467                                         version = [6, 0];
1468                                         _a.AllowScriptAccess = "always"; // throws if fp < 6.47 
1469                                         
1470                                 } catch(ee) {
1471                                         if (version[0] == 6) { return; }
1472                                 }
1473                                 try {
1474                                         _a = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
1475                                 } catch(eee) {
1476                                 
1477                                 }
1478                                 
1479                         }
1480                         
1481                         if (typeof _a == "object") {
1482                                 _d = _a.GetVariable("$version"); // bugs in fp 6.21 / 6.23
1483                                 if (typeof _d != "undefined") {
1484                                         _d = _d.replace(/^\S+\s+(.*)$/, "$1").split(",");
1485                                         version = [parseInt(_d[0], 10), parseInt(_d[2], 10)];
1486                                 }
1487                         }
1488                 } 
1489                 
1490                 return version;
1491         },
1492         
1493         isSupported: function(version) {
1494                 var now = flashembed.getVersion();
1495                 var ret = (now[0] > version[0]) || (now[0] == version[0] && now[1] >= version[1]);                      
1496                 return ret;
1497         },
1498         
1499         domReady: domReady,
1500         
1501         // returns a String representation from JSON object 
1502         toString: toString
1503         
1506 //}}}
1509 // setup jquery support
1510 if (jQ) {
1511         
1512         jQuery.prototype.flashembed = function(params, flashvars) { 
1513                 return this.each(function() { 
1514                         flashembed(this, params, flashvars);
1515                 });
1516         };
1520 })();