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