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