* initial import "kaltura skin" (yaron.s)
[lhc/web/wiklou.git] / js2 / mwEmbed / mv_embed.js
1 /*
2 * ~mv_embed ~
3 * for details see: http://metavid.org/wiki/index.php/Mv_embed
4 *
5 * All Metavid Wiki code is Released under the GPL2
6 * for more info visit http://metavid.org/wiki/Code
7 *
8 * @url http://metavid.org
9 *
10 * parseUri:
11 * http://stevenlevithan.com/demo/parseuri/js/
12 *
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)
15 *
16 */
17 //fix multiple instances of mv_embed (ie include twice from two different servers)
18 var MV_DO_INIT=true;
19 if( MV_EMBED_VERSION ){
20 MV_DO_INIT=false;
21 }
22 //used to grab fresh copies of scripts. (should be changed on commit)
23 var MV_EMBED_VERSION = '1.0r19';
24
25 /*
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 ;)
29 */
30 var defaultMwConfig = {
31 'skin_name': 'kskin',
32 'video_size':'400x300'
33 }
34
35 if(!mwConfig)
36 var mwConfig = {};
37
38 //install the default config values for anything not set in mwConfig
39 checkDefaultMwConfig();
40
41 //whether or not to load java from an iframe.
42 //note: this is necessary for remote embedding because of java security model)
43 if(!mv_java_iframe)
44 var mv_java_iframe = true;
45
46 //for when useing mv_embed with script-loader in root mediawiki path
47 var mediaWiki_mvEmbed_path = 'js2/mwEmbed/';
48
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;
54
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*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};
57
58
59 //get mv_embed location if it has not been set
60 if( !mv_embed_path ){
61 var mv_embed_path = getMvEmbedPath();
62 }
63 var jQueryUiVN = 'jquery.ui-1.7.1';
64
65
66 //setup the skin path:
67 var mv_jquery_skin_path = mv_embed_path + 'jquery/' + jQueryUiVN + '/themes/base/';
68 var mv_skin_img_path = mv_embed_path + 'skins/' + mwConfig['skin_name'] + '/images/';
69 var mv_default_thumb_url = mv_skin_img_path + 'vid_default_thumb.jpg';
70
71
72 //init the global Msg if not already
73 if(!gMsg){var gMsg={};}
74
75 //laguage msg loader:
76 function loadGM( msgSet ){
77 for(var i in msgSet){
78 gMsg[ i ] = msgSet[i];
79 }
80 }
81
82 //all default msg in [English] should be overwritten by the CMS language msg system.
83 loadGM({
84 "loading_txt":"loading <blink>...</blink>",
85 "loading_title" : "Loading...",
86
87 "size-gigabytes" : "$1 GB",
88 "size-megabytes" : "$1 MB",
89 "size-kilobytes" : "$1 K",
90 "size-bytes" : "$1 B"
91
92 });
93
94 /**
95 * AutoLoader paths (this should mirror the file: jsAutoloadLocalClasses.php )
96 * any file _not_ listed here won't be auto-loadable
97 * @path the path to the file (or set of files) with ending slash
98 * @gClasses the set of classes
99 * if an array $j.className become jquery.className.js
100 * if an asssociative object then key => value paris are used
101 */
102 if(typeof mvClassPaths == 'undefined')
103 mvClassPaths = {};
104
105 function lcPaths( path, gClasses , opt){
106 if(!opt)
107 opt = {};
108 if(typeof opt['j_replace'] == 'undefined')
109 opt['j_replace'] = 'jquery.';
110 if(!path)
111 path = '';
112 if(gClasses.length){
113 //do array loop:
114 for(var i=0; i < gClasses.length; i++){
115 if(typeof gClasses[i] != 'undefined'){
116 //setup normal replacement of j with jquery
117 var jsName = ( gClasses[i].substr(0,3) == '$j.' ) ? opt['j_replace'] + gClasses[i].substr(3) : gClasses[i];
118 mvClassPaths[ gClasses[i] ] = path + jsName + '.js';
119 }
120 }
121 }else{
122 //do object loop:
123 for(var i in gClasses){
124 //assume object with key:path:
125 mvClassPaths[i] = path + gClasses[ i ];
126 }
127 }
128 }
129 function mvGetClassPath(k){
130 if( mvClassPaths[k] ){
131 //js_log('got classpath:' + k + ' : '+ mvClassPaths[k]);
132 return mvClassPaths[k];
133 }else{
134 return js_error('could not find path for requested class ' + k );
135 }
136 }
137 if(typeof mvCssPaths == 'undefined')
138 mvCssPaths = {};
139
140 function lcCssPath(cssSet){
141 for(var i in cssSet){
142 mvCssPaths[i]= mv_embed_path + cssSet[i];
143 }
144 }
145 //core and (non-standard named files relative to class the init):
146 lcPaths('',{
147 'mv_embed' : 'mv_embed.js',
148 'window.jQuery' : 'jquery/jquery-1.3.2.js',
149 '$j.fn.pngFix' : 'jquery/plugins/jquery.pngFix.js',
150 '$j.fn.autocomplete': 'jquery/plugins/jquery.autocomplete.js',
151 '$j.fn.hoverIntent' : 'jquery/plugins/jquery.hoverIntent.js',
152 '$j.fn.datePicker' : 'jquery/plugins/jquery.datePicker.js',
153 '$j.ui' : 'jquery/jquery.ui-1.7.1/ui/ui.core.js',
154 '$j.fn.ColorPicker' : 'libClipEdit/colorpicker/js/colorpicker.js',
155 '$j.Jcrop' : 'libClipEdit/Jcrop/js/jquery.Jcrop.js',
156 '$j.fn.simpleUploadForm': 'libAddMedia/simpleUploadForm.js'
157 });
158 //query plugins
159 lcPaths( 'jquery/plugins/', [
160 '$j.secureEvalJSON',
161 '$j.cookie',
162 '$j.contextMenu'
163 ]);
164 //jquery ui
165 lcPaths('jquery/jquery.ui-1.7.1/ui/', [
166 '$j.effects.blind',
167 '$j.effects.drop',
168 '$j.effects.pulsate',
169 '$j.effects.transfer',
170 '$j.ui.droppable',
171 '$j.ui.slider',
172 '$j.effects.bounce',
173 '$j.effects.explode',
174 '$j.effects.scale',
175 '$j.ui.datepicker',
176 '$j.ui.progressbar',
177 '$j.ui.sortable',
178 '$j.effects.clip',
179 '$j.effects.fold',
180 '$j.effects.shake',
181 '$j.ui.dialog',
182 '$j.ui.resizable',
183 '$j.ui.tabs',
184 '$j.effects.core',
185 '$j.effects.highlight',
186 '$j.effects.slide',
187 '$j.ui.accordion',
188 '$j.ui.draggable',
189 '$j.ui.selectable'
190 ],
191 {'j_replace':''});
192 //add mediaLibs
193 lcPaths('libAddMedia/', [
194 'mvFirefogg',
195 'mvAdvFirefogg',
196 'mvBaseUploadInterface',
197 'remoteSearchDriver',
198 'seqRemoteSearchDriver'
199 ]);
200 //search libs:
201 lcPaths('libAddMedia/searchLibs/', [
202 'baseRemoteSearch',
203 'mediaWikiSearch',
204 'metavidSearch',
205 'archiveOrgSearch',
206 'baseRemoteSearch'
207 ]);
208 //libclip edit
209 lcPaths( 'libClipEdit/', [
210 'mvClipEdit'
211 ])
212 //libEmbedObj (we could load all these clasess in embedVideo):
213 lcPaths( 'libEmbedVideo/', [
214 'embedVideo',
215 'flashEmbed',
216 'genericEmbed',
217 'htmlEmbed',
218 'javaEmbed',
219 'nativeEmbed',
220 'quicktimeEmbed',
221 'vlcEmbed'
222 ])
223 //libSequencer:
224 lcPaths( 'libSequencer/', [
225 'mvPlayList',
226 'mvSequencer',
227 'mvFirefoggRender',
228 'mvTimedEffectsEdit'
229 ])
230 //libTimedText:
231 lcPaths( 'libTimedText/', [
232 'mvTextInterface'
233 ]);
234
235 //depencency mapping for css files for self contained included plugins:
236 lcCssPath({
237 '$j.Jcrop' : 'libClipEdit/Jcrop/css/jquery.Jcrop.css',
238 '$j.fn.ColorPicker' : 'libClipEdit/colorpicker/css/colorpicker.css'
239 })
240
241 /**
242 * Language Functions:
243 *
244 * These functions try to losely mirro the functionality of Language.php in mediaWiki
245 */
246 function gM( key , args ) {
247 var ms ='';
248 if ( key in gMsg ) {
249 ms = gMsg[ key ];
250 if(typeof args == 'object' || typeof args == 'array'){
251 for(var v in args){
252 //msg test replace arguments start at 1 insted of zero:
253 var rep = '\$'+ ( parseInt(v) + 1 );
254 ms = ms.replace( rep, args[v]);
255 }
256 }else if(typeof args =='string' || typeof args =='number'){
257 ms = ms.replace(/\$1/, args);
258 }
259 return ms;
260 } else{
261 //key is missing return indication:
262 return '&lt;' + key + '&gt;';
263 }
264 }
265 /*
266 * msgSet is either a string corresponding to a single msg to load
267 * or msgSet is an array with set of msg to load
268 */
269 function gMsgLoadRemote(msgSet, callback){
270 var ammessages = '';
271 if(typeof msgSet == 'object' ){
272 for(var i in msgSet){
273 ammessages += msgSet[i] + '|';
274 }
275 }else if(typeof msgSet == 'string'){
276 ammessages += msgSet;
277 }
278 if(ammessages == ''){
279 js_log('gMsgLoadRemote::no msg set requested');
280 return false;
281 }
282 do_api_req({
283 'data':{
284 'meta':'allmessages',
285 'ammessages':ammessages
286 }
287 },function(data){
288 if(data.query.allmessages){
289 var msgs = data.query.allmessages;
290 for(var i in msgs){
291 var ld = {};
292 ld[ msgs[i]['name'] ] = msgs[i]['*'];
293 loadGM( ld );
294 }
295 }
296 //load the result into local msg var
297 callback();
298 });
299 }
300
301 /**
302 * Format a size in bytes for output, using an appropriate
303 * unit (B, KB, MB or GB) according to the magnitude in question
304 *
305 * @param size Size to format
306 * @return string Plain text (not HTML)
307 */
308 function formatSize( size ) {
309 // For small sizes no decimal places necessary
310 var round = 0;
311 var msg = '';
312 if( size > 1024 ) {
313 size = size / 1024;
314 if( size > 1024 ) {
315 size = size / 1024;
316 // For MB and bigger two decimal places are smarter
317 round = 2;
318 if( size > 1024 ) {
319 size = size / 1024;
320 msg = 'size-gigabytes';
321 } else {
322 msg = 'size-megabytes';
323 }
324 } else {
325 msg = 'size-kilobytes';
326 }
327 } else {
328 msg = 'size-bytes';
329 }
330 //javascript does not let you do precession points in rounding
331 var p = Math.pow(10,round);
332 var size = Math.round( size * p ) / p;
333 //@@todo we need a formatNum and we need to request some special packaged info to deal with that case.
334 return gM( msg , size );
335 }
336
337 //gets the loading image:
338 function mv_get_loading_img( style , class_attr ){
339 var style_txt = (style)?style:'';
340 var class_attr = (class_attr)?'class="'+class_attr+'"':'class="mv_loading_img"';
341 return '<div '+class_attr+' style="' + style +'"></div>';
342 }
343
344 function mv_set_loading(target, load_id){
345 var id_attr = ( load_id )?' id="' + load_id + '" ':'';
346 $j(target).append('<div '+id_attr+' style="position:absolute;top:0px;left:0px;height:100%;width:100%;'+
347 'background-color:#FFF;">' +
348 mv_get_loading_img('top:30px;left:30px') +
349 '</div>');
350 }
351
352 /**
353 * mvJsLoader class handles initialization and js file loads
354 */
355 var mvJsLoader = {
356 libreq : {},
357 libs : {},
358 //base lib flags:
359 onReadyEvents:new Array(),
360 doneReadyEvents:false,
361 jQueryCheckFlag:false,
362 //to keep consistency across threads:
363 ptime:0,
364 ctime:0,
365 load_error:false, //load error flag (false by default)
366 load_time:0,
367 callbacks:new Array(),
368 cur_path: null,
369 missing_path : null,
370 doLoad:function(loadLibs, callback){
371 this.ctime++;
372 if( loadLibs && loadLibs.length!=0 ){ //setup this.libs:
373
374 //first check if we already have this lib loaded
375 var all_libs_loaded=true;
376 for(var i=0; i< loadLibs.length; i++){
377 //check if the lib is already loaded:
378 if( ! this.checkObjPath( loadLibs[i] ) ){
379 all_libs_loaded=false;
380 }
381 }
382 if( all_libs_loaded ){
383 js_log('all libs already loaded skipping... load req');
384 callback();
385 return ;
386 }
387 //do a check for any css we may need and get it:
388 for(var i=0; i< loadLibs.length; i++){
389 if( typeof mvCssPaths[ loadLibs[i] ] != 'undefined' ){
390 loadExternalCss( mvCssPaths[ loadLibs[i] ]);
391 }
392 }
393
394 //check if we should use the script loader to combine all the requests into one:
395 if( typeof mwSlScript != 'undefined' ){
396 var class_set = '';
397 var last_class = '';
398 var coma = '';
399 for(var i=0; i< loadLibs.length; i++){
400 var curLib = loadLibs[i];
401 //only add if not included yet:
402 if( ! this.checkObjPath( curLib ) ){
403 class_set+=coma + curLib ;
404 last_class=curLib;
405 coma=',';
406 }
407 }
408 var puri = parseUri( getMvEmbedURL() );
409 if( (getMvEmbedURL().indexOf('://')!=-1) && puri.host != parseUri( document.URL).host){
410 mwSlScript = puri.protocol + '://' + puri.authority + mwSlScript;
411 }
412
413 var dbug_attr = (puri.queryKey['debug'])?'&debug=true':'';
414 this.libs[ last_class ] = mwSlScript + '?class=' + class_set +
415 '&urid=' + getMvUniqueReqId() + dbug_attr;
416
417 }else{
418 //do many requests:
419 for(var i=0; i< loadLibs.length; i++){
420 var curLib = loadLibs[i];
421 if(curLib){
422 var libLoc = mvGetClassPath(curLib);
423 // do a direct load of the file (pass along unique request id from request or mv_embed Version )
424 var qmark = (libLoc.indexOf('?')!==true)?'?':'&';
425 this.libs[curLib] = mv_embed_path + libLoc + qmark + 'urid='+ getMvUniqueReqId();
426 }
427 }
428 }
429 }
430 if( callback ){
431 this.callbacks.push(callback);
432 }
433 if( this.checkLoading() ){
434 if( this.load_time++ > 1000){ //time out after ~80seconds
435 js_error( gM('error_load_lib') + this.missing_path );
436 this.load_error=true;
437 }else{
438 setTimeout( 'mvJsLoader.doLoad()', 20 );
439 }
440 }else{
441 //js_log('checkLoading passed run callbacks');
442 //only do callback if we are in the same instance (weird concurency issue)
443 var cb_count=0;
444 for(var i=0; i < this.callbacks.length; i++)
445 cb_count++;
446 //js_log('REST LIBS: loading is: '+ loading + ' run callbacks: '+cb_count +' p:'+ this.ptime +' c:'+ this.ctime);
447 //reset the libs
448 this.libs={};
449 //js_log('done loading do call: ' + this.callbacks[0] );
450 while( this.callbacks.length !=0 ){
451 if( this.ptime== ( this.ctime-1) ){ //enforce thread consistency
452 this.callbacks.pop()();
453 //func = this.callbacks.pop();
454 //js_log(' run: '+this.ctime+ ' p: ' + this.ptime + ' ' +loading+ ' :'+ func);
455 //func();
456 }else{
457 //re-issue doLoad ( ptime will be set to ctime so we should catch up)
458 setTimeout( 'mvJsLoader.doLoad()', 25 );
459 break;
460 }
461 }
462 }
463 this.ptime=this.ctime;
464 },
465 doLoadFullPaths:function(loadObj, callback){
466
467 },
468 doLoadDepMode:function(loadChain, callback){
469 //firefox executes js ~in-order of it being included~ so just directly issue request:
470 if( $j.browser.firefox ){
471 var loadSet = [];
472 for(var i=0; i< loadChain.length;i++){
473 for(var j=0;j<loadChain[i].length;j++){
474 loadSet.push(loadChain[i][j]);
475 }
476 }
477 mvJsLoader.doLoad(loadSet, callback);
478 }else{
479 //safari and IE tend to execute out of order so load with dependenciy checks
480 mvJsLoader.doLoad(loadChain.shift(),function(){
481 if(loadChain.length!=0){
482 mvJsLoader.doLoadDepMode(loadChain, callback);
483 }else{
484 callback();
485 }
486 });
487 } },
488 checkLoading:function(){
489 var loading=0;
490 var i=null;
491 for(var i in this.libs){ //for in loop oky on object
492 if( !this.checkObjPath( i ) ){
493 if(!this.libreq[i]){
494 loadExternalJs( this.libs[i] );
495 }
496
497 this.libreq[i]=1;
498 //js_log("has not yet loaded: " + i);
499 loading=1;
500 }
501 }
502 return loading;
503 },
504 checkObjPath:function( libVar ){
505 if(!libVar)
506 return false;
507 var objPath = libVar.split('.')
508 var cur_path ='';
509 for(var p=0; p < objPath.length; p++){
510 cur_path = (cur_path=='')?cur_path+objPath[p]:cur_path+'.'+objPath[p];
511 eval( 'var ptest = typeof ( '+ cur_path + ' ); ');
512 if( ptest == 'undefined'){
513 this.missing_path = cur_path;
514 return false;
515 }
516 }
517 this.cur_path = cur_path;
518 return true;
519 },
520 /**
521 * checks for jQuery and adds the $j noConflict var
522 */
523 jQueryCheck:function(callback){
524 //skip stuff if $j is already loaded:
525 if(_global['$j'] && callback)
526 callback();
527 var _this = this;
528 //load jquery
529 _this.doLoad([
530 'window.jQuery'
531 ],function(){
532 _global['$j'] = jQuery.noConflict();
533 //set up ajax to not send dynamic urls for loading scripts (we control that with the scriptLoader)
534 $j.ajaxSetup({
535 cache: true
536 });
537 js_log('jquery loaded');
538 //setup mvEmbed jquery bindigns:
539 mv_jqueryBindings();
540 //run the callback
541 if(callback){
542 callback();
543 }
544 });
545 },
546 embedVideoCheck:function( callback ){
547 var _this = this;
548 js_log('embedVideoCheck:');
549 //set videonojs to loading
550 //issue a style sheet request get both mv_embed and jquery styles:
551 loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css' );
552 loadExternalCss( mv_embed_path + 'skins/'+mwConfig['skin_name']+'/styles.css');
553
554 //make sure we have jQuery
555 _this.jQueryCheck(function(){
556 $j('.videonojs').html( gM('loading_txt') );
557 var depReq = [
558 [
559 '$j.ui',
560 'embedVideo',
561 '$j.cookie'
562 ],
563 [
564 '$j.ui.slider'
565 ]
566 ];
567 //add png fix if needed:
568 if($j.browser.msie || $j.browser.version < 7)
569 depReq[0].push( '$j.fn.pngFix' );
570
571 _this.doLoadDepMode(depReq,function(){
572 embedTypes.init();
573 callback();
574 $j('.videonojs').remove();
575 });
576 });
577 },
578 addLoadEvent:function(fn){
579 this.onReadyEvents.push(fn);
580 },
581 //checks the jQuery flag (this way when remote embeding we don't load jQuery
582 // unless js2AddOnloadHook was used or there is video on the page
583 runQuededFunctions:function(){
584 var _this = this;
585 this.doneReadyEvents=true;
586 if(this.jQueryCheckFlag){
587 this.jQueryCheck(function(){
588 _this.runReadyEvents();
589 });
590 }else{
591 this.runReadyEvents();
592 }
593 },
594 runReadyEvents:function(){
595 js_log("runReadyEvents");
596 while( this.onReadyEvents.length ){
597 this.onReadyEvents.shift()();
598 }
599 }
600
601 }
602 //load an external JS (similar to jquery .require plugin)
603 //but checks for object availability rather than load state
604
605 /*********** INITIALIZATION CODE *************
606 * this will get called when DOM is ready
607 *********************************************/
608 /* jQuery .ready does not work when jQuery is loaded dynamically
609 * for an example of the problem see:1.1.3 working:http://pastie.caboo.se/92588
610 * and >= 1.1.4 not working: http://pastie.caboo.se/92595
611 * $j(document).ready( function(){ */
612 function mwdomReady(force){
613 js_log('f:mwdomReady:');
614 if( !force && mv_init_done ){
615 js_log("mv_init_done already done do nothing...");
616 return false;
617 }
618 mv_init_done=true;
619 //handle the execution of Queded function with jQuery "ready"
620
621 //check if this page does have video or playlist
622 var e = [
623 document.getElementsByTagName("video"),
624 document.getElementsByTagName("audio"),
625 document.getElementsByTagName("playlist")
626 ];
627 if(e[0].length!=0 || e[1].length!=0 || e[2].length!=0){
628 js_log('we have items to rewrite');
629
630 //load libs and proccess:
631 mvJsLoader.embedVideoCheck(function(){
632 //run any queded global events:
633 mv_video_embed( function(){
634 mvJsLoader.runQuededFunctions();
635 });
636 });
637 }else{
638 //if we already have jQuery make sure its loaded into its proper context $j
639 //run any queded global events:
640 mvJsLoader.runQuededFunctions();
641 }
642 }
643 //js2AddOnloadHook: ensure jQuery and the DOM are ready:
644 function js2AddOnloadHook( func ) {
645 //make sure the skin/style sheets are avaliable always:
646 loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css' );
647 loadExternalCss( mv_embed_path + 'skins/'+mwConfig['skin_name']+'/styles.css');
648
649 //if we have already run the dom ready just run the function directly:
650 if( mvJsLoader.doneReadyEvents ){
651 //make sure jQuery is there:
652 mvJsLoader.jQueryCheck(function(){
653 func();
654 });
655 }else{
656 //if using js2AddOnloadHook we need to get jQuery into place (if its not already included)
657 mvJsLoader.jQueryCheckFlag = true;
658 mvJsLoader.addLoadEvent( func );
659 };
660 }
661 //depreciated mwAddOnloadHook in favor of js2 naming (for clear seperation of js2 code from old mw code
662 var mwAddOnloadHook = js2AddOnloadHook;
663 /*
664 * this function allows for targeted rewriting
665 */
666 function rewrite_by_id( vid_id, ready_callback ){
667 js_log('f:rewrite_by_id: ' + vid_id);
668 //force a recheck of the dom for playlist or video element:
669 mvJsLoader.embedVideoCheck(function(){
670 mv_video_embed(ready_callback, vid_id );
671 });
672 }
673 //depricated in favor of updates to oggHanlder
674 function rewrite_for_oggHanlder( vidIdList ){
675 for(var i = 0; i < vidIdList.length ; i++){
676 var vidId = vidIdList[i];
677 js_log('looking at vid: ' + i +' ' + vidId);
678 //grab the thumbnail and src video
679 var pimg = $j('#'+vidId + ' img');
680 var poster_attr = 'poster = "' + pimg.attr('src') + '" ';
681 var pwidth = pimg.attr('width');
682 var pheight = pimg.attr('height');
683
684 var type_attr = '';
685 //check for audio
686 if( pwidth=='22' && pheight=='22'){
687 pwidth='400';
688 pheight='300';
689 type_attr = 'type="audio/ogg"';
690 poster_attr = '';
691 }
692
693 //parsed values:
694 var src = '';
695 var duration = '';
696
697 var re = new RegExp( /videoUrl(&quot;:?\s*)*([^&]*)/ );
698 src = re.exec( $j('#'+vidId).html() )[2];
699
700 var re = new RegExp( /length(&quot;:?\s*)*([^&]*)/ );
701 duration = re.exec( $j('#'+vidId).html() )[2];
702
703 var re = new RegExp( /offset(&quot;:?\s*)*([^&]*)/ );
704 offset = re.exec( $j('#'+vidId).html() )[2];
705 var offset_attr = (offset)? 'startOffset="'+ offset + '"': '';
706
707 if( src ){
708 //replace the top div with mv_embed based player:
709 var vid_html = '<video id="vid_' + i +'" '+
710 'src="' + src + '" ' +
711 poster_attr + ' ' +
712 type_attr + ' ' +
713 offset_attr + ' ' +
714 'duration="' + duration + '" ' +
715 'style="width:' + pwidth + 'px;height:' +
716 pheight + 'px;"></video>';
717 //js_log("video html: " + vid_html);
718 $j('#'+vidId).html( vid_html );
719 }
720
721 //rewrite that video id:
722 rewrite_by_id('vid_' + i);
723 }
724 }
725
726
727 /*********** INITIALIZATION CODE *************
728 * set DOM ready callback to init_mv_embed
729 *********************************************/
730 // for Mozilla browsers
731 if (document.addEventListener ) {
732 document.addEventListener("DOMContentLoaded", function(){mwdomReady()}, false);
733 }else{
734 //backup "onload" method in case on DOMContentLoaded does not exist
735 window.onload = function(){ mwdomReady() };
736 }
737 /*
738 * should depreciate and use jquery.ui.dialog instead
739 */
740 function mv_write_modal(content, speed){
741 $j('#modalbox,#mv_overlay').remove();
742 $j('body').append('<div id="modalbox" style="background:#DDD;border:3px solid #666666;font-size:115%;'+
743 'top:30px;left:20px;right:20px;bottom:30px;position:fixed;z-index:100;">'+
744 content +
745 '</div>'+
746 '<div id="mv_overlay" style="background:#000;cursor:wait;height:100%;left:0;position:fixed;'+
747 'top:0;width:100%;z-index:5;filter:alpha(opacity=60);-moz-opacity: 0.6;'+
748 'opacity: 0.6;"/>');
749 $j('#modalbox,#mv_overlay').show( speed );
750 }
751 function mv_remove_modal(speed){
752 $j('#modalbox,#mv_overlay').remove( speed);
753 }
754
755 /*
756 * stores all the mwEmbed jQuery specific bindings
757 * (setup after jQuery is avaliable)
758 * lets you call rewrites in a jquery "way"
759 *
760 * @@ eventually we should refactor mwCode over to jQuery style plugins
761 * and mv_embed.js will just hanndle dependency mapping and loading.
762 *
763 */
764 function mv_jqueryBindings(){
765 js_log('mv_jqueryBindings');
766 (function($) {
767 $.fn.addMediaWiz = function( iObj, callback ){
768 //first set the cursor for the button to "loading"
769 $j(this.selector).css('cursor','wait').attr('title', gM('loading_title'));
770
771 iObj['target_invocation'] = this.selector;
772
773 //load the mv_embed_base skin:
774 loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css' );
775 loadExternalCss( mv_embed_path + 'skins/'+mwConfig['skin_name']+'/styles.css' );
776 //load all the req libs:
777 mvJsLoader.jQueryCheck(function(){
778 //load with staged dependeinces (for ie and safari that don't execute in order)
779 mvJsLoader.doLoadDepMode([
780 [ 'remoteSearchDriver',
781 '$j.cookie',
782 '$j.ui'
783 ],[
784 '$j.ui.resizable',
785 '$j.ui.draggable',
786 '$j.ui.dialog',
787 '$j.ui.tabs',
788 '$j.ui.sortable'
789 ]
790 ], function(){
791 iObj['instance_name']= 'rsdMVRS';
792 _global['rsdMVRS'] = new remoteSearchDriver( iObj );
793 if( callback ){
794 callback( _global['rsdMVRS'] );
795 }
796 });
797 });
798 }
799 $.fn.sequencer = function( iObj, callback){
800 //debugger;
801 iObj['target_sequence_container'] = this.selector;
802 //issue a request to get the css file (if not already included):
803 loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css');
804 loadExternalCss( mv_embed_path+'skins/'+mwConfig['skin_name']+'/mv_sequence.css');
805 //make sure we have the required mv_embed libs (they are not loaded when no video element is on the page)
806 mvJsLoader.embedVideoCheck(function(){
807 //load playlist object and then jquery ui stuff:
808 mvJsLoader.doLoadDepMode([
809 [
810 'mvPlayList',
811 '$j.ui',
812 '$j.contextMenu',
813 '$j.secureEvalJSON',
814 'mvSequencer'
815 ],
816 [
817 '$j.ui.accordion',
818 '$j.ui.dialog',
819 '$j.ui.droppable',
820 '$j.ui.draggable',
821 '$j.ui.progressbar',
822 '$j.ui.sortable',
823 '$j.ui.resizable',
824 '$j.ui.slider',
825 '$j.ui.tabs'
826 ]
827 ], function(){
828 js_log('calling new mvSequencer');
829 //init the sequence object (it will take over from there) no more than one mvSeq obj for now:
830 if(!_global['mvSeq']){
831 _global['mvSeq'] = new mvSequencer(iObj);
832 }else{
833 js_log('mvSeq already init');
834 }
835 });
836 });
837 }
838 /*
839 * the firefogg jquery function:
840 * @@note this firefogg envocation could be made to work more like real jquery plugins
841 */
842 $.fn.firefogg = function( iObj, callback ) {
843 if(!iObj)
844 iObj={};
845 //add base theme css:
846 loadExternalCss( mv_jquery_skin_path + 'jquery-ui-1.7.1.custom.css');
847 loadExternalCss( mv_embed_path + 'skins/'+mwConfig['skin_name']+'/styles.css' );
848
849 //check if we already have firefogg loaded (the call just updates properties for that element)
850 var sElm = $j(this.selector).get(0);
851 if(sElm['firefogg']){
852 if(sElm['firefogg']=='loading'){
853 js_log("Error: called firefogg operations on Firefogg selector that is not done loading");
854 return false;
855 }
856 //update properties:
857 for(var i in iObj){
858 js_log("firefogg::updated: "+ i + ' to '+ iObj[i]);
859 sElm['firefogg'][i] = iObj[i];
860 }
861 return sElm['firefogg'];
862 }else{
863 //avoid concurency
864 sElm['firefogg'] = 'loading';
865 }
866 //add the selector:
867 iObj['selector'] = this.selector;
868
869 var loadSet = [
870 [
871 'mvBaseUploadInterface',
872 'mvFirefogg',
873 '$j.ui'
874 ],
875 [
876 '$j.ui.progressbar',
877 '$j.ui.dialog'
878 ]
879 ];
880 if( iObj.encoder_interface ){
881 loadSet.push([
882 'mvAdvFirefogg',
883 '$j.cookie',
884 '$j.ui.accordion',
885 '$j.ui.slider',
886 '$j.ui.datepicker'
887 ]);
888 }
889 //make sure we have everything loaded that we need:
890 mvJsLoader.doLoadDepMode( loadSet, function(){
891 js_log('firefogg libs loaded. target select:' + iObj.selector);
892 //select interface provicer based on if we want to include the encoder interface or not:
893 if(iObj.encoder_interface){
894 var myFogg = new mvAdvFirefogg( iObj );
895 }else{
896 var myFogg = new mvFirefogg( iObj );
897 }
898 if(myFogg){
899 myFogg.doRewrite( callback );
900 var selectorElement = $j( iObj.selector ).get(0);
901 selectorElement['firefogg']=myFogg;
902 }
903 });
904 }
905 //takes a input player as the selector and exposes basic rendering controls
906 $.fn.firefoggRender = function( iObj, callback ){
907 //check if we already have render loaded then just pass on updates/actions
908 var sElm = $j(this.selector).get(0);
909 if(sElm['fogg_render']){
910 if(sElm['fogg_render']=='loading'){
911 js_log("Error: called firefoggRender while loading");
912 return false;
913 }
914 //call or update the property:
915 }
916 sElm['fogg_render']='loading';
917 //add the selector:
918 iObj['player_target'] = this.selector;
919 mvJsLoader.doLoad([
920 'mvFirefogg',
921 'mvFirefoggRender'
922 ],function(){
923 sElm['fogg_render']= new mvFirefoggRender( iObj );
924 if( callback && typeof callback == 'function' )
925 callback( sElm['fogg_render'] );
926 });
927 }
928
929 $.fn.baseUploadInterface = function(iObj){
930 mvJsLoader.doLoadDepMode([
931 [
932 'mvBaseUploadInterface',
933 '$j.ui',
934 ],
935 [
936 '$j.ui.progressbar',
937 '$j.ui.dialog'
938 ]
939 ],function(){
940 myUp = new mvBaseUploadInterface( iObj );
941 myUp.setupForm();
942 });
943 }
944
945 //shortcut to a themed button:
946 $.btnHtml = function(msg, className, iconId, opt){
947 if(!opt)
948 opt = {};
949 var href = (opt.href)?opt.href:'#';
950 var target_attr = (opt.target)?' target="' + opt.target + '" ':'';
951 var style_attr = (opt.style)?' style="'+opt.style +'" ':'';
952 return '<a href="' + href + '" ' + target_attr + style_attr +' class="ui-state-default ui-corner-all ui-icon_link ' +
953 className + '"><span class="ui-icon ui-icon-' + iconId + '" />' +
954 msg + '</a>';
955 }
956 //shortcut to bind hover state:
957 $.fn.btnBind = function(){
958 $j(this).hover(
959 function(){
960 $j(this).addClass('ui-state-hover');
961 },
962 function(){
963 $j(this).removeClass('ui-state-hover');
964 }
965 )
966 return this;
967 }
968
969 })(jQuery);
970 }
971 /*
972 * utility functions:
973 */
974 //simple url re-writer for rewriting urls (could probably be refactored into an inline regular expresion)
975 function getURLParamReplace( url, opt ){
976 var pSrc = parseUri( url );
977 if(pSrc.protocol != '' ){
978 var new_url = pSrc.protocol +'://'+ pSrc.authority + pSrc.path +'?';
979 }else{
980 var new_url = pSrc.path +'?';
981 }
982 var amp = '';
983 for(var key in pSrc.queryKey){
984 var val = pSrc.queryKey[ key ];
985 //do override if requested
986 if( opt[ key ] )
987 val = opt[ key ];
988 new_url+= amp + key + '=' + val;
989 amp = '&';
990 };
991 //add any vars that did were not originally there:
992 for(var i in opt){
993 if(!pSrc.queryKey[i]){
994 new_url+=amp + i + '=' + opt[i];
995 amp = '&';
996 }
997 }
998 return new_url;
999 }
1000 /**
1001 * seconds2npt given a float seconds returns npt format response:
1002 * @param float seconds
1003 * @param boolean if we should show ms or not.
1004 */
1005 function seconds2npt(sec, show_ms){
1006 if( isNaN( sec ) ){
1007 //js_log("warning: trying to get npt time on NaN:" + sec);
1008 return '0:0:0';
1009 }
1010 var hours = Math.floor(sec/ 3600);
1011 var minutes = Math.floor((sec/60) % 60);
1012 var seconds = sec % 60;
1013 //round the second amount requested significant digits
1014 if(show_ms){
1015 seconds = Math.round( seconds * 1000 ) / 1000;
1016 }else{
1017 seconds = Math.round( seconds );
1018 }
1019 if(seconds <10 )
1020 seconds = '0'+ seconds;
1021 if(minutes < 10 )
1022 minutes = '0' + minutes;
1023
1024 return hours+":"+minutes+":"+seconds;
1025 }
1026 /*
1027 * takes hh:mm:ss,ms or hh:mm:ss.ms input returns number of seconds
1028 */
1029 function npt2seconds( npt_str ){
1030 if(!npt_str){
1031 //js_log('npt2seconds:not valid ntp:'+ntp);
1032 return false;
1033 }
1034 //strip npt: time definition if present
1035 npt_str = npt_str.replace('npt:', '');
1036
1037 times = npt_str.split(':');
1038 if(times.length!=3){
1039 js_log('error: npt2seconds on ' + npt_str);
1040 return false;
1041 }
1042 //sometimes the comma is used inplace of pereid for ms
1043 times[2] = times[2].replace(/,\s?/,'.');
1044 //return seconds float (ie take seconds float value if present):
1045 return parseInt(times[0]*3600)+parseInt(times[1]*60)+parseFloat(times[2]);
1046 }
1047 /*
1048 * simple helper to grab a edit token
1049 *
1050 * @param title the wiki page title you want to edit )
1051 * @param api_url 'optional' the target api url
1052 * @param callback the callback function to pass the token or "false" to
1053 */
1054 function get_mw_token( title, api_url, callback){
1055 js_log(':get_mw_token:');
1056 if(!title && wgUserName){
1057 title = 'User:' + wgUserName;
1058 }
1059 var reqObj = {
1060 'action':'query',
1061 'prop':'info',
1062 'intoken':'edit',
1063 'titles':title
1064 };
1065 do_api_req( {
1066 'data': reqObj,
1067 'url' : api_url
1068 },function(data){
1069 for(var i in data.query.pages){
1070 if(data.query.pages[i]['edittoken']){
1071 if(typeof callback == 'function')
1072 callback ( data.query.pages[i]['edittoken'] );
1073 }
1074 }
1075 //no token found:
1076 return false;
1077 }
1078 );
1079 }
1080 //does a remote or local api request based on request url
1081 //@param options: url, data, cbParam, callback
1082 function do_api_req( options, callback ){
1083 if(typeof options.data != 'object'){
1084 return js_error('Error: request paramaters must be an object');;
1085 }
1086 //gennerate the url if its missing:
1087 if( typeof options.url == 'undefined' || options.url === false){
1088 if(!wgServer || ! wgScriptPath){
1089 return js_error('Error: no api url for api request');;
1090 }
1091 //update to api.php (if index.php was in the wgScript path):
1092 options.url = mwGetLocalApiUrl();
1093 }
1094 if( typeof options.data == 'undefined' )
1095 options.data = {};
1096
1097 //force format to json (if not already set)
1098 options.data['format'] = 'json';
1099
1100 //if action not set assume query
1101 if(!options.data['action'])
1102 options.data['action']='query';
1103
1104 js_log('do api req: ' + options.url +'?' + jQuery.param(options.data) );
1105 //build request string:
1106 if( parseUri( document.URL ).host == parseUri( options.url ).host ){
1107 //local request do api request directly
1108 $j.ajax({
1109 type: "POST",
1110 url: options.url,
1111 data: options.data,
1112 dataType:'json', //api requests _should_ always return JSON data:
1113 async: false,
1114 success:function(data){
1115 callback( data );
1116 },
1117 error:function(e){
1118 js_error( ' error' + e +' in getting: ' + options.url);
1119 }
1120 });
1121 }else{
1122 //set the callback param if not already set:
1123 if( typeof options.jsonCB == 'undefined')
1124 options.jsonCB = 'callback';
1125
1126 var req_url = options.url;
1127 var paramAnd = (req_url.indexOf('?')==-1)?'?':'&';
1128 //put all the values into the GET req:
1129 for(var i in options.data){
1130 req_url += paramAnd + encodeURIComponent( i ) + '=' + encodeURIComponent( options.data[i] );
1131 paramAnd ='&';
1132 }
1133 var fname = 'mycpfn_' + ( global_cb_count++ );
1134 _global[ fname ] = callback;
1135 req_url += '&' + options.jsonCB + '=' + fname;
1136 loadExternalJs( req_url );
1137 }
1138 }
1139 function mwGetLocalApiUrl(url){
1140 if (wgServer && wgScriptPath){
1141 return wgServer + wgScriptPath + '/api.php';
1142 }
1143 return false;
1144 }
1145 //grab wiki form error for wiki html page proccessing (should be depricated)
1146 function grabWikiFormError ( result_page ){
1147 var res = {};
1148 sp = result_page.indexOf('<span class="error">');
1149 if(sp!=-1){
1150 se = result_page.indexOf('</span>', sp);
1151 res.error_txt = result_page.substr(sp, (sp-se)) + '</span>';
1152 }else{
1153 //look for warning:
1154 sp = result_page.indexOf('<ul class="warning">')
1155 if(sp != -1){
1156 se = result_page.indexOf('</ul>', sp);
1157 res.error_txt = result_page.substr(sp, (se-sp)) + '</ul>';
1158 //try and add the ignore form item:
1159 sfp = result_page.indexOf('<form method="post"');
1160 if(sfp!=-1){
1161 sfe = result_page.indexOf('</form>', sfp);
1162 res.form_txt = result_page.substr(sfp, ( sfe - sfp )) + '</form>';
1163 }
1164 }else{
1165 //one more error type check:
1166 sp = result_page.indexOf('class="mw-warning-with-logexcerpt">')
1167 if(sp!=-1){
1168 se = result_page.indexOf('</div>', sp);
1169 res.error_txt = result_page.substr(sp, ( se - sp )) + '</div>';
1170 }
1171 }
1172 }
1173 return res;
1174 }
1175 //do a "normal" request
1176 function do_request(req_url, callback){
1177 js_log('do_request::req_url:' + req_url + ' != ' + parseUri( req_url).host);
1178 //if we are doing a request to the same domain or relative link do a normal GET:
1179 if( parseUri(document.URL).host == parseUri(req_url).host ||
1180 req_url.indexOf('://') == -1 ){ //relative url
1181 //do a direct request:
1182 $j.ajax({
1183 type: "GET",
1184 url:req_url,
1185 async: false,
1186 success:function(data){
1187 callback( data );
1188 }
1189 });
1190 }else{
1191 //get data via DOM injection with callback
1192 global_req_cb.push(callback);
1193 //prepend json_ to feed_format if not already requesting json format
1194 if( req_url.indexOf("feed_format=")!=-1 && req_url.indexOf("feed_format=json")==-1)
1195 req_url = req_url.replace(/feed_format=/, 'feed_format=json_');
1196 loadExternalJs( req_url + '&cb=mv_jsdata_cb&cb_inx=' + (global_req_cb.length-1));
1197 }
1198 }
1199
1200 function mv_jsdata_cb(response){
1201 js_log('f:mv_jsdata_cb:'+ response['cb_inx']);
1202 //run the callback from the global req cb object:
1203 if( !global_req_cb[response['cb_inx']] ){
1204 js_log('missing req cb index');
1205 return false;
1206 }
1207 if( !response['pay_load'] ){
1208 js_log("missing pay load");
1209 return false;
1210 }
1211 //switch on content type:
1212 switch(response['content-type']){
1213 case 'text/plain':
1214 break;
1215 case 'text/xml':
1216 if(typeof response['pay_load'] == 'string'){
1217 //js_log('load string:'+"\n"+ response['pay_load']);
1218 //debugger;
1219 //attempt to parse as xml for IE
1220 if( $j.browser.msie ){
1221 var xmldata=new ActiveXObject("Microsoft.XMLDOM");
1222 xmldata.async="false";
1223 xmldata.loadXML(response['pay_load']);
1224 }else{ //for others (firefox, safari etc)
1225 try{
1226 var xmldata = (new DOMParser()).parseFromString(response['pay_load'], "text/xml");
1227 }catch(e) {
1228 js_log('XML parse ERROR: ' + e.message);
1229 }
1230 }
1231 //@@todo hanndle xml parser errors
1232 if(xmldata)response['pay_load']=xmldata;
1233 }
1234 break
1235 default:
1236 js_log('bad response type' + response['content-type']);
1237 return false;
1238 break;
1239 }
1240 global_req_cb[response['cb_inx']]( response['pay_load'] );
1241 }
1242 //load external js via dom injection
1243 function loadExternalJs( url, callback ){
1244 js_log('load js: '+ url);
1245 //if(window['$j']) //use jquery call:
1246 /*$j.ajax({
1247 type: "GET",
1248 url: url,
1249 dataType: 'script',
1250 cache: true
1251 });*/
1252 // else{
1253 var e = document.createElement("script");
1254 e.setAttribute('src', url);
1255 e.setAttribute('type', "text/javascript");
1256 /*if(callback)
1257 e.onload = callback;
1258 */
1259 //e.setAttribute('defer', true);
1260 document.getElementsByTagName("head")[0].appendChild(e);
1261 // }
1262 }
1263 function styleSheetPresent(url){
1264 style_elements = document.getElementsByTagName('link');
1265 if( style_elements.length > 0) {
1266 for(i = 0; i < style_elements.length; i++) {
1267 if(style_elements[i].href == url)
1268 return true;
1269 }
1270 }
1271 return false;
1272 }
1273 function loadExternalCss(url){
1274 //if could have script loader group thes css request
1275 //but debatable it may hurt more than it helps with caching and all
1276 if(typeof url =='object'){
1277 for(var i in url){
1278 loadExternalCss ( url[i] );
1279 }
1280 return ;
1281 }
1282
1283 if( url.indexOf('?') == -1 ){
1284 url+='?'+getMvUniqueReqId();
1285 }
1286 if(!styleSheetPresent(url) ){
1287 js_log('load css: ' + url);
1288 var e = document.createElement("link");
1289 e.href = url;
1290 e.type = "text/css";
1291 e.rel = 'stylesheet';
1292 document.getElementsByTagName("head")[0].appendChild(e);
1293 }
1294 }
1295 function getMvEmbedURL(){
1296 if( _global['mv_embed_url'] )
1297 return _global['mv_embed_url'];
1298 var js_elements = document.getElementsByTagName("script");
1299 for(var i=0; i < js_elements.length; i++){
1300 //check for normal mv_embed.js and or script loader
1301 var src = js_elements[i].getAttribute("src");
1302 if( src ){
1303 if( src.indexOf('mv_embed.js') !=-1 || (
1304 ( src.indexOf('mwScriptLoader.php') != -1 || src.indexOf('jsScriptLoader.php') != -1 )
1305 && src.indexOf('mv_embed') != -1) ){ //(check for class=mv_embed script_loader call)
1306 _global['mv_embed_url'] = src;
1307 return src;
1308 }
1309 }
1310 }
1311 js_error('Error: getMvEmbedURL failed to get Embed Path');
1312 return false;
1313 }
1314 //gets a unique request id to ensure fresh javascript
1315 function getMvUniqueReqId(){
1316 if( _global['urid'] )
1317 return _global['urid'];
1318 var mv_embed_url = getMvEmbedURL();
1319 //if we have a uri retun that:
1320 var urid = parseUri( mv_embed_url).queryKey['urid']
1321 if( urid ){
1322 _global['urid'] = urid;
1323 return urid;
1324 }
1325 //if in debug mode get a fresh unique request key:
1326 if( parseUri( mv_embed_url ).queryKey['debug'] == 'true'){
1327 var d = new Date();
1328 var urid = d.getTime();
1329 _global['urid'] = urid;
1330 return urid;
1331 }
1332 //else just return the mv_embed version;
1333 return MV_EMBED_VERSION;
1334 }
1335 /*
1336 * sets the global mv_embed path based on the scripts location
1337 */
1338 function getMvEmbedPath(){
1339 if( _global['mv_embed_path'])
1340 return _global['mv_embed_path'];
1341 var mv_embed_url = getMvEmbedURL();
1342 if( mv_embed_url.indexOf('mv_embed.js') !== -1 ){
1343 mv_embed_path = mv_embed_url.substr(0, mv_embed_url.indexOf('mv_embed.js'));
1344 }else if(mv_embed_url.indexOf('mwScriptLoader.php')!==-1){
1345 //script load is in the root of mediaWiki so include the default mv_embed extention path (if using the script loader)
1346 mv_embed_path = mv_embed_url.substr(0, mv_embed_url.indexOf('mwScriptLoader.php')) + mediaWiki_mvEmbed_path ;
1347 }else{
1348 mv_embed_path = mv_embed_url.substr(0, mv_embed_url.indexOf('jsScriptLoader.php'));
1349 }
1350 //absolute the url (if relative) (if we don't have mv_embed path)
1351 if( mv_embed_path.indexOf('://') == -1){
1352 var pURL = parseUri( document.URL );
1353 if(mv_embed_path.charAt(0)=='/'){
1354 mv_embed_path = pURL.protocol + '://' + pURL.authority + mv_embed_path;
1355 }else{
1356 //relative:
1357 if(mv_embed_path==''){
1358 mv_embed_path = pURL.protocol + '://' + pURL.authority + pURL.directory + mv_embed_path;
1359 }
1360 }
1361 }
1362 _global['mv_embed_path'] = mv_embed_path;
1363 return mv_embed_path;
1364 }
1365
1366 if (typeof DOMParser == "undefined") {
1367 DOMParser = function () {}
1368 DOMParser.prototype.parseFromString = function (str, contentType) {
1369 if (typeof ActiveXObject != "undefined") {
1370 var d = new ActiveXObject("MSXML.DomDocument");
1371 d.loadXML(str);
1372 return d;
1373 } else if (typeof XMLHttpRequest != "undefined") {
1374 var req = new XMLHttpRequest;
1375 req.open("GET", "data:" + (contentType || "application/xml") +
1376 ";charset=utf-8," + encodeURIComponent(str), false);
1377 if (req.overrideMimeType) {
1378 req.overrideMimeType(contentType);
1379 }
1380 req.send(null);
1381 return req.responseXML;
1382 }
1383 }
1384 }
1385 /*
1386 * utility functions:
1387 */
1388 function js_log(string){
1389 if( window.console ){
1390 window.console.log(string);
1391 }else{
1392 /*
1393 * IE and non-firebug debug:
1394 */
1395 /*var log_elm = document.getElementById('mv_js_log');
1396 if(!log_elm){
1397 document.getElementsByTagName("body")[0].innerHTML = document.getElementsByTagName("body")[0].innerHTML +
1398 '<div style="position:absolute;z-index:500;top:0px;left:0px;right:0px;height:10px;">'+
1399 '<textarea id="mv_js_log" cols="120" rows="5"></textarea>'+
1400 '</div>';
1401
1402 var log_elm = document.getElementById('mv_js_log');
1403 }
1404 if(log_elm){
1405 log_elm.value+=string+"\n";
1406 }*/
1407 }
1408 return false;
1409 }
1410
1411 function checkDefaultMwConfig(){
1412 for(var i in defaultMwConfig){
1413 if(typeof(mwConfig[i])=='undefined'){
1414 mwConfig[i] =defaultMwConfig[i];
1415 }
1416 }
1417 }
1418
1419 function js_error(string){
1420 alert(string);
1421 return false;
1422 }