Bug 20489 Configure illegal file characters https://bugzilla.wikimedia.org/show_bug...
[mediawiki.git] / js2 / mwEmbed / libAddMedia / mvFirefogg.js
blob1add3c586a2a9befa90e7ac958238704916c757f
1 /* adds firefogg support.
2 * autodetects: new upload api or old http POST.
3  */
5 loadGM({
6         "fogg-select_file" : "Select file",
7         "fogg-select_new_file" : "Select new file",
8         "fogg-select_url" : "Select URL",
9         "fogg-save_local_file" : "Save Ogg",
10         "fogg-check_for_fogg" : "Checking for Firefogg <blink>...<\/blink>",
11         "fogg-installed" : "Firefogg is installed",
12         "fogg-for_improved_uplods" : "For improved uploads:",
13         "fogg-please_install" : "<a href=\"$1\">Install Firefogg<\/a>. More <a href=\"http:\/\/commons.wikimedia.org\/wiki\/Commons:Firefogg\">about Firefogg<\/a>",
14         "fogg-use_latest_fox" : "Please first install <a href=\"http:\/\/www.mozilla.com\/en-US\/firefox\/upgrade.html?from=firefogg\">Firefox 3.5<\/a> (or later). <i>Then revisit this page to install the <b>Firefogg<\/b> extension.<\/i>",
15         "fogg-passthrough_mode" : "Your selected file is already Ogg or not a video file",
16         "fogg-transcoding" : "Encoding video to Ogg",
17         "fogg-encoding-done" : "Encoding complete",
18         "fogg-badtoken" : "Token is not valid"
19 });
21 var firefogg_install_links =  {
22         'macosx':       'http://firefogg.org/macosx/Firefogg.xpi',
23         'win32':        'http://firefogg.org/win32/Firefogg.xpi',
24         'linux' :       'http://firefogg.org/linux/Firefogg.xpi'
27 var default_firefogg_options = {
28         //what to do when finished uploading
29         'done_upload_cb':false,
30         //if firefoog is enabled
31         'fogg_enabled':false,
32         //the api url to upload to
33         'api_url':null,
34         //the passthrough flag (enables un-modified uploads)
35         'passthrough': false,
36         //if we will be showing the encoder interface
37         'encoder_interface': false,
38         //if we want to limit the library functionality to "only firefoog" (no upload or progress bars)
39         'only_fogg': false,
42         //callbacks:
43         'new_source_cb': false, //called on source name update passes along source name
45         //target control container or form (can't be left null)
46         'selector': '',
48         //if not rewriting a form we are encoding local.
49         'form_rewrite': false,
51         //taget buttons:
52         'target_btn_select_file': false,
53         'target_btn_select_new_file': false,
55         //'target_btn_select_url': false,
57         'target_btn_save_local_file': false,
58         'target_input_file_name': false,
61         //target install descriptions
62         'target_check_for_fogg': false,
63         'target_installed': false,
64         'target_please_install': false,
65         'target_use_latest_fox': false,
66         //status:
67         'target_passthrough_mode':false,
69         //if firefogg should take over the form submit action
70         'firefogg_form_action':true
74 var mvFirefogg = function(iObj){
75         return this.init( iObj );
77 mvFirefogg.prototype = { //extends mvBaseUploadInterface
79         min_firefogg_version : '0.9.9.5',
80         fogg_enabled : false,            //if firefogg is enabled or not.
81         encoder_settings:{                      //@@todo allow server to set this
82                 'maxSize'        : '400',
83         'videoBitrate'   : '544',
84         'audioBitrate'   : '96',
85         'noUpscaling'    : true
86         },
87         sourceFileInfo: {},
88         ogg_extensions: ['ogg', 'ogv', 'oga'],
89         video_extensions: ['avi', 'mov', 'mp4', 'mp2', 'mpeg', 'mpeg2', 'mpeg4', 'dv', 'wmv'],
91         passthrough: false,
92         sourceMode: 'file',
94         init: function( iObj ){
95                 if(!iObj)
96                         iObj = {};
98                 //if we have no api_url set upload to "post"
99                 if(!iObj.api_url)
100                         iObj.upload_mode = 'post';
102                 //inherit iObj properties:
103                 for(var i in default_firefogg_options){
104                         if(iObj[i]){
105                                 this[i] = iObj[i];
106                         }else{
107                                 this[i] = default_firefogg_options[i];
108                         }
109                 }
110                 //check if we want to limit the usage:
111                 if(!this.only_fogg){
112                         var myBUI = new mvBaseUploadInterface( iObj );
114                         //standard extends code:
115                         for(var i in myBUI){
116                                 if(this[i]){
117                                         this['pe_'+ i] = myBUI[i];
118                                 }else{
119                                         this[i] =  myBUI[i];
120                                 }
121                         }
122                 }
124                 if(!this.selector){
125                         js_log('firefogg: missing selector ');
126                 }
127         },
128         doRewrite:function( callback ){
129                 var _this = this;
130                 js_log('sel len: ' + this.selector + '::' + $j(this.selector).length + ' tag:'+ $j(this.selector).get(0).tagName);
131                 if( $j(this.selector).length >=0 ){
133                         if( $j(this.selector).get(0).tagName.toLowerCase() == 'input' ){
134                                 _this.form_rewrite = true;
135                         }
136                 }
137                 //check if we are rewriting an input or a form:
138                 if( this.form_rewrite ){
139                         this.setupForm();
140                 }else{
141                         this.doControlHTML();
142                         this.doControlBindings();
143                 }
145                 //doRewrite is done:
146                 if(callback)
147                         callback();
148         },
149         doControlHTML: function( ){
150                 var _this = this;
151                 var out = '';
152                 $j.each(default_firefogg_options, function(target, na){
153                         if(target.substring(0, 6)=='target'){
154                                 //js_log('check for target html: ' + target);
155                                 //check for the target if missing add to the output:
156                                 if( _this[target] === false){
157                                         out += _this.getTargetHtml(target) + ' ';
158                                         //update the target selector
159                                     _this[target] = _this.selector + ' .' + target;
160                                 }
161                         }
162                 });
163                 $j( this.selector ).append( out ).hide();
164         },
165         getTargetHtml:function(target){
166                 if( target.substr(7,3)=='btn'){
167                         return '<input style="" class="' + target + '" type="button" value="' + gM( 'fogg-' + target.substring(11)) + '"/> ';
168                 }else if(target.substr(7,5)=='input'){
169                         return '<input style="" class="' + target + '" type="text" value="' + gM( 'fogg-' + target.substring(11)) + '"/> ';
170                 }else{
171                         return '<div style="" class="' + target + '" >'+ gM('fogg-'+ target.substring(7)) + '</div> ';
172                 }
173         },
174         doControlBindings: function(){
175                 var _this = this;
177                 //hide all targets:
178                 var hide_target_list='';
179                 var coma='';
180                 $j.each(default_firefogg_options, function(target, na){
181                         if(target.substring(0, 6)=='target'){
182                                 hide_target_list+=coma + _this[target];
183                                 coma=',';
184                         }
185                 });
186                 $j( hide_target_list ).hide();
187                 //now that the proper set of items has been hiiden show:
188                 $j( this.selector ).show();
191                 //hide all but check-for-fogg
192                 //check for firefogg
193                 if( _this.firefoggCheck() ){
195                         //if rewriting the form lets keep the text input around:
196                         if( _this.form_rewrite )
197                                 $j(this.target_input_file_name).show();
199                         //show select file:
200                         $j( this.target_btn_select_file ).unbind(
201                                 ).attr('disabled', false
202                                 ).css({'display':'inline'}
203                                 ).click(function(){
204                                         _this.selectFogg();
205                                 });
207                     //also setup the text file display on Click to select file:
208                     $j(this.target_input_file_name).unbind().attr('readonly', 'readonly').click(function(){
209                         _this.selectFogg();
210                     })
212                 }else{
213                         //first check firefox version:
214                         if(!( $j.browser.mozilla && $j.browser.version >= '1.9.1' )) {
215                                 js_log( 'show use latest::' + _this.target_use_latest_fox );
216                                 if( _this.target_use_latest_fox ){
217                                         if( _this.form_rewrite )
218                                                 $j( _this.target_use_latest_fox ).prepend( gM('fogg-for_improved_uplods') );
220                                         $j( _this.target_use_latest_fox ).show();
221                                 }
222                                 return ;
223                         }
225                         //if rewriting form use upload msg text
226                         var upMsg = (_this.form_rewrite) ? gM('fogg-for_improved_uplods') : '';
227                         $j( _this.target_please_install ).html( upMsg + gM('fogg-please_install', _this.getOSlink() )).css('padding', '10px').show();
228                 }
229                 //setup the target save local file bindins:
230                 $j( _this.target_btn_save_local_file ).unbind().click(function(){
231                         _this.saveLocalFogg();
232                 });
233         },
234         /*
235          * returns the firefogg link for your os:
236          */
237         getOSlink:function(){
238                 var os_link = false;
239                 if(navigator.oscpu){
240                         if(navigator.oscpu.search('Linux') >= 0)
241                                 os_link = firefogg_install_links['linux'];
242                         else if(navigator.oscpu.search('Mac') >= 0)
243                                   os_link = firefogg_install_links['macosx'];
244                         else if(navigator.oscpu.search('Win') >= 0)
245                                   os_link = firefogg_install_links['win32'];
246                 }
247                 return os_link
248         },
249         firefoggCheck:function(){
250                 if(typeof(Firefogg) != 'undefined' && Firefogg().version >= this.min_firefogg_version){
251                         this.fogg = new Firefogg();
252                         this.fogg_enabled = true;
253                         return true;
254                 }else{
255                         return false;
256                 }
257         },
258         //assume input target
259         setupForm: function(){
260                 js_log('firefogg::setupForm::');
261                 //to parent form setup if we want http updates
262                 if( this.form_rewrite ){
263                         //do parent form setup:
264                         this.pe_setupForm();
265                 }
267                 //check if we have firefogg (if not just add a link and stop proccessing)
268                 if( !this.firefoggCheck() ){
269                         //add some status indicators if not provided:
270                         if(!this.target_please_install){
271                                 $j(this.selector).after ( this.getTargetHtml('target_please_install') );
272                                 this.target_please_install = this.selector + ' ~ .target_please_install';
273                         }
274                         if(!this.target_use_latest_fox){
275                                 $j(this.selector).after ( this.getTargetHtml('target_use_latest_fox') );
276                                 this.target_use_latest_fox = this.selector + ' ~ .target_use_latest_fox';
277                         }
278                         //update download link:
279                         this.doControlBindings();
280                         return ;
281                 }
283                 //change the file browser to type text: (can't directly change input from "file" to "text" so longer way:
284                 var inTag = '<input ';
285                 $j.each($j(this.selector).get(0).attributes, function(i, attr){
286                         var val = attr.value;
287                         if( attr.name == 'type')
288                                 val = 'text';
289                         inTag += attr.name + '="' + val + '" ';
290                 });
291                 if(!$j(this.selector).attr('style'))
292                         inTag += 'style="display:inline" ';
294                 inTag+= '/><span id="' + $j(this.selector).attr('name') + '_fogg-control"></span>';
296                 js_log('set input: ' + inTag);
297                 $j(this.selector).replaceWith(inTag);
299                 this.target_input_file_name = 'input[name=' + $j(this.selector).attr('name') + ']';
300                 //update the selector to the control target:
301                 this.selector = '#' + $j(this.selector).attr('name') +  "_fogg-control";
303                 this.doControlHTML();
304                 //check for the other inline status indicator targets:
306                 //update the bindings:
307                 this.doControlBindings();
308         },
309         getEditForm:function(){
310                 if( this.target_edit_from )
311                         return this.pe_getEditForm();
312                 //else try to get the parent "from" of the file selector:
313                 return $j(this.selector).parents('form:first').get(0);
314         },
315         selectFogg:function(){
316                 var _this = this;
317                 if(_this.fogg.selectVideo() ){
318                         this.selectFoggActions();
319                 }
320         },
321         selectFoggActions:function(){
322                 var _this = this;
323                 js_log('videoSelectReady');
324                 //if not already hidden hide select file and show "select new":
325                 $j(_this.target_btn_select_file).hide();
327                 //show and setup binding for select new file:
328                 $j(_this.target_btn_select_new_file).show().unbind().click(function(){
329                         //create new fogg instance:
330                         _this.fogg = new Firefogg();
331                         _this.selectFogg();
332                 });
334                 //update if we are in passthrough mode or going to encode
335                 if( _this.fogg.sourceInfo && _this.fogg.sourceFilename  ){
336                         //update the source status
337                         try{
338                                 _this.sourceFileInfo = JSON.parse( _this.fogg.sourceInfo ) ;
339                         }catch (e){
340                                 js_error('error could not parse fogg sourceInfo');
341                         }
343                         //now setup encoder settings based source type:
344                         _this.autoEncoderSettings();
346                         //if set to passthough update the interface:
347                         if(_this.encoder_settings['passthrough']==true){
348                                 $j(_this.target_passthrough_mode).show();
349                         }else{
350                                 $j(_this.target_passthrough_mode).hide();
351                                 //if set to encoder expose the encode button:
352                                 if( !_this.form_rewrite ){
353                                         $j(_this.target_btn_save_local_file).show();
354                                 }
355                         }
356                         //~otherwise the encoding will be triggered by the form~
358                         //do source name update callback:
359                         js_log(" should update: " + _this.target_input_file_name + ' to: ' + _this.fogg.sourceFilename );
360                         $j(_this.target_input_file_name).val(_this.fogg.sourceFilename).show();
362                         if(_this.new_source_cb){
363                                 if(_this.encoder_settings['passthrough']){
364                                         var fName = _this.fogg.sourceFilename
365                                 }else{
366                                     var oggExt = (_this.isSourceAudio())?'oga':'ogg';
367                     oggExt = (_this.isSourceVideo())?'ogv':oggExt;
368                     oggExt = (_this.isUnknown())?'ogg':oggExt;
369                                     oggName = _this.fogg.sourceFilename.substr(0,
370                                                   _this.fogg.sourceFilename.lastIndexOf('.'));
371                                     var fName = oggName +'.'+ oggExt
372                                 }
373                                 _this.new_source_cb( _this.fogg.sourceFilename , fName);
374                         }
375                 }
376         },
377         saveLocalFogg:function(){
378            //request target location:
379            if(this.fogg){
380                    if(!this.fogg.saveVideoAs() )
381                            return false;
383                    //we have set a target now call the encode:
384                   this.doEncode();
385            }
386         },
387         //simple auto encoder settings just enable passthough if file is not video or > 480 pixles tall
388         autoEncoderSettings:function(){
389                 var _this = this;
390                 //grab the extension:
391                 var sf = _this.fogg.sourceFilename;
392                 var ext = '';
393                 if(     sf.lastIndexOf('.') != -1){
394                         ext = sf.substring( sf.lastIndexOf('.')+1 ).toLowerCase();
395                 }
397                 //set to passthrough to true by default (images, arbitrary files that we want to send with http chunks)
398                 this.encoder_settings['passthrough'] = true;
400                 //see if we have video or audio:
401                 if(  _this.isSourceAudio() || _this.isSourceVideo() ){
402                          _this.encoder_settings['passthrough'] = false;
403                 }
405                 //special case see if we already have ogg video:
406                 if( _this.isOggFormat() ){
407                         _this.encoder_settings['passthrough'] = true;
408                 }
410                 js_log('base autoEncoderSettings::' + _this.sourceFileInfo.contentType  + ' passthrough:' + _this.encoder_settings['passthrough']);
411         },
412         isUnknown:function(){
413                 return (this.sourceFileInfo.contentType.indexOf("unknown") != -1);
414         },
415         isSourceAudio:function(){
416            return (this.sourceFileInfo.contentType.indexOf("audio/") != -1);
417         },
418         isSourceVideo:function(){
419             return (this.sourceFileInfo.contentType.indexOf("video/") != -1);
420         },
421         isOggFormat:function(){
422            return ( this.sourceFileInfo.contentType.indexOf("video/ogg") != -1 ||
423                         this.sourceFileInfo.contentType.indexOf("application/ogg") != -1   );
424         },
425         getProgressTitle:function(){
426                 js_log("fogg:getProgressTitle f:" + this.fogg_enabled  + ' rw:' + this.form_rewrite);
427                 //return the parent if we don't have fogg turned on:
428                 if(! this.fogg_enabled || !this.firefogg_form_action )
429                         return this.pe_getProgressTitle();
430                 if( !this.form_rewrite )
431                   return gM('fogg-transcoding');
432                 //else return our upload+transcode msg:
433                 return gM('mwe-upload-transcode-in-progress');
434         },
435         doUploadSwitch:function(){
436                 var _this = this;
437                 js_log("firefogg: doUploadSwitch:: " + this.fogg_enabled + ' up mode:' +  _this.upload_mode);
438                 //make sure firefogg is enabled otherwise do parent UploadSwich:
439                 if( !this.fogg_enabled || !this.firefogg_form_action )
440                         return _this.pe_doUploadSwitch();
442                 //check what mode to use firefogg in:
443                 if( _this.upload_mode == 'post' ){
444                         _this.doEncode();
445                 }else if( _this.upload_mode == 'api' ){ //if api mode and chunks supported do chunkUpload
446                         _this.doChunkUpload();
447                 }else{
448                         js_error( 'Error: unrecongized upload mode: ' + _this.upload_mode );
449                 }
450         },
451         //doChunkUpload does both uploading and encoding at the same time and uploads one meg chunks as they are ready
452         doChunkUpload : function(){
453                 js_log('firefogg::doChunkUpload');
454                 var _this = this;
455                 _this.action_done = false;
456                 
457                 //extension should already be ogg but since its user editable,
458                 //check again
459                 //we are transcoding so we know it will be an ogg
460                 //(should not be done for passthrough mode)
461                 var sf = _this.formData['filename'];
462                 var ext = '';
463                 if(     sf.lastIndexOf('.') != -1){
464                         ext = sf.substring( sf.lastIndexOf('.') ).toLowerCase();
465                 }
466                 if( !_this.encoder_settings['passthrough'] && $j.inArray(ext.substr(1), _this.ogg_extensions) == -1 ){
467                         var extreg = new RegExp(ext + '$', 'i');
468                         _this.formData['filename'] = sf.replace(extreg, '.ogg');
469                 }
470                 //add chunk response hook to build the resultURL when uploading chunks
472                 //check for editToken:
473                 if(!this.etoken){
474                         js_log('missing token try ' + _this.formData['token']);
475                         if( _this.formData['token']){
476                                 _this.etoken = _this.formData['token'];
477                                 _this.doChunkWithFormData();
478                         }else{
479                                 get_mw_token(
480                                         'File:'+ _this.formData['filename'],
481                                         _this.api_url,
482                                         function( eToken ){
483                                                 if( !eToken || eToken == '+\\' ){
484                                                         _this.updateProgressWin( gM('fogg-badtoken'), gM('fogg-badtoken') );
485                                                         return false;
486                                                 }
487                                                 _this.etoken = eToken;
488                                                 _this.doChunkWithFormData();
489                                         }
490                                 );
491                         }
492                 }else{
493                         js_log('we already have token: ' + this.etoken);
494                         _this.doChunkWithFormData();
495                 }
496         },
497         doChunkWithFormData:function(){
498                 var _this = this;
499                 js_log("firefogg::doChunkWithFormData"  + _this.etoken);
500                 //build the api url:
501                 var aReq ={
502                         'action': 'upload',
503                         'format': 'json',
504                         'filename': _this.formData['filename'],
505                         'comment': _this.formData['comment'],
506                         'enablechunks': 'true'
507                 };
509                 if( _this.etoken )
510                         aReq['token'] = this.etoken;
512                 if( _this.formData['watch'] )
513                         aReq['watch'] =  _this.formData['watch'];
515                 if(  _this.formData['ignorewarnings'] )
516                         aReq['ignorewarnings'] = _this.formData['ignorewarnings'];
518                 js_log('do fogg upload/encode call: '+ _this.api_url + ' :: ' + JSON.stringify( aReq ) );
519                 js_log('foggEncode: '+ JSON.stringify( _this.encoder_settings ) );
520                 _this.fogg.upload( JSON.stringify( _this.encoder_settings ),  _this.api_url ,  JSON.stringify( aReq ) );
522                 //update upload status:
523                 _this.doUploadStatus();
524         },
525         //doEncode and monitor progress:
526         doEncode : function(){
527                 var _this = this;
528                 _this.action_done = false;
529                 _this.dispProgressOverlay();
530                 js_log('doEncode: with: ' +  JSON.stringify( _this.encoder_settings ) );
531                 _this.fogg.encode( JSON.stringify( _this.encoder_settings ) );
534                  //show transcode status:
535                 $j('#up-status-state').html( gM('mwe-upload-transcoded-status') );
537                 //setup a local function for timed callback:
538                 var encodingStatus = function() {
539                         var status = _this.fogg.status();
541                         //update progress bar
542                         _this.updateProgress( _this.fogg.progress() );
544                         //loop to get new status if still encoding
545                         if( _this.fogg.state == 'encoding' ) {
546                                 setTimeout(encodingStatus, 500);
547                         }else if ( _this.fogg.state == 'encoding done' ) { //encoding done, state can also be 'encoding failed
548                                 _this.encodeDone();
549                         }else if(_this.fogg.state == 'encoding fail'){
550                                 //@@todo error handling:
551                                 js_error('encoding failed');
552                         }
553                 }
554                 encodingStatus();
555         },
556         encodeDone:function(){
557                 var _this = this;
558                 js_log('::encodeDone::');
559                 _this.action_done = true;
560                 //send to the post url:
561                 if( _this.form_rewrite && _this.upload_mode == 'post' ){
562                         js_log('done with encoding do POST upload:' + _this.editForm.action);
563                         // ignore warnings & set source type
564                         //_this.formData[ 'wpIgnoreWarning' ]='true';
565                         _this.formData[ 'wpSourceType' ] = 'upload';
566                         _this.formData[ 'action' ]               = 'submit';
567                         //wpUploadFile is set by firefogg
568                         delete _this.formData[ 'file' ];
570                         _this.fogg.post( _this.editForm.action, 'wpUploadFile', JSON.stringify( _this.formData ) );
571                         //update upload status:
572                         _this.doUploadStatus();
573                 }else{
574                         js_log("done with encoding (no upload) ");
575                         //set stuats to 100% for one second:
576                         _this.updateProgress( 1 );
577                         setTimeout(function(){
578                                 _this.updateProgressWin(gM('fogg-encoding-done'), gM('fogg-encoding-done'));
579                         }, 1000);
580                 }
581         },
582         doUploadStatus:function() {
583                 var _this = this;
584                 $j( '#up-status-state' ).html( gM('mwe-uploaded-status')  );
586                 _this.oldResponseText = '';
587                 //setup a local function for timed callback:
588                 var uploadStatus = function(){
589                         //get the response text:
590                         var response_text =  _this.fogg.responseText;
591                         if(!response_text){
592                                    try{
593                                            var pstatus = JSON.parse( _this.fogg.uploadstatus() );
594                                            response_text = pstatus["responseText"];
595                                    }catch(e){
596                                            js_log("could not parse uploadstatus / could not get responseText");
597                                    }
598                         }
600                         if( _this.oldResponseText != response_text){
601                                 js_log('new result text:' + response_text + ' state:' + _this.fogg.state);
602                                 _this.oldResponseText = response_text;
603                                 //try and parse the response text and check for errors
604                                 try{
605                                         var apiResult = JSON.parse( response_text );
606                                 }catch(e){
607                                         js_log("could not parse response_text::" + response_text + ' ...for now try with eval...');
608                                         try{
609                                                 var apiResult = eval( response_text );
610                                         }catch(e){
611                                                 var apiResult = null;
612                                         }                                       
613                                 }
614                                 if(apiResult && _this.apiUpdateErrorCheck( apiResult ) === false){
615                                         //stop status update we have an error
616                                         _this.action_done = true;
617                                         _this.fogg.cancel();
618                                         return false;
619                                 }
620                         }
621                         //update progress bar
622                         _this.updateProgress( _this.fogg.progress() );
624                         //loop to get new status if still uploading (could also be encoding if we are in chunk upload mode)
625                         if( _this.fogg.state == 'encoding' || _this.fogg.state == 'uploading') {
626                                 setTimeout(uploadStatus, 100);
627                         }//check upload state
628                         else if( _this.fogg.state == 'upload done' ||
629                                                  _this.fogg.state == 'done' ||
630                                                  _this.fogg.state == 'encoding done' ) {
631                                    //if in "post" upload mode read the html response (should be depricated):
632                                    if( _this.upload_mode == 'api' ){
633                                            if( apiResult && apiResult.resultUrl ){
634                                                         var buttons ={};
635                                                         buttons[gM('mwe-go-to-resource')] =  function(){
636                                                                 window.location = apiResult.resultUrl;
637                                                         }
638                                                         var go_to_url_txt = gM('mwe-go-to-resource');
639                                                         if( typeof _this.done_upload_cb == 'function' ){
640                                                                 //if done action return 'true'
641                                                                 if( _this.done_upload_cb( _this.formData ) ){
642                                                                         //update status
643                                                                         _this.updateProgressWin( gM('mwe-successfulupload'),  gM( 'mwe-upload_done', apiResult.resultUrl),buttons);
644                                                                 }else{
645                                                                         //if done action returns 'false' //close progress window
646                                                                         this.action_done = true;
647                                                                 $j('#upProgressDialog').dialog('close');
648                                                                 }
649                                                         }else{
650                                                                 //update status (without done_upload_cb)
651                                                                 _this.updateProgressWin( gM('mwe-successfulupload'),  gM( 'mwe-upload_done', apiResult.resultUrl),buttons);
652                                                         }
653                                            }else{
654                                                    //done state with error? ..not really possible given how firefogg works
655                                                    js_log(" Upload done in chunks mode, but no resultUrl!");
656                                            }
657                                    }else if( _this.upload_mode == 'post' && _this.api_url ) {
658                                            _this.procPageResponse( response_text );
659                                    }
660                         }else{
661                                 //upload error:
662                                 js_log('Error:firefogg upload error: ' + _this.fogg.state );
663                    }
664            }
665            uploadStatus();
666         },
667         cancel_action:function( dlElm ){
668                 if(!this.fogg_enabled){
669                         return this.pe_cancel_action();
670                 }
671                 js_log('firefogg:cancel')
672                 if( confirm( gM('mwe-cancel-confim') )){
673                     if(navigator.oscpu && navigator.oscpu.search('Win') >= 0){
674                          alert( 'sorry we do not yet support cancel on windows' );
675                     }else{
676                         this.action_done = true;
677                         this.fogg.cancel();
678                         $j(dlElm).dialog('close');
679                     }
680                 } else{
681                         return false;
682                 }
683         },
684         /**
685         * procPageResponse should be faded out in favor of the upload api soon..
686         * its all very fragile to read the html output and guess at stuff
687         */
688         procPageResponse:function( result_page ){
689                 var _this = this;
690                 js_log('f:procPageResponse');
691                 var sstring = 'var wgTitle = "' + this.formData['filename'].replace('_',' ');
693                 if(wgArticlePath){
694                         var result_txt = gM('mwe-upload_done', wgArticlePath.replace(/\$1/, 'File:' + _this.formData['filename'] ) );
695                 }else{
696                         result_txt = 'File has uploaded but api "done" URL was provided. Check the log for result page output';
697                 }
699                 //set the error text in case we dont' get far along in processing the response
700                 _this.updateProgressWin( gM('mwe-upload_completed'), result_txt );
702                 if( result_page && result_page.toLowerCase().indexOf( sstring.toLowerCase() ) != -1){
703                         js_log( 'upload done got redirect found: ' + sstring + ' r:' + _this.done_upload_cb );
704                         if( _this.done_upload_cb == 'redirect' ){
705                                 $j( '#dlbox-centered' ).html( '<h3>Upload Completed:</h3>' + result_txt + '<br>' + form_txt);
706                                 window.location = wgArticlePath.replace( /\$1/, 'File:' + _this.formData['wpDestFile'] );
707                         }else{
708                                 //check if the add_done_action is a callback:
709                                 if( typeof _this.done_upload_cb == 'function' )
710                                         _this.done_upload_cb();
711                         }
712                 }else{
713                         //js_log( 'upload page error: did not find: ' +sstring + ' in ' + "\n" + result_page );
714                         var form_txt = '';
715                         if( !result_page ){
716                                 //@@todo fix this:
717                                 //the mediaWiki upload system does not have an API so we can\'t read errors
718                         }else{
719                                 var res = grabWikiFormError( result_page );
721                                 if(res.error_txt)
722                                         result_txt = res.error_txt;
724                                 if(res.form_txt)
725                                         form_txt = res.form_txt;
726                         }
727                         js_log( 'error text is: ' + result_txt );
728                         $j( '#dlbox-centered' ).html( '<h3>' + gM('mwe-upload_completed') + '</h3>' + result_txt + '<br>' + form_txt);
729                 }
730         }