35fd85aa461dd7aa6d3e6b4c8c0145360ed201b1
2 * the base Upload Interface for uploading.
4 * this base uploader is optionally extended by firefogg
7 "upload-transcode-in-progress":"Doing Transcode & Upload (do not close this window)",
8 "upload-in-progress": "Upload in Progress (do not close this window)",
9 "upload-transcoded-status": "Transcoded",
10 "uploaded-status": "Uploaded",
12 "wgfogg_wrong_version": "You have firefogg installed but its outdated, <a href=\"http://firefogg.org\">please upgrade</a> ",
13 "upload-stats-fileprogres": "$1 of $2",
15 "mv_upload_completed": "Your upload is complete",
17 "mv_upload_done" : "Your upload <i>should be</i> accessible <a href=\"$1\">here</a>",
18 "upload-unknown-size": "Unknown size",
20 "mv-cancel-confim" : "Are you sure you want to cancel?",
22 "successfulupload" : "Successful Upload",
23 "uploaderror" : "Upload error",
24 "uploadwarning": "Upload warning",
25 "unknown-error": "Unknown Error",
26 "return-to-form": "Return to form",
28 "file-exists-duplicate" : "This file is a duplicate of the following file",
29 "fileexists" : "A file with this name exists already, please check <b><tt>$1</tt></b> if you are not sure if you want to change it.",
30 "fileexists-thumb": "<center><b>Existing file</b></center>",
31 "ignorewarning" : "Ignore warning and save file anyway",
32 "file-thumbnail-no" : "The filename begins with <b><tt>$1</tt></b>",
33 "go-to-resource" : "Go to Resource Page",
34 "upload-misc-error" : "Unknown upload error",
36 "wgfogg_waring_bad_extension" : "You have selected a file with an unsuported extension (<a href=\"http://commons.wikimedia.org/wiki/Commons:Firefogg#Supported_File_Types\">more information</a>).",
38 "cancel-button" : "Cancel",
44 var default_bui_options
= {
46 'parent_uploader':null,
48 'done_upload_cb': null,
49 'target_edit_from':null,
51 //upload_mode can be 'post', 'api' or 'autodetect'. (autodetect issues an api call)
52 'upload_mode': 'autodetect'
55 var mvBaseUploadInterface = function( iObj
){
56 return this.init( iObj
);
58 mvBaseUploadInterface
.prototype = {
59 parent_uploader
:false,
60 formData
:{}, //the form to be submitted
61 warnings_sessionkey
:null,
62 chunks_supported
:false,
63 form_post_override
:false,
67 init: function( iObj
){
70 //inherit iObj properties:
71 for(var i
in default_bui_options
){
75 this[i
] = default_bui_options
[i
];
81 //set up the local pointer to the edit form:
82 _this
.editForm
= _this
.getEditForm();
83 $j(_this
.editForm
).attr('target', 'f_1');
85 //set up the org_onsubmit if not set:
86 if( typeof( _this
.org_onsubmit
) == 'undefined' && _this
.editForm
.onsubmit
)
87 _this
.org_onsubmit
= _this
.editForm
.onsubmit
;
89 //set up the submit action:
90 $j( _this
.editForm
).submit( function(){
92 //run the original onsubmit (if not run yet set flag to avoid excessive chaining )
93 if( typeof( _this
.org_onsubmit
) == 'function' ){
94 if( ! _this
.org_onsubmit() ){
95 //error in org submit return false;
99 //check for post action override:
100 if( _this
.form_post_override
){
101 js_log('form_post_override is true do form proccessing:');
104 //get the input form data in flat json:
105 var tmpAryData
= $j( _this
.editForm
).serializeArray();
106 for(var i
=0; i
< tmpAryData
.length
; i
++){
107 if( tmpAryData
[i
]['name'] )
108 _this
.formData
[ tmpAryData
[i
]['name'] ] = tmpAryData
[i
]['value'];
110 //put into a try catch so we are sure to return false:
112 //get a clean loader:
113 _this
.dispProgressOverlay();
115 //for some unknown reason we have to drop down the #p-search z-index:
116 $j('#p-search').css('z-index', 1);
118 //select upload mode:
119 _this
.detectUploadMode();
124 //don't submit the form we will do the post in ajax
130 detectUploadMode:function( callback
){
132 //check the upload mode:
133 if( _this
.upload_mode
== 'autodetect' ){
134 js_log('detectUploadMode::' + _this
.upload_mode
+ ' api:' + _this
.api_url
);
135 if( ! _this
.api_url
)
136 return js_error( 'Error: can\'t autodetect mode without api url' );
138 'data':{ 'action':'paraminfo','modules':'upload' },
141 if( typeof data
.paraminfo
== 'undefined' || typeof data
.paraminfo
.modules
== 'undefined' )
142 return js_error( 'Error: bad api results' );
143 if( typeof data
.paraminfo
.modules
[0].classname
== 'undefined'){
144 js_log( 'Autodetect Upload Mode: \'post\' ');
145 _this
.upload_mode
= 'post';
147 js_log( 'Autodetect Upload Mode: api ' );
148 _this
.upload_mode
= 'api';
149 //check to see if chunks are supported:
150 for( var i
in data
.paraminfo
.modules
[0].parameters
){
151 var pname
= data
.paraminfo
.modules
[0].parameters
[i
].name
;
152 if( pname
== 'enablechunks' ){
153 js_log( 'this.chunks_supported = true' );
154 _this
.chunks_supported
= true;
159 js_log("do call: doUploadSwitch");
160 _this
.doUploadSwitch();
163 _this
.doUploadSwitch();
166 doUploadSwitch:function(){
168 js_log('mvUPload:doUploadSwitch():' + _this
.upload_mode
);
169 //issue a normal post request
170 if( _this
.upload_mode
== 'post' ) {
171 //we don't support the upload api
172 //trick the browser into thinking the wpUpload button was pressed (there might be a cleaner way to do this)
173 $j(_this
.editForm
).append(
174 '<input type="hidden" name="wpUpload" value="' + $j('input[name=\'wpUpload\']').val() + '"/>'
177 _this
.form_post_override
= true;
179 _this
.editForm
.submit();
181 _this
.upload_mode
=='api' &&
182 ( $j('#wpSourceTypeFile').length
== 0 || $j('#wpSourceTypeFile').get(0).checked
)
184 //@@TODO check for sendAsBinnary to support firefox 3.5 progress
185 //else remap to iframe target
186 var id
= 'f_' + ($j('iframe').length
+ 1);
187 $j("body").append('<iframe src="javascript:false;" id="' + id
+ '" ' +
188 'name="' + id
+ '" style="display:none;" ></iframe>');
189 //set up the done binding
190 $j('#' + id
).load(function(){
191 var iframe
= $j(this).get(0);
192 _this
.proccessIframeResult( iframe
);
194 //set the editForm iframe target
195 //$j(_this.editForm).attr('target', id);
197 //set the action to the api url:
198 $j(_this
.editForm
).attr('action', _this
.api_url
);
200 if( $j(_this
.editForm
).find("[name='action']").length
== 0)
201 $j(_this
.editForm
).append('<input type="hidden" name="action" value="upload">');
204 if( $j(_this
.editForm
).find("[name='format']").length
== 0)
205 $j(_this
.editForm
).append('<input type="hidden" name="format" value="jsonfm">');
207 //map the form vars to api vars:
208 $j(_this
.editForm
).find('#wpUploadFile').attr('name', 'file');
209 $j(_this
.editForm
).find('#wpDestFile').attr('name', 'filename');
210 $j(_this
.editForm
).find('#wpUploadDescription').attr('name', 'comment');
211 $j(_this
.editForm
).find('#wpEditToken').attr('name', 'token');
212 $j(_this
.editForm
).find('#wpIgnoreWarning').attr('name', 'ignorewarnings');
213 $j(_this
.editForm
).find('#wpWatchthis').attr('name', 'watch');
215 //update the status to 100% progress bar (no status in iframe submit)
216 $j('#up-progressbar' ).progressbar('value', parseInt( 100 ) );
217 $j('#up-status-container').html( gM('upload-in-progress') );
220 js_log('do iframe form submit');
224 _this
.form_post_override
= true;
225 //reset the done with action flag:
226 _this
.action_done
= false;
228 js_log('do the submit');
229 _this
.editForm
.submit();
232 }else if( _this
.upload_mode
== 'api' && $j('#wpSourceTypeURL').get(0).checked
){
233 js_log('doHttpUpload (no form submit) ');
234 //if the api is supported.. && source type is http do upload with http status updates
236 'url' : $j('#wpUploadFileURL').val(),
237 'filename' : $j('#wpDestFile').val(),
238 'comment' : $j('#wpUploadDescription').val(),
239 'watch' : ($j('#wpWatchthis').is(':checked'))?'true':'false'
241 //set up ignore warnings and watch arguments:
242 if( $j('#wpIgnoreWarning').is(':checked') ){
243 httpUpConf
[ 'ignorewarnings'] = 'true';
245 if( $j('#wpWatchthis').is(':checked') ){
246 httpUpConf
[ 'watch'] = 'true';
248 //check for editToken
249 _this
.etoken
= $j("#wpEditToken").val();
250 _this
.doHttpUpload( httpUpConf
);
252 js_error( 'Error: unrecongized upload mode: ' + _this
.upload_mode
);
256 proccessIframeResult:function(iframe
){
258 var doc
= iframe
.contentDocument
? iframe
.contentDocument
: frames
[iframe
.id
].document
;
260 if (doc
.readyState
&& doc
.readyState
!= 'complete'){
264 if (doc
.body
&& doc
.body
.innerHTML
== "false"){
268 if (doc
.XMLDocument
){
269 // response is a xml document IE property
270 response
= doc
.XMLDocument
;
271 } else if (doc
.body
){
273 json_str
= $j(doc
.body
).find('pre').html();
276 response
= window
["eval"]("(" +json_str
+ ")");
281 // response is a xml document
284 //do proccess the api result
285 _this
.processApiResult( response
);
287 doHttpUpload:function( opt
){
289 //set the http box to loading (in case we don't get an update for some time)
290 $j('#dlbox-centered').html( '<h5>' + _this
.getProgressTitle() + '</h5>' +
291 mv_get_loading_img( 'left:40%;top:20%')
296 'asyncdownload' : true //do a s
298 //set config from options:
303 //else try and get a token:
304 if(!_this
.etoken
&& _this
.api_url
){
305 js_log('Error:doHttpUpload: missing token');
307 req
['token'] =_this
.etoken
;
309 //reset the done with action flag:
310 _this
.action_done
= false;
314 'url' : _this
.api_url
316 _this
.processApiResult( data
);
319 doAjaxWarningIgnore:function(){
321 if( !_this
.upload_session_key
)
322 return js_error('missing upload_session_key (can\'t ignore warnigns');
323 //do the ignore warnings submit to the api:
325 'ignorewarnings' : 'true',
326 'sessionkey' :!_this
.upload_session_key
328 //add token if present:
330 req
['token'] = this.etoken
;
336 _this
.processApiResult(data
);
339 doAjaxUploadStatus:function() {
342 //set up the progress display for status updates:
343 _this
.dispProgressOverlay();
346 'httpstatus' : 'true',
347 'sessionkey' : _this
.upload_session_key
349 //add token if present:
351 req
['token'] = this.etoken
;
353 var uploadStatus = function(){
354 //do the api request:
357 'url' : _this
.api_url
359 //@@check if we are done
360 if( data
.upload
['apiUploadResult'] ){
361 //update status to 100%
362 _this
.updateProgress( 1 );
363 if(typeof JSON
== 'undefined'){
364 //we need to load the jQuery json parser: (older browsers don't have JSON.parse
368 var apiResult
= $j
.secureEvalJSON( data
.upload
['apiUploadResult'] );
369 _this
.processApiResult( apiResult
);
374 apiResult
= JSON
.parse ( data
.upload
['apiUploadResult'] ) ;
376 //could not parse api result
377 js_log('errro: could not parse apiUploadResult ')
379 _this
.processApiResult( apiResult
);
384 //@@ else update status:
385 if( data
.upload
['content_length'] && data
.upload
['loaded'] ){
386 //we have content length we can show percentage done:
387 var perc
= data
.upload
['loaded'] / data
.upload
['content_length'];
389 _this
.updateProgress( perc
);
390 //special case update the file progress where we have data size:
391 $j('#up-status-container').html(
392 gM('upload-stats-fileprogres', [
393 formatSize( data
.upload
['loaded'] ),
394 formatSize( data
.upload
['content_length'] )
398 }else if( data
.upload
['loaded'] ){
399 _this
.updateProgress( 1 );
400 js_log('just have loaded (no cotent length: ' + data
.upload
['loaded']);
401 //for lack of content-length requests:
402 $j('#up-status-container').html(
403 gM('upload-stats-fileprogres', [
404 formatSize( data
.upload
['loaded'] ),
405 gM('upload-unknown-size')
410 //(we got a result) set it to 100ms + your server update interval (in our case 2s)
411 setTimeout(uploadStatus
, 2100);
416 apiUpdateErrorCheck:function( apiRes
){
418 if( apiRes
.error
|| ( apiRes
.upload
&& apiRes
.upload
.result
== "Failure" ) ){
419 //gennerate the error button:
421 bObj
[ gM('return-to-form') ] = function(){
422 _this
.form_post_override
= false;
423 $j(this).dialog('close');
426 //@@TODO should be refactored to more specialUpload page type error handling
428 //check a few places for the error code:
430 var errorReplaceArg
='';
431 if( apiRes
.error
&& apiRes
.error
.code
){
432 error_code
= apiRes
.error
.code
;
433 }else if( apiRes
.upload
.code
){
434 if(typeof apiRes
.upload
.code
== 'object'){
435 if(apiRes
.upload
.code
[0]){
436 error_code
= apiRes
.upload
.code
[0];
438 if(apiRes
.upload
.code
['status']){
439 error_code
= apiRes
.upload
.code
['status'];
440 if(apiRes
.upload
.code
['filtered'])
441 errorReplaceArg
=apiRes
.upload
.code
['filtered'];
449 if(typeof apiRes
.error
== 'string')
450 error_msg
= apiRes
.error
;
451 //error space is too large so we don't front load it
452 //this upload error space replicates code in: SpecialUpload.php::processUpload()
453 //would be nice if we refactored that to the upload api.(problem is some need special actions)
454 var error_msg_key
= {
455 '2' : 'largefileserver',
458 '5' : 'illegalfilename'
461 //@@todo: need to write conditionals that mirror SpecialUpload for handling these error types:
462 var error_onlykey
= {
463 '1': 'BEFORE_PROCESSING',
464 '6': 'PROTECTED_PAGE',
465 '7': 'OVERWRITE_EXISTING_FILE',
466 '8': 'FILETYPE_MISSING',
467 '9': 'FILETYPE_BADTYPE',
468 '10': 'VERIFICATION_ERROR',
469 '11': 'UPLOAD_VERIFICATION_ERROR',
470 '12': 'UPLOAD_WARNING',
471 '13': 'INTERNAL_ERROR',
472 '14': 'MIN_LENGHT_PARTNAME'
475 //do a remote call to get the error msg:
476 if(!error_code
|| error_code
== 'unknown-error'){
477 if(typeof JSON
!= 'undefined'){
478 js_log('Error: apiRes: ' + JSON
.stringify( apiRes
) );
480 if( apiRes
.upload
.error
== 'internal-error'){
481 errorKey
= apiRes
.upload
.details
[0];
482 gMsgLoadRemote(errorKey
, function(){
483 _this
.updateProgressWin( gM( 'uploaderror' ), gM( errorKey
), bObj
);
489 _this
.updateProgressWin( gM('uploaderror'), gM('unknown-error') + '<br>' + error_msg
, bObj
);
492 if(apiRes
.error
&& apiRes
.error
.info
){
493 _this
.updateProgressWin( gM('uploaderror'), apiRes
.error
.info
,bObj
);
496 if(typeof error_code
== 'number' && typeof error_msg_key
[error_code
] == 'undefined' ){
497 if(apiRes
.upload
.code
.finalExt
){
498 _this
.updateProgressWin( gM('uploaderror'), gM('wgfogg_waring_bad_extension', apiRes
.upload
.code
.finalExt
) , bObj
);
500 _this
.updateProgressWin( gM('uploaderror'), gM('unknown-error') + ' : ' + error_code
, bObj
);
503 js_log('get key: ' + error_msg_key
[ error_code
])
504 gMsgLoadRemote( error_msg_key
[ error_code
], function(){
505 _this
.updateProgressWin( gM('uploaderror'), gM( error_msg_key
[ error_code
], errorReplaceArg
), bObj
);
513 //check for upload.error type erros.
514 if( apiRes
.upload
&& apiRes
.upload
.error
){
515 js_log(' apiRes.upload.error: ' + apiRes
.upload
.error
);
516 _this
.updateProgressWin( gM('uploaderror'), gM('unknown-error') + '<br>', bObj
);
519 //check for known warnings:
520 if(apiRes
.upload
&& apiRes
.upload
.warnings
){
523 for(var wtype
in apiRes
.upload
.warnings
){
524 var winfo
= apiRes
.upload
.warnings
[wtype
]
529 if(winfo
[1] && winfo
[1].title
&& winfo
[1].title
.mTextform
){
530 wmsg
+= gM('file-exists-duplicate') +' '+
531 '<b>' + winfo
[1].title
.mTextform
+ '</b>';
533 //misc error (weird that winfo[1] not present
534 wmsg
+= gM('upload-misc-error') + ' ' + wtype
;
537 case 'file-thumbnail-no':
538 wmsg
+= gM('file-thumbnail-no', winfo
);
541 wmsg
+= gM('upload-misc-error') + ' ' + wtype
;
547 if( apiRes
.upload
.warnings
.sessionkey
)
548 _this
.warnings_sessionkey
= apiRes
.upload
.warnings
.sessionkey
;
550 bObj
[ gM('ignorewarning') ] = function() {
551 //re-inciate the upload proccess
552 $j('#wpIgnoreWarning').attr('checked', true);
553 $j( '#mw-upload-form' ).submit();
555 bObj
[ gM('return-to-form') ] = function(){
556 $j(this).dialog('close');
557 _this
.form_post_override
= false;
559 _this
.updateProgressWin( gM('uploadwarning'), '<h3>' + gM('uploadwarning') + '</h3>' +wmsg
+ '<p>',bObj
);
565 processApiResult: function( apiRes
){
567 js_log('processApiResult::');
568 //check for upload api error:
569 // {"upload":{"result":"Failure","error":"unknown-error","code":{"status":5,"filtered":"NGC2207%2BIC2163.jpg"}}}
570 if( _this
.apiUpdateErrorCheck(apiRes
) === false){
571 //error returned false (updated and
574 //check for upload_session key for async upload:
575 if( apiRes
.upload
&& apiRes
.upload
.upload_session_key
){
576 //set the session key
577 _this
.upload_session_key
= apiRes
.upload
.upload_session_key
;
579 //do ajax upload status:
580 _this
.doAjaxUploadStatus();
581 js_log("set upload_session_key: " + _this
.upload_session_key
);
585 if( apiRes
.upload
.imageinfo
&& apiRes
.upload
.imageinfo
.descriptionurl
){
586 var url
= apiRes
.upload
.imageinfo
.descriptionurl
;
588 if( _this
.done_upload_cb
&& typeof _this
.done_upload_cb
== 'function'){
590 $j('#upProgressDialog').dialog('close');
592 _this
.done_upload_cb( url
);
595 bObj
[ gM('return-to-form')] = function(){
596 $j(this).dialog('close');
597 _this
.form_post_override
= false;
599 bObj
[ gM('go-to-resource') ] = function(){
600 window
.location
= url
;
602 _this
.action_done
= true;
603 _this
.updateProgressWin( gM('successfulupload'), gM( 'mv_upload_done', url
), bObj
);
604 js_log('apiRes.upload.imageinfo::'+url
);
610 updateProgressWin:function(title_txt
, msg
, buttons
){
613 title_txt
= _this
.getProgressTitle();
615 msg
= mv_get_loading_img( 'left:40%;top:40px;');
616 $j( '#upProgressDialog' ).dialog('option', 'title', title_txt
);
617 $j( '#upProgressDialog' ).html( msg
);
619 $j('#upProgressDialog').dialog('option','buttons', buttons
);
621 //@@todo should convice the jquery ui people to not use object keys as user msg's
623 bObj
[ gM('ok-button') ] = function(){
624 $j(this).dialog('close');
626 $j('#upProgressDialog').dialog('option','buttons', bObj
);
629 getProgressTitle:function(){
630 return gM('upload-in-progress');
632 getEditForm:function(){
633 if( this.target_edit_from
&& $j( this.target_edit_from
).length
!= 0){
634 return $j( this.target_edit_from
).get(0);
636 //just return the first form fond on the page.
637 return $j('form :first').get(0);
639 updateProgress:function( perc
){
640 //js_log('update progress: ' + perc);
641 $j( '#up-progressbar' ).progressbar('value', parseInt( perc
* 100 ) );
642 $j( '#up-pstatus' ).html( parseInt( perc
* 100 ) + '% - ' );
644 /*update to jQuery.ui progress display type */
645 dispProgressOverlay:function(){
647 //remove old instance:
648 if($j('#upProgressDialog').length
!=0){
649 $j('#upProgressDialog').dialog( 'destroy' ).remove();
652 $j('body').append('<div id="upProgressDialog" ></div>');
654 $j('#upProgressDialog').dialog({
655 title
:_this
.getProgressTitle(),
660 beforeclose: function(event
, ui
) {
661 if( event
.button
==0 && _this
.action_done
=== false){
662 return _this
.cancel_action();
664 //click on button (dont do close action);
668 buttons
: _this
.cancel_button()
670 $j('#upProgressDialog').html(
671 //set initial content:
672 '<div id="up-pbar-container" style="width:90%;height:15px;" >' +
673 '<div id="up-progressbar" style="height:15px;"></div>' +
674 '<div id="up-status-container">'+
675 '<span id="up-pstatus">0% - </span> ' +
676 '<span id="up-status-state">' + gM('uploaded-status') + '</span> ' +
680 //setup progress bar:
681 $j('#up-progressbar').progressbar({
684 //just display an empty progress window
685 $j('#upProgressDialog').dialog('open');
688 cancel_button:function(){
690 var cancelBtn
= new Array();
691 cancelBtn
[ gM('cancel-button') ] = function(){
692 return _this
.cancel_action(this)
696 cancel_action : function( dlElm
){
698 if( confirm( gM('mv-cancel-confim') )){
699 //@@todo (cancel the encode / upload)
700 $j(this).dialog('close');