8011fdb889aebe06cdd220e4fd85239ed1ce11a5
3 * for details see: http://metavid.org/wiki/index.php/Mv_embed
5 * All Metavid Wiki code is Released under the GPL2
6 * for more info visit http://metavid.org/wiki/Code
8 * @url http://metavid.org
11 * http://stevenlevithan.com/demo/parseuri/js/
13 * config values you can manually set the location of the mv_embed folder here
14 * (in cases where media will be hosted in a different place than the embedding page)
17 //fix multiple instances of mv_embed (ie include twice from two different servers)
19 if( MV_EMBED_VERSION
){
22 //used to grab fresh copies of scripts. (should be changed on commit)
23 var MV_EMBED_VERSION
= '1.0r19';
26 * Configuration variables (can be set from some precceding script)
27 * set up mwConfig global overide any of the defaultMwConfig values:
28 * @@ more config valuse on the way ;)
30 var defaultMwConfig
= {
32 'video_size':'400x300'
38 //install the default config values for anything not set in mwConfig
39 checkDefaultMwConfig();
41 //whether or not to load java from an iframe.
42 //note: this is necessary for remote embedding because of java security model)
44 var mv_java_iframe
= true;
46 //for when useing mv_embed with script-loader in root mediawiki path
47 var mediaWiki_mvEmbed_path
= 'js2/mwEmbed/';
49 var global_player_list
= new Array(); //the global player list per page
50 var global_req_cb
= new Array(); //the global request callback array
51 var _global
= this; //global obj
52 var mv_init_done
=false;
53 var global_cb_count
=0;
55 /*parseUri class parses URIs:*/
56 var parseUri=function(d
){var o
=parseUri
.options
,value
=o
.parser
[o
.strictMode
?"strict":"loose"].exec(d
);for(var i
=0,uri
={};i
<14;i
++){uri
[o
.key
[i
]]=value
[i
]||""}uri
[o
.q
.name
]={};uri
[o
.key
[12]].replace(o
.q
.parser
,function(a
,b
,c
){if(b
)uri
[o
.q
.name
][b
]=c
});return uri
};parseUri
.options
={strictMode
:false,key
:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q
:{name
:"queryKey",parser
:/(?:^|&)([^&=]*)=?([^&]*)/g},parser
:{strict
:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose
:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};
59 //get mv_embed location if it has not been set
61 var mv_embed_path
= getMvEmbedPath();
64 //setup the skin path:
65 var mv_jquery_skin_path
= mv_embed_path
+ 'jquery/jquery.ui/themes/redmond/';
66 var mv_skin_img_path
= mv_embed_path
+ 'skins/' + mwConfig
['skin_name'] + '/images/';
67 var mv_default_thumb_url
= mv_skin_img_path
+ 'vid_default_thumb.jpg';
70 //init the global Msg if not already
71 if(!gMsg
){var gMsg
={};}
74 function loadGM( msgSet
){
76 gMsg
[ i
] = msgSet
[i
];
80 //all default msg in [English] should be overwritten by the CMS language msg system.
82 "loading_txt":"loading <blink>...</blink>",
83 "loading_title" : "Loading...",
85 "size-gigabytes" : "$1 GB",
86 "size-megabytes" : "$1 MB",
87 "size-kilobytes" : "$1 K",
93 * AutoLoader paths (this should mirror the file: jsAutoloadLocalClasses.php )
94 * any file _not_ listed here won't be auto-loadable
95 * @path the path to the file (or set of files) with ending slash
96 * @gClasses the set of classes
97 * if an array $j.className become jquery.className.js
98 * if an asssociative object then key => value paris are used
100 if(typeof mvAutoLoadClasses
== 'undefined')
101 mvAutoLoadClasses
= {};
103 //the script that loads the classet
104 function lcPaths( classSet
){
105 for(var i
in classSet
){
106 mvAutoLoadClasses
[i
] = classSet
[i
];
110 function mvGetClassPath(k
){
111 if( mvAutoLoadClasses
[k
] ){
112 //js_log('got classpath:' + k + ' : '+ mvClassPaths[k]);
113 return mvAutoLoadClasses
[k
];
115 return js_error('could not find path for requested class ' + k
);
118 if(typeof mvCssPaths
== 'undefined')
121 function lcCssPath(cssSet
){
122 for(var i
in cssSet
){
123 mvCssPaths
[i
]= mv_embed_path
+ cssSet
[i
];
128 * -- Load Class Paths --
130 * MUST BE VALID JSON (NOT JS)
131 * is used by the scriptloader to autoLoad classes (so we only define this once for php & javascript)
133 * this is more verbose than earlier version that compressed paths
134 * but its all good gziping help compress repetative path strings
137 * right now php AutoLoader only reads this mv_embed.js file
138 * in the future we could have multiple lcPath calls that php reads
139 * (if our autoloading class list becomes too long) just have to add thouse
140 * files to the jsAutoLoader file list.
143 "mv_embed" : "mv_embed.js",
144 "window.jQuery" : "jquery/jquery-1.3.2.js",
145 "$j.fn.pngFix" : "jquery/plugins/jquery.pngFix.js",
146 "$j.fn.autocomplete": "jquery/plugins/jquery.autocomplete.js",
147 "$j.fn.hoverIntent" : "jquery/plugins/jquery.hoverIntent.js",
148 "$j.fn.datePicker" : "jquery/plugins/jquery.datePicker.js",
149 "$j.ui" : "jquery/jquery.ui/ui/ui.core.js",
150 "$j.fn.ColorPicker" : "libClipEdit/colorpicker/js/colorpicker.js",
151 "$j.Jcrop" : "libClipEdit/Jcrop/js/jquery.Jcrop.js",
152 "$j.fn.simpleUploadForm": "libAddMedia/simpleUploadForm.js",
154 "baseSkin" : "skins/baseSkin.js",
155 "kskin" : "skins/kskin/kskin.js",
156 "mvpcf" : "skins/mvpcf/mvpcf.js",
158 "$j.secureEvalJSON" : "jquery/plugins/jquery.secureEvalJSON.js",
159 "$j.cookie" : "jquery/plugins/jquery.cookie.js",
160 "$j.contextMenu" : "jquery/plugins/jquery.contextMenu.js",
162 "$j.effects.blind" : "jquery/jquery.ui/ui/effects.blind.js",
163 "$j.effects.drop" : "jquery/jquery.ui/ui/effects.drop.js",
164 "$j.effects.pulsate" : "jquery/jquery.ui/ui/effects.pulsate.js",
165 "$j.effects.transfer" : "jquery/jquery.ui/ui/effects.transfer.js",
166 "$j.ui.droppable" : "jquery/jquery.ui/ui/ui.droppable.js",
167 "$j.ui.slider" : "jquery/jquery.ui/ui/ui.slider.js",
168 "$j.effects.bounce" : "jquery/jquery.ui/ui/effects.bounce.js",
169 "$j.effects.explode" : "jquery/jquery.ui/ui/effects.explode.js",
170 "$j.effects.scale" : "jquery/jquery.ui/ui/effects.scale.js",
171 "$j.ui.datepicker" : "jquery/jquery.ui/ui/ui.datepicker.js",
172 "$j.ui.progressbar" : "jquery/jquery.ui/ui/ui.progressbar.js",
173 "$j.ui.sortable" : "jquery/jquery.ui/ui/ui.sortable.js",
174 "$j.effects.clip" : "jquery/jquery.ui/ui/effects.clip.js",
175 "$j.effects.fold" : "jquery/jquery.ui/ui/effects.fold.js",
176 "$j.effects.shake" : "jquery/jquery.ui/ui/effects.shake.js",
177 "$j.ui.dialog" : "jquery/jquery.ui/ui/ui.dialog.js",
178 "$j.ui.resizable" : "jquery/jquery.ui/ui/ui.resizable.js",
179 "$j.ui.tabs" : "jquery/jquery.ui/ui/ui.tabs.js",
180 "$j.effects.core" : "jquery/jquery.ui/ui/effects.core.js",
181 "$j.effects.highlight" : "jquery/jquery.ui/ui/effects.highlight.js",
182 "$j.effects.slide" : "jquery/jquery.ui/ui/effects.slide.js",
183 "$j.ui.accordion" : "jquery/jquery.ui/ui/ui.accordion.js",
184 "$j.ui.draggable" : "jquery/jquery.ui/ui/ui.draggable.js",
185 "$j.ui.selectable" : "jquery/jquery.ui/ui/ui.selectable.js",
187 "mvFirefogg" : "libAddMedia/mvFirefogg.js",
188 "mvAdvFirefogg" : "libAddMedia/mvAdvFirefogg.js",
189 "mvBaseUploadInterface" : "libAddMedia/mvBaseUploadInterface.js",
190 "remoteSearchDriver" : "libAddMedia/remoteSearchDriver.js",
191 "seqRemoteSearchDriver" : "libAddMedia/seqRemoteSearchDriver.js",
193 "baseRemoteSearch" : "libAddMedia/searchLibs/baseRemoteSearch.js",
194 "mediaWikiSearch" : "libAddMedia/searchLibs/mediaWikiSearch.js",
195 "metavidSearch" : "libAddMedia/searchLibs/metavidSearch.js",
196 "archiveOrgSearch" : "libAddMedia/searchLibs/archiveOrgSearch.js",
197 "baseRemoteSearch" : "libAddMedia/searchLibs/baseRemoteSearch.js",
199 "mvClipEdit" : "libClipEdit/mvClipEdit.js",
201 "embedVideo" : "libEmbedVideo/embedVideo.js",
202 "flashEmbed" : "libEmbedVideo/flashEmbed.js",
203 "genericEmbed" : "libEmbedVideo/genericEmbed.js",
204 "htmlEmbed" : "libEmbedVideo/htmlEmbed.js",
205 "javaEmbed" : "libEmbedVideo/javaEmbed.js",
206 "nativeEmbed" : "libEmbedVideo/nativeEmbed.js",
207 "quicktimeEmbed" : "libEmbedVideo/quicktimeEmbed.js",
208 "vlcEmbed" : "libEmbedVideo/vlcEmbed.js",
210 "mvPlayList" : "libSequencer/mvPlayList.js",
211 "mvSequencer" : "libSequencer/mvSequencer.js",
212 "mvFirefoggRender" : "libSequencer/mvFirefoggRender.js",
213 "mvTimedEffectsEdit": "libSequencer/mvTimedEffectsEdit.js",
215 "libTimedText" : "libTimedText/mvTextInterface.js"
219 //depencency mapping for css files for self contained included plugins:
221 '$j.Jcrop' : 'libClipEdit/Jcrop/css/jquery.Jcrop.css',
222 '$j.fn.ColorPicker' : 'libClipEdit/colorpicker/css/colorpicker.css'
226 * Language Functions:
228 * These functions try to losely mirro the functionality of Language.php in mediaWiki
230 function gM( key
, args
) {
234 if(typeof args
== 'object' || typeof args
== 'array'){
236 //msg test replace arguments start at 1 insted of zero:
237 var rep
= '\$'+ ( parseInt(v
) + 1 );
238 ms
= ms
.replace( rep
, args
[v
]);
240 }else if(typeof args
=='string' || typeof args
=='number'){
241 ms
= ms
.replace(/\$1/, args
);
245 //key is missing return indication:
246 return '<' + key
+ '>';
250 * msgSet is either a string corresponding to a single msg to load
251 * or msgSet is an array with set of msg to load
253 function gMsgLoadRemote(msgSet
, callback
){
255 if(typeof msgSet
== 'object' ){
256 for(var i
in msgSet
){
257 ammessages
+= msgSet
[i
] + '|';
259 }else if(typeof msgSet
== 'string'){
260 ammessages
+= msgSet
;
262 if(ammessages
== ''){
263 js_log('gMsgLoadRemote::no msg set requested');
268 'meta':'allmessages',
269 'ammessages':ammessages
272 if(data
.query
.allmessages
){
273 var msgs
= data
.query
.allmessages
;
276 ld
[ msgs
[i
]['name'] ] = msgs
[i
]['*'];
280 //load the result into local msg var
286 * Format a size in bytes for output, using an appropriate
287 * unit (B, KB, MB or GB) according to the magnitude in question
289 * @param size Size to format
290 * @return string Plain text (not HTML)
292 function formatSize( size
) {
293 // For small sizes no decimal places necessary
300 // For MB and bigger two decimal places are smarter
304 msg
= 'size-gigabytes';
306 msg
= 'size-megabytes';
309 msg
= 'size-kilobytes';
314 //javascript does not let you do precession points in rounding
315 var p
= Math
.pow(10,round
);
316 var size
= Math
.round( size
* p
) / p
;
317 //@@todo we need a formatNum and we need to request some special packaged info to deal with that case.
318 return gM( msg
, size
);
321 //gets the loading image:
322 function mv_get_loading_img( style
, class_attr
){
323 var style_txt
= (style
)?style
:'';
324 var class_attr
= (class_attr
)?'class="'+class_attr
+'"':'class="mv_loading_img"';
325 return '<div '+class_attr
+' style="' + style
+'"></div>';
328 function mv_set_loading(target
, load_id
){
329 var id_attr
= ( load_id
)?' id="' + load_id
+ '" ':'';
330 $j(target
).append('<div '+id_attr
+' style="position:absolute;top:0px;left:0px;height:100%;width:100%;'+
331 'background-color:#FFF;">' +
332 mv_get_loading_img('top:30px;left:30px') +
337 * mvJsLoader class handles initialization and js file loads
343 onReadyEvents
:new Array(),
344 doneReadyEvents
:false,
345 jQueryCheckFlag
:false,
346 //to keep consistency across threads:
349 load_error
:false, //load error flag (false by default)
351 callbacks
:new Array(),
354 doLoad:function(loadLibs
, callback
){
356 if( loadLibs
&& loadLibs
.length
!=0 ){ //setup this.libs:
358 //first check if we already have this lib loaded
359 var all_libs_loaded
=true;
360 for(var i
=0; i
< loadLibs
.length
; i
++){
361 //check if the lib is already loaded:
362 if( ! this.checkObjPath( loadLibs
[i
] ) ){
363 all_libs_loaded
=false;
366 if( all_libs_loaded
){
367 js_log('all libs already loaded skipping... load req');
371 //do a check for any css we may need and get it:
372 for(var i
=0; i
< loadLibs
.length
; i
++){
373 if( typeof mvCssPaths
[ loadLibs
[i
] ] != 'undefined' ){
374 loadExternalCss( mvCssPaths
[ loadLibs
[i
] ]);
378 //check if we should use the script loader to combine all the requests into one:
379 if( typeof mwSlScript
!= 'undefined' ){
383 for(var i
=0; i
< loadLibs
.length
; i
++){
384 var curLib
= loadLibs
[i
];
385 //only add if not included yet:
386 if( ! this.checkObjPath( curLib
) ){
387 class_set
+=coma
+ curLib
;
392 var puri
= parseUri( getMvEmbedURL() );
393 if( (getMvEmbedURL().indexOf('://')!=-1) && puri
.host
!= parseUri( document
.URL
).host
){
394 mwSlScript
= puri
.protocol
+ '://' + puri
.authority
+ mwSlScript
;
397 var dbug_attr
= (puri
.queryKey
['debug'])?'&debug=true':'';
398 this.libs
[ last_class
] = mwSlScript
+ '?class=' + class_set
+
399 '&urid=' + getMvUniqueReqId() + dbug_attr
;
403 for(var i
=0; i
< loadLibs
.length
; i
++){
404 var curLib
= loadLibs
[i
];
406 var libLoc
= mvGetClassPath(curLib
);
407 // do a direct load of the file (pass along unique request id from request or mv_embed Version )
408 var qmark
= (libLoc
.indexOf('?')!==true)?'?':'&';
409 this.libs
[curLib
] = mv_embed_path
+ libLoc
+ qmark
+ 'urid='+ getMvUniqueReqId();
415 this.callbacks
.push(callback
);
417 if( this.checkLoading() ){
418 if( this.load_time
++ > 1000){ //time out after ~80seconds
419 js_error( gM('error_load_lib') + this.missing_path
);
420 this.load_error
=true;
422 setTimeout( 'mvJsLoader.doLoad()', 20 );
425 //js_log('checkLoading passed run callbacks');
426 //only do callback if we are in the same instance (weird concurency issue)
428 for(var i
=0; i
< this.callbacks
.length
; i
++)
430 //js_log('REST LIBS: loading is: '+ loading + ' run callbacks: '+cb_count +' p:'+ this.ptime +' c:'+ this.ctime);
433 //js_log('done loading do call: ' + this.callbacks[0] );
434 while( this.callbacks
.length
!=0 ){
435 if( this.ptime
== ( this.ctime
-1) ){ //enforce thread consistency
436 this.callbacks
.pop()();
437 //func = this.callbacks.pop();
438 //js_log(' run: '+this.ctime+ ' p: ' + this.ptime + ' ' +loading+ ' :'+ func);
441 //re-issue doLoad ( ptime will be set to ctime so we should catch up)
442 setTimeout( 'mvJsLoader.doLoad()', 25 );
447 this.ptime
=this.ctime
;
449 doLoadFullPaths:function(loadObj
, callback
){
452 doLoadDepMode:function(loadChain
, callback
){
453 //firefox executes js ~in-order of it being included~ so just directly issue request:
454 if( $j
.browser
.firefox
){
456 for(var i
=0; i
< loadChain
.length
;i
++){
457 for(var j
=0;j
<loadChain
[i
].length
;j
++){
458 loadSet
.push(loadChain
[i
][j
]);
461 mvJsLoader
.doLoad(loadSet
, callback
);
463 //safari and IE tend to execute out of order so load with dependenciy checks
464 mvJsLoader
.doLoad(loadChain
.shift(),function(){
465 if(loadChain
.length
!=0){
466 mvJsLoader
.doLoadDepMode(loadChain
, callback
);
472 checkLoading:function(){
475 for(var i
in this.libs
){ //for in loop oky on object
476 if( !this.checkObjPath( i
) ){
478 loadExternalJs( this.libs
[i
] );
482 //js_log("has not yet loaded: " + i);
488 checkObjPath:function( libVar
){
491 var objPath
= libVar
.split('.')
493 for(var p
=0; p
< objPath
.length
; p
++){
494 cur_path
= (cur_path
=='')?cur_path
+objPath
[p
]:cur_path
+'.'+objPath
[p
];
495 eval( 'var ptest = typeof ( '+ cur_path
+ ' ); ');
496 if( ptest
== 'undefined'){
497 this.missing_path
= cur_path
;
501 this.cur_path
= cur_path
;
505 * checks for jQuery and adds the $j noConflict var
507 jQueryCheck:function(callback
){
508 //skip stuff if $j is already loaded:
509 if(_global
['$j'] && callback
)
516 _global
['$j'] = jQuery
.noConflict();
517 //set up ajax to not send dynamic urls for loading scripts (we control that with the scriptLoader)
521 js_log('jquery loaded');
522 //setup mvEmbed jquery bindigns:
530 embedVideoCheck:function( callback
){
532 js_log('embedVideoCheck:');
533 //set videonojs to loading
534 //issue a style sheet request get both mv_embed and jquery styles:
535 loadExternalCss( mv_jquery_skin_path
+ 'jquery-ui-1.7.1.custom.css' );
536 loadExternalCss( mv_embed_path
+ 'skins/'+mwConfig
['skin_name']+'/styles.css');
538 //make sure we have jQuery
539 _this
.jQueryCheck(function(){
540 $j('.videonojs').html( gM('loading_txt') );
551 //add png fix if needed:
552 if($j
.browser
.msie
|| $j
.browser
.version
< 7)
553 depReq
[0].push( '$j.fn.pngFix' );
555 _this
.doLoadDepMode(depReq
,function(){
558 $j('.videonojs').remove();
562 addLoadEvent:function(fn
){
563 this.onReadyEvents
.push(fn
);
565 //checks the jQuery flag (this way when remote embeding we don't load jQuery
566 // unless js2AddOnloadHook was used or there is video on the page
567 runQuededFunctions:function(){
569 this.doneReadyEvents
=true;
570 if(this.jQueryCheckFlag
){
571 this.jQueryCheck(function(){
572 _this
.runReadyEvents();
575 this.runReadyEvents();
578 runReadyEvents:function(){
579 js_log("runReadyEvents");
580 while( this.onReadyEvents
.length
){
581 this.onReadyEvents
.shift()();
586 //load an external JS (similar to jquery .require plugin)
587 //but checks for object availability rather than load state
589 /*********** INITIALIZATION CODE *************
590 * this will get called when DOM is ready
591 *********************************************/
592 /* jQuery .ready does not work when jQuery is loaded dynamically
593 * for an example of the problem see:1.1.3 working:http://pastie.caboo.se/92588
594 * and >= 1.1.4 not working: http://pastie.caboo.se/92595
595 * $j(document).ready( function(){ */
596 function mwdomReady(force
){
597 js_log('f:mwdomReady:');
598 if( !force
&& mv_init_done
){
599 js_log("mv_init_done already done do nothing...");
603 //handle the execution of Queded function with jQuery "ready"
605 //check if this page does have video or playlist
607 document
.getElementsByTagName("video"),
608 document
.getElementsByTagName("audio"),
609 document
.getElementsByTagName("playlist")
611 if(e
[0].length
!=0 || e
[1].length
!=0 || e
[2].length
!=0){
612 js_log('we have items to rewrite');
614 //load libs and proccess:
615 mvJsLoader
.embedVideoCheck(function(){
616 //run any queded global events:
617 mv_video_embed( function(){
618 mvJsLoader
.runQuededFunctions();
622 //if we already have jQuery make sure its loaded into its proper context $j
623 //run any queded global events:
624 mvJsLoader
.runQuededFunctions();
627 //js2AddOnloadHook: ensure jQuery and the DOM are ready:
628 function js2AddOnloadHook( func
) {
629 //make sure the skin/style sheets are avaliable always:
630 loadExternalCss( mv_jquery_skin_path
+ 'jquery-ui-1.7.1.custom.css' );
631 loadExternalCss( mv_embed_path
+ 'skins/'+mwConfig
['skin_name']+'/styles.css');
633 //if we have already run the dom ready just run the function directly:
634 if( mvJsLoader
.doneReadyEvents
){
635 //make sure jQuery is there:
636 mvJsLoader
.jQueryCheck(function(){
640 //if using js2AddOnloadHook we need to get jQuery into place (if its not already included)
641 mvJsLoader
.jQueryCheckFlag
= true;
642 mvJsLoader
.addLoadEvent( func
);
645 //depreciated mwAddOnloadHook in favor of js2 naming (for clear seperation of js2 code from old mw code
646 var mwAddOnloadHook
= js2AddOnloadHook
;
648 * this function allows for targeted rewriting
650 function rewrite_by_id( vid_id
, ready_callback
){
651 js_log('f:rewrite_by_id: ' + vid_id
);
652 //force a recheck of the dom for playlist or video element:
653 mvJsLoader
.embedVideoCheck(function(){
654 mv_video_embed(ready_callback
, vid_id
);
657 //depricated in favor of updates to oggHanlder
658 function rewrite_for_oggHanlder( vidIdList
){
659 for(var i
= 0; i
< vidIdList
.length
; i
++){
660 var vidId
= vidIdList
[i
];
661 js_log('looking at vid: ' + i
+' ' + vidId
);
662 //grab the thumbnail and src video
663 var pimg
= $j('#'+vidId
+ ' img');
664 var poster_attr
= 'poster = "' + pimg
.attr('src') + '" ';
665 var pwidth
= pimg
.attr('width');
666 var pheight
= pimg
.attr('height');
670 if( pwidth
=='22' && pheight
=='22'){
673 type_attr
= 'type="audio/ogg"';
681 var re
= new RegExp( /videoUrl(":?\s*)*([^&]*)/ );
682 src
= re
.exec( $j('#'+vidId
).html() )[2];
684 var re
= new RegExp( /length(":?\s*)*([^&]*)/ );
685 duration
= re
.exec( $j('#'+vidId
).html() )[2];
687 var re
= new RegExp( /offset(":?\s*)*([^&]*)/ );
688 offset
= re
.exec( $j('#'+vidId
).html() )[2];
689 var offset_attr
= (offset
)? 'startOffset="'+ offset
+ '"': '';
692 //replace the top div with mv_embed based player:
693 var vid_html
= '<video id="vid_' + i
+'" '+
694 'src="' + src
+ '" ' +
698 'duration="' + duration
+ '" ' +
699 'style="width:' + pwidth
+ 'px;height:' +
700 pheight
+ 'px;"></video>';
701 //js_log("video html: " + vid_html);
702 $j('#'+vidId
).html( vid_html
);
705 //rewrite that video id:
706 rewrite_by_id('vid_' + i
);
711 /*********** INITIALIZATION CODE *************
712 * set DOM ready callback to init_mv_embed
713 *********************************************/
714 // for Mozilla browsers
715 if (document
.addEventListener
) {
716 document
.addEventListener("DOMContentLoaded", function(){mwdomReady()}, false);
718 //backup "onload" method in case on DOMContentLoaded does not exist
719 window
.onload = function(){ mwdomReady() };
722 * should depreciate and use jquery.ui.dialog instead
724 function mv_write_modal(content
, speed
){
725 $j('#modalbox,#mv_overlay').remove();
726 $j('body').append('<div id="modalbox" style="background:#DDD;border:3px solid #666666;font-size:115%;'+
727 'top:30px;left:20px;right:20px;bottom:30px;position:fixed;z-index:100;">'+
730 '<div id="mv_overlay" style="background:#000;cursor:wait;height:100%;left:0;position:fixed;'+
731 'top:0;width:100%;z-index:5;filter:alpha(opacity=60);-moz-opacity: 0.6;'+
733 $j('#modalbox,#mv_overlay').show( speed
);
735 function mv_remove_modal(speed
){
736 $j('#modalbox,#mv_overlay').remove( speed
);
740 * stores all the mwEmbed jQuery specific bindings
741 * (setup after jQuery is avaliable)
742 * lets you call rewrites in a jquery "way"
744 * @@ eventually we should refactor mwCode over to jQuery style plugins
745 * and mv_embed.js will just hanndle dependency mapping and loading.
748 function mv_jqueryBindings(){
749 js_log('mv_jqueryBindings');
751 $.fn
.addMediaWiz = function( iObj
, callback
){
752 //first set the cursor for the button to "loading"
753 $j(this.selector
).css('cursor','wait').attr('title', gM('loading_title'));
755 iObj
['target_invocation'] = this.selector
;
757 //load the mv_embed_base skin:
758 loadExternalCss( mv_jquery_skin_path
+ 'jquery-ui-1.7.1.custom.css' );
759 loadExternalCss( mv_embed_path
+ 'skins/'+mwConfig
['skin_name']+'/styles.css' );
760 //load all the req libs:
761 mvJsLoader
.jQueryCheck(function(){
762 //load with staged dependeinces (for ie and safari that don't execute in order)
763 mvJsLoader
.doLoadDepMode([
764 [ 'remoteSearchDriver',
775 iObj
['instance_name']= 'rsdMVRS';
776 _global
['rsdMVRS'] = new remoteSearchDriver( iObj
);
778 callback( _global
['rsdMVRS'] );
783 $.fn
.sequencer = function( iObj
, callback
){
785 iObj
['target_sequence_container'] = this.selector
;
786 //issue a request to get the css file (if not already included):
787 loadExternalCss( mv_jquery_skin_path
+ 'jquery-ui-1.7.1.custom.css');
788 loadExternalCss( mv_embed_path
+'skins/'+mwConfig
['skin_name']+'/mv_sequence.css');
789 //make sure we have the required mv_embed libs (they are not loaded when no video element is on the page)
790 mvJsLoader
.embedVideoCheck(function(){
791 //load playlist object and then jquery ui stuff:
792 mvJsLoader
.doLoadDepMode([
812 js_log('calling new mvSequencer');
813 //init the sequence object (it will take over from there) no more than one mvSeq obj for now:
814 if(!_global
['mvSeq']){
815 _global
['mvSeq'] = new mvSequencer(iObj
);
817 js_log('mvSeq already init');
823 * the firefogg jquery function:
824 * @@note this firefogg envocation could be made to work more like real jquery plugins
826 $.fn
.firefogg = function( iObj
, callback
) {
829 //add base theme css:
830 loadExternalCss( mv_jquery_skin_path
+ 'jquery-ui-1.7.1.custom.css');
831 loadExternalCss( mv_embed_path
+ 'skins/'+mwConfig
['skin_name']+'/styles.css' );
833 //check if we already have firefogg loaded (the call just updates properties for that element)
834 var sElm
= $j(this.selector
).get(0);
835 if(sElm
['firefogg']){
836 if(sElm
['firefogg']=='loading'){
837 js_log("Error: called firefogg operations on Firefogg selector that is not done loading");
842 js_log("firefogg::updated: "+ i
+ ' to '+ iObj
[i
]);
843 sElm
['firefogg'][i
] = iObj
[i
];
845 return sElm
['firefogg'];
848 sElm
['firefogg'] = 'loading';
851 iObj
['selector'] = this.selector
;
855 'mvBaseUploadInterface',
864 if( iObj
.encoder_interface
){
873 //make sure we have everything loaded that we need:
874 mvJsLoader
.doLoadDepMode( loadSet
, function(){
875 js_log('firefogg libs loaded. target select:' + iObj
.selector
);
876 //select interface provicer based on if we want to include the encoder interface or not:
877 if(iObj
.encoder_interface
){
878 var myFogg
= new mvAdvFirefogg( iObj
);
880 var myFogg
= new mvFirefogg( iObj
);
883 myFogg
.doRewrite( callback
);
884 var selectorElement
= $j( iObj
.selector
).get(0);
885 selectorElement
['firefogg']=myFogg
;
889 //takes a input player as the selector and exposes basic rendering controls
890 $.fn
.firefoggRender = function( iObj
, callback
){
891 //check if we already have render loaded then just pass on updates/actions
892 var sElm
= $j(this.selector
).get(0);
893 if(sElm
['fogg_render']){
894 if(sElm
['fogg_render']=='loading'){
895 js_log("Error: called firefoggRender while loading");
898 //call or update the property:
900 sElm
['fogg_render']='loading';
902 iObj
['player_target'] = this.selector
;
907 sElm
['fogg_render']= new mvFirefoggRender( iObj
);
908 if( callback
&& typeof callback
== 'function' )
909 callback( sElm
['fogg_render'] );
913 $.fn
.baseUploadInterface = function(iObj
){
914 mvJsLoader
.doLoadDepMode([
916 'mvBaseUploadInterface',
924 myUp
= new mvBaseUploadInterface( iObj
);
929 //shortcut to a themed button:
930 $.btnHtml = function(msg
, className
, iconId
, opt
){
933 var href
= (opt
.href
)?opt
.href
:'#';
934 var target_attr
= (opt
.target
)?' target="' + opt
.target
+ '" ':'';
935 var style_attr
= (opt
.style
)?' style="'+opt
.style
+'" ':'';
936 return '<a href="' + href
+ '" ' + target_attr
+ style_attr
+' class="ui-state-default ui-corner-all ui-icon_link ' +
937 className
+ '"><span class="ui-icon ui-icon-' + iconId
+ '" />' +
940 //shortcut to bind hover state:
941 $.fn
.btnBind = function(){
944 $j(this).addClass('ui-state-hover');
947 $j(this).removeClass('ui-state-hover');
958 //simple url re-writer for rewriting urls (could probably be refactored into an inline regular expresion)
959 function getURLParamReplace( url
, opt
){
960 var pSrc
= parseUri( url
);
961 if(pSrc
.protocol
!= '' ){
962 var new_url
= pSrc
.protocol
+'://'+ pSrc
.authority
+ pSrc
.path
+'?';
964 var new_url
= pSrc
.path
+'?';
967 for(var key
in pSrc
.queryKey
){
968 var val
= pSrc
.queryKey
[ key
];
969 //do override if requested
972 new_url
+= amp
+ key
+ '=' + val
;
975 //add any vars that did were not originally there:
977 if(!pSrc
.queryKey
[i
]){
978 new_url
+=amp
+ i
+ '=' + opt
[i
];
985 * seconds2npt given a float seconds returns npt format response:
986 * @param float seconds
987 * @param boolean if we should show ms or not.
989 function seconds2npt(sec
, show_ms
){
991 //js_log("warning: trying to get npt time on NaN:" + sec);
994 var hours
= Math
.floor(sec
/ 3600);
995 var minutes
= Math
.floor((sec
/60) % 60);
996 var seconds
= sec
% 60;
997 //round the second amount requested significant digits
999 seconds
= Math
.round( seconds
* 1000 ) / 1000;
1001 seconds
= Math
.round( seconds
);
1004 seconds
= '0'+ seconds
;
1006 minutes
= '0' + minutes
;
1008 return hours
+":"+minutes
+":"+seconds
;
1011 * takes hh:mm:ss,ms or hh:mm:ss.ms input returns number of seconds
1013 function npt2seconds( npt_str
){
1015 //js_log('npt2seconds:not valid ntp:'+ntp);
1018 //strip npt: time definition if present
1019 npt_str
= npt_str
.replace('npt:', '');
1021 times
= npt_str
.split(':');
1022 if(times
.length
!=3){
1023 js_log('error: npt2seconds on ' + npt_str
);
1026 //sometimes the comma is used inplace of pereid for ms
1027 times
[2] = times
[2].replace(/,\s?/,'.');
1028 //return seconds float (ie take seconds float value if present):
1029 return parseInt(times
[0]*3600)+parseInt(times
[1]*60)+parseFloat(times
[2]);
1032 * simple helper to grab a edit token
1034 * @param title the wiki page title you want to edit )
1035 * @param api_url 'optional' the target api url
1036 * @param callback the callback function to pass the token or "false" to
1038 function get_mw_token( title
, api_url
, callback
){
1039 js_log(':get_mw_token:');
1040 if(!title
&& wgUserName
){
1041 title
= 'User:' + wgUserName
;
1053 for(var i
in data
.query
.pages
){
1054 if(data
.query
.pages
[i
]['edittoken']){
1055 if(typeof callback
== 'function')
1056 callback ( data
.query
.pages
[i
]['edittoken'] );
1064 //does a remote or local api request based on request url
1065 //@param options: url, data, cbParam, callback
1066 function do_api_req( options
, callback
){
1067 if(typeof options
.data
!= 'object'){
1068 return js_error('Error: request paramaters must be an object');;
1070 //gennerate the url if its missing:
1071 if( typeof options
.url
== 'undefined' || options
.url
=== false){
1072 if(!wgServer
|| ! wgScriptPath
){
1073 return js_error('Error: no api url for api request');;
1075 //update to api.php (if index.php was in the wgScript path):
1076 options
.url
= mwGetLocalApiUrl();
1078 if( typeof options
.data
== 'undefined' )
1081 //force format to json (if not already set)
1082 options
.data
['format'] = 'json';
1084 //if action not set assume query
1085 if(!options
.data
['action'])
1086 options
.data
['action']='query';
1088 js_log('do api req: ' + options
.url
+'?' + jQuery
.param(options
.data
) );
1089 //build request string:
1090 if( parseUri( document
.URL
).host
== parseUri( options
.url
).host
){
1091 //local request do api request directly
1096 dataType
:'json', //api requests _should_ always return JSON data:
1098 success:function(data
){
1102 js_error( ' error' + e
+' in getting: ' + options
.url
);
1106 //set the callback param if not already set:
1107 if( typeof options
.jsonCB
== 'undefined')
1108 options
.jsonCB
= 'callback';
1110 var req_url
= options
.url
;
1111 var paramAnd
= (req_url
.indexOf('?')==-1)?'?':'&';
1112 //put all the values into the GET req:
1113 for(var i
in options
.data
){
1114 req_url
+= paramAnd
+ encodeURIComponent( i
) + '=' + encodeURIComponent( options
.data
[i
] );
1117 var fname
= 'mycpfn_' + ( global_cb_count
++ );
1118 _global
[ fname
] = callback
;
1119 req_url
+= '&' + options
.jsonCB
+ '=' + fname
;
1120 loadExternalJs( req_url
);
1123 function mwGetLocalApiUrl(url
){
1124 if (wgServer
&& wgScriptPath
){
1125 return wgServer
+ wgScriptPath
+ '/api.php';
1129 //grab wiki form error for wiki html page proccessing (should be depricated)
1130 function grabWikiFormError ( result_page
){
1132 sp
= result_page
.indexOf('<span class="error">');
1134 se
= result_page
.indexOf('</span>', sp
);
1135 res
.error_txt
= result_page
.substr(sp
, (sp
-se
)) + '</span>';
1138 sp
= result_page
.indexOf('<ul class="warning">')
1140 se
= result_page
.indexOf('</ul>', sp
);
1141 res
.error_txt
= result_page
.substr(sp
, (se
-sp
)) + '</ul>';
1142 //try and add the ignore form item:
1143 sfp
= result_page
.indexOf('<form method="post"');
1145 sfe
= result_page
.indexOf('</form>', sfp
);
1146 res
.form_txt
= result_page
.substr(sfp
, ( sfe
- sfp
)) + '</form>';
1149 //one more error type check:
1150 sp
= result_page
.indexOf('class="mw-warning-with-logexcerpt">')
1152 se
= result_page
.indexOf('</div>', sp
);
1153 res
.error_txt
= result_page
.substr(sp
, ( se
- sp
)) + '</div>';
1159 //do a "normal" request
1160 function do_request(req_url
, callback
){
1161 js_log('do_request::req_url:' + req_url
+ ' != ' + parseUri( req_url
).host
);
1162 //if we are doing a request to the same domain or relative link do a normal GET:
1163 if( parseUri(document
.URL
).host
== parseUri(req_url
).host
||
1164 req_url
.indexOf('://') == -1 ){ //relative url
1165 //do a direct request:
1170 success:function(data
){
1175 //get data via DOM injection with callback
1176 global_req_cb
.push(callback
);
1177 //prepend json_ to feed_format if not already requesting json format
1178 if( req_url
.indexOf("feed_format=")!=-1 && req_url
.indexOf("feed_format=json")==-1)
1179 req_url
= req_url
.replace(/feed_format=/, 'feed_format=json_');
1180 loadExternalJs( req_url
+ '&cb=mv_jsdata_cb&cb_inx=' + (global_req_cb
.length
-1));
1184 function mv_jsdata_cb(response
){
1185 js_log('f:mv_jsdata_cb:'+ response
['cb_inx']);
1186 //run the callback from the global req cb object:
1187 if( !global_req_cb
[response
['cb_inx']] ){
1188 js_log('missing req cb index');
1191 if( !response
['pay_load'] ){
1192 js_log("missing pay load");
1195 //switch on content type:
1196 switch(response
['content-type']){
1200 if(typeof response
['pay_load'] == 'string'){
1201 //js_log('load string:'+"\n"+ response['pay_load']);
1203 //attempt to parse as xml for IE
1204 if( $j
.browser
.msie
){
1205 var xmldata
=new ActiveXObject("Microsoft.XMLDOM");
1206 xmldata
.async
="false";
1207 xmldata
.loadXML(response
['pay_load']);
1208 }else{ //for others (firefox, safari etc)
1210 var xmldata
= (new DOMParser()).parseFromString(response
['pay_load'], "text/xml");
1212 js_log('XML parse ERROR: ' + e
.message
);
1215 //@@todo hanndle xml parser errors
1216 if(xmldata
)response
['pay_load']=xmldata
;
1220 js_log('bad response type' + response
['content-type']);
1224 global_req_cb
[response
['cb_inx']]( response
['pay_load'] );
1226 //load external js via dom injection
1227 function loadExternalJs( url
, callback
){
1228 js_log('load js: '+ url
);
1229 //if(window['$j']) //use jquery call:
1237 var e
= document
.createElement("script");
1238 e
.setAttribute('src', url
);
1239 e
.setAttribute('type', "text/javascript");
1241 e.onload = callback;
1243 //e.setAttribute('defer', true);
1244 document
.getElementsByTagName("head")[0].appendChild(e
);
1247 function styleSheetPresent(url
){
1248 style_elements
= document
.getElementsByTagName('link');
1249 if( style_elements
.length
> 0) {
1250 for(i
= 0; i
< style_elements
.length
; i
++) {
1251 if(style_elements
[i
].href
== url
)
1257 function loadExternalCss(url
){
1258 //if could have script loader group thes css request
1259 //but debatable it may hurt more than it helps with caching and all
1260 if(typeof url
=='object'){
1262 loadExternalCss ( url
[i
] );
1267 if( url
.indexOf('?') == -1 ){
1268 url
+='?'+getMvUniqueReqId();
1270 if(!styleSheetPresent(url
) ){
1271 js_log('load css: ' + url
);
1272 var e
= document
.createElement("link");
1274 e
.type
= "text/css";
1275 e
.rel
= 'stylesheet';
1276 document
.getElementsByTagName("head")[0].appendChild(e
);
1279 function getMvEmbedURL(){
1280 if( _global
['mv_embed_url'] )
1281 return _global
['mv_embed_url'];
1282 var js_elements
= document
.getElementsByTagName("script");
1283 for(var i
=0; i
< js_elements
.length
; i
++){
1284 //check for normal mv_embed.js and or script loader
1285 var src
= js_elements
[i
].getAttribute("src");
1287 if( src
.indexOf('mv_embed.js') !=-1 || (
1288 ( src
.indexOf('mwScriptLoader.php') != -1 || src
.indexOf('jsScriptLoader.php') != -1 )
1289 && src
.indexOf('mv_embed') != -1) ){ //(check for class=mv_embed script_loader call)
1290 _global
['mv_embed_url'] = src
;
1295 js_error('Error: getMvEmbedURL failed to get Embed Path');
1298 //gets a unique request id to ensure fresh javascript
1299 function getMvUniqueReqId(){
1300 if( _global
['urid'] )
1301 return _global
['urid'];
1302 var mv_embed_url
= getMvEmbedURL();
1303 //if we have a uri retun that:
1304 var urid
= parseUri( mv_embed_url
).queryKey
['urid']
1306 _global
['urid'] = urid
;
1309 //if in debug mode get a fresh unique request key:
1310 if( parseUri( mv_embed_url
).queryKey
['debug'] == 'true'){
1312 var urid
= d
.getTime();
1313 _global
['urid'] = urid
;
1316 //else just return the mv_embed version;
1317 return MV_EMBED_VERSION
;
1320 * sets the global mv_embed path based on the scripts location
1322 function getMvEmbedPath(){
1323 if( _global
['mv_embed_path'])
1324 return _global
['mv_embed_path'];
1325 var mv_embed_url
= getMvEmbedURL();
1326 if( mv_embed_url
.indexOf('mv_embed.js') !== -1 ){
1327 mv_embed_path
= mv_embed_url
.substr(0, mv_embed_url
.indexOf('mv_embed.js'));
1328 }else if(mv_embed_url
.indexOf('mwScriptLoader.php')!==-1){
1329 //script load is in the root of mediaWiki so include the default mv_embed extention path (if using the script loader)
1330 mv_embed_path
= mv_embed_url
.substr(0, mv_embed_url
.indexOf('mwScriptLoader.php')) + mediaWiki_mvEmbed_path
;
1332 mv_embed_path
= mv_embed_url
.substr(0, mv_embed_url
.indexOf('jsScriptLoader.php'));
1334 //absolute the url (if relative) (if we don't have mv_embed path)
1335 if( mv_embed_path
.indexOf('://') == -1){
1336 var pURL
= parseUri( document
.URL
);
1337 if(mv_embed_path
.charAt(0)=='/'){
1338 mv_embed_path
= pURL
.protocol
+ '://' + pURL
.authority
+ mv_embed_path
;
1341 if(mv_embed_path
==''){
1342 mv_embed_path
= pURL
.protocol
+ '://' + pURL
.authority
+ pURL
.directory
+ mv_embed_path
;
1346 _global
['mv_embed_path'] = mv_embed_path
;
1347 return mv_embed_path
;
1350 if (typeof DOMParser
== "undefined") {
1351 DOMParser = function () {}
1352 DOMParser
.prototype.parseFromString = function (str
, contentType
) {
1353 if (typeof ActiveXObject
!= "undefined") {
1354 var d
= new ActiveXObject("MSXML.DomDocument");
1357 } else if (typeof XMLHttpRequest
!= "undefined") {
1358 var req
= new XMLHttpRequest
;
1359 req
.open("GET", "data:" + (contentType
|| "application/xml") +
1360 ";charset=utf-8," + encodeURIComponent(str
), false);
1361 if (req
.overrideMimeType
) {
1362 req
.overrideMimeType(contentType
);
1365 return req
.responseXML
;
1370 * utility functions:
1372 function js_log(string
){
1373 if( window
.console
){
1374 window
.console
.log(string
);
1377 * IE and non-firebug debug:
1379 /*var log_elm = document.getElementById('mv_js_log');
1381 document.getElementsByTagName("body")[0].innerHTML = document.getElementsByTagName("body")[0].innerHTML +
1382 '<div style="position:absolute;z-index:500;top:0px;left:0px;right:0px;height:10px;">'+
1383 '<textarea id="mv_js_log" cols="120" rows="5"></textarea>'+
1386 var log_elm = document.getElementById('mv_js_log');
1389 log_elm.value+=string+"\n";
1395 function checkDefaultMwConfig(){
1396 for(var i
in defaultMwConfig
){
1397 if(typeof(mwConfig
[i
])=='undefined'){
1398 mwConfig
[i
] =defaultMwConfig
[i
];
1403 function js_error(string
){