Rework of libAddMedia. The changes are entirely untested and there may be bugs, but...
authorTim Starling <tstarling@users.mediawiki.org>
Fri, 20 Nov 2009 07:23:08 +0000 (07:23 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Fri, 20 Nov 2009 07:23:08 +0000 (07:23 +0000)
In libAddMedia:
* Made many style changes, renamed many variables.
* Wrote a doc comment for most functions
* Renamed messages:
   * fogg-check_for_fogg -> fogg-check_for_firefogg
   * fogg-for_improved_uplods -> fogg-for_improved_uploads
   * fogg-use_latest_fox -> fogg-use_latest_firefox
   * mwe-upload-stats-fileprogres -> mwe-upload-stats-fileprogress

* Renamed functions:
   * doRemapFormToApi -> remapFormToApi
   * doUploadSwitch -> doUpload
   * proccessIframeResult -> processIframeResult
   * getEditForm -> getForm
   * dispProgressOverlay -> displayProgressOverlay
   * cancel_button -> getCancelButton
   * cancel_action -> onCancel
   * doControlHTML -> createControls
   * getTargetHtml -> getControlHtml
   * doControlBindings -> bindControls
   * getOSlink -> getFirefoggInstallUrl
   * doPreviewControl -> createPreviewControls
   * doRenderPreview -> renderPreview
   * selectFogg -> selectSourceFile
   * selectFoggActions -> updateSourceFileUI
   * saveLocalFogg -> doLocalEncodeAndSave
   * doChunkWithFormData -> doChunkUploadWithFormData
   * proccessPresetControl -> getPresetControlHtml
   * proccessCkControlHTML -> getConfigControlHtml
   * selectByUrl -> selectSourceUrl

* Promoted anonymous functions to methods:
   * onSubmit
   * onAjaxUploadStatusTimer
   * onAjaxUploadStatusResponse
   * onPreviewClick

In mvBaseUploadInterface:
* Made http_copy_upload lazy-initialised
* Made detectUploadMode() do only what it says, moved the actual upload stage to a callback.
* Refactored doUpload(), splitting out doApiCopyUpload() and doPostUpload()
* Refactored apiUpdateErrorCheck() into isApiSuccess() and showApiError()

In mvFirefogg:
* Made have_firefogg, sourceFileInfo lazy initialised
* Rearranged autoEncoderSettings() to make it the accessor getEncoderSettings()
* Rearranged firefoggCheck() to make it the accessor getFirefogg()
* Split encodeDone into the anonymous doEncode() done callbacks, and also the new function onLocalEncodeDone()

In mvAdvFirefogg:
* Refactored autoEncoderSettings() into getEncoderSetings() and updateSourceFileUI()

Elsewhere:
* Fixed spelling error UploadBase::MIN_LENGHT_PARTNAME

includes/api/ApiUpload.php
includes/upload/UploadBase.php
js2/mwEmbed/libAddMedia/mvAdvFirefogg.js
js2/mwEmbed/libAddMedia/mvBaseUploadInterface.js
js2/mwEmbed/libAddMedia/mvFirefogg.js
js2/mwEmbed/php/languages/mwEmbed.i18n.php
js2/uploadPage.js

index 3b8a7c3..faa948a 100644 (file)
@@ -231,7 +231,7 @@ class ApiUpload extends ApiBase {
                                                                'allowed' => $wgFileExtensions
                                                        ) );
                                        break;
-                               case UploadBase::MIN_LENGHT_PARTNAME:
+                               case UploadBase::MIN_LENGTH_PARTNAME:
                                        $this->dieUsage( 'The filename is too short', 'filename-tooshort' );
                                        break;
                                case UploadBase::ILLEGAL_FILENAME:
index 147da3d..e06ee53 100644 (file)
@@ -31,7 +31,6 @@ abstract class UploadBase {
        const VERIFICATION_ERROR = 10;
        const UPLOAD_VERIFICATION_ERROR = 11;
        const HOOK_ABORTED = 11;
-       const MIN_LENGHT_PARTNAME = 14;
 
        const SESSION_VERSION = 2;
 
index 66d2fcf..b132954 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Adds advanced firefogg support (let you control and structure advanced controls over many aspects of video encoding)
+ * Advanced Firefogg support. Lets you control many aspects of video encoding.
  */
 
 //@@todo put all msg text into loadGM json
@@ -14,7 +14,7 @@ loadGM({
        "fogg-cg-advAudio" : "Advanced audio encoding controls",
        "fogg-preset-custom" : "Custom settings",
        "fogg-webvideo-desc" : "Web video Theora, Vorbis 400 kbit\/s and 400px maximum width",
-       "fogg-savebandwith-desc" : "Low bandwith Theora, Vorbis 164 kbit\/s and 200px maximum width",
+       "fogg-savebandwidth-desc" : "Low bandwidth Theora, Vorbis 164 kbit\/s and 200px maximum width",
        "fogg-highquality-desc" : "High quality Theora, Vorbis 1080px maximum width",
        "fogg-videoQuality-title" : "Video quality",
        "fogg-videoQuality-help" : "Used to set the <i>visual quality<\/i> of the encoded video (not used if you set bitrate in advanced controls below).",
@@ -39,7 +39,7 @@ loadGM({
        "fogg-framerate-title" : "Frame rate",
        "fogg-framerate-help" : "The video frame rate. More about <a target=\"_new\" href=\"http:\/\/en.wikipedia.org\/wiki\/Frame_rate\">frame rate<\/a>.",
        "fogg-aspect-title" : "Aspect ratio",
-       "fogg-aspect-help" : "The video aspect ratio can be fraction 4:3 or 16:9. More about <a target=\"_new\" href=\"http:\/\/en.wikipedia.org\/wiki\/Aspect_ratio_%28image%29\">aspect ratios<\/a>.",
+       "fogg-aspect-help" : "The video aspect ratio can be 4:3 or 16:9. More about <a target=\"_new\" href=\"http:\/\/en.wikipedia.org\/wiki\/Aspect_ratio_%28image%29\">aspect ratios<\/a>.",
        "fogg-keyframeInterval-title" : "Key frame interval",
        "fogg-keyframeInterval-help" : "The keyframe interval in frames. Note: Most codecs force keyframes if the difference between frames is greater than keyframe encode size. More about <a href=\"http:\/\/en.wikipedia.org\/wiki\/I-frame\">keyframes<\/a>.",
        "fogg-denoise-title" : "Denoise filter",
@@ -48,7 +48,7 @@ loadGM({
        "fogg-novideo-help" : "disable video in the output",
        "fogg-audioBitrate-title" : "Audio bitrate",
        "fogg-samplerate-title" : "Audio sampling rate",
-       "fogg-samplerate-help" : "set output samplerate (in Hz).",
+       "fogg-samplerate-help" : "set output sample rate (in Hz).",
        "fogg-noaudio-title" : "No audio",
        "fogg-noaudio-help" : "disable audio in the output",
        "fogg-title-title" : "Title",
@@ -69,41 +69,40 @@ loadGM({
        "fogg-contact-help" : "Contact link"
 });
 
-var mvAdvFirefogg = function( iObj ){
+var mvAdvFirefogg = function( iObj ) {
        return this.init( iObj );
 }
 var default_mvAdvFirefogg_config = {
-       // Which config groups to include
-       'config_groups'  : ['preset', 'range', 'quality', 'meta', 'advVideo', 'advAudio'],
+       // Config groups to include
+       'config_groups': [ 'preset', 'range', 'quality', 'meta', 'advVideo', 'advAudio' ],
 
        // If you want to load any custom presets must follow the mvAdvFirefogg.presetConf json outline below
-       'custom_presets'        : {},
+       'custom_presets': {},
 
-       // Any firefog config properties that may need to be excluded from options
-       'exclude_settings' : [],
+       // Any Firefog config properties that may need to be excluded from options
+       'exclude_settings': [],
 
-       // The control container (where we put all the controls)
-       'target_control_container':false
+       // The control container
+       'target_control_container': false
 }
 
 mvAdvFirefogg.prototype = {
-       //the global groupings and titles for for configuration options :
-       config_groups : [ 'preset', 'range', 'quality', 'meta', 'advVideo', 'advAudio'],
-       //list of pre-sets:
-
-       //local instance encoder config:
-       default_local_settings:{
-               'd'     : 'webvideo',
-               'type'  : 'select',
+       // The configuration group names
+       config_groups: [ 'preset', 'range', 'quality', 'meta', 'advVideo', 'advAudio' ],
+
+       // Default configuration for this class
+       default_local_settings: {
+               'default': 'webvideo',
+               'type': 'select',
                'selectVal': ['webvideo'],
-               'group' : "preset",
-               'pSet' : {
-                       'custom':{
+               'group': "preset",
+               'presets': {
+                       'custom': {
                                'descKey': 'fogg-preset-custom',
                                'conf': {}
                        },
                        'webvideo': {
-                               'desc': gM('fogg-webvideo-desc'),
+                               'desc': gM( 'fogg-webvideo-desc' ),
                                'conf': {
                                        'maxSize'      : 400,
                                        'videoBitrate' : 544,
@@ -111,8 +110,8 @@ mvAdvFirefogg.prototype = {
                                        'noUpscaling'  : true,
                                }
                        },
-                       'savebandwith': {
-                               'desc': gM('fogg-savebandwith-desc'),
+                       'savebandwidth': {
+                               'desc': gM( 'fogg-savebandwidth-desc' ),
                                'conf': {
                                        'maxSize'       : 200,
                                        'videoBitrate'  : 164,
@@ -123,8 +122,8 @@ mvAdvFirefogg.prototype = {
                                        'noUpscaling'   : true
                                }
                        },
-                       'hqstream':{
-                               'desc': gM('fogg-highquality-desc'),
+                       'hqstream': {
+                               'desc': gM( 'fogg-highquality-desc' ),
                                'conf': {
                                        'maxSize'      : 1080,
                                        'videoQuality' : 6,
@@ -134,717 +133,851 @@ mvAdvFirefogg.prototype = {
                        },
                }
        },
-       local_settings: {},
 
-       //core firefogg default encoder configuration
-       //see encoder options here: http://www.firefogg.org/dev/index.html
+       // Customised configuration hashtable
+       local_settings: {},
 
-       
-       default_encoder_config : {
-               //base quality settings:
+       // Core Firefogg default encoder configuration
+       // See encoder options here: http://www.firefogg.org/dev/index.html
+       default_encoder_config: {
+               // Base quality settings
                'videoQuality': {
-                       'd'     : 5,                    
-                       'range' : {'min':0,'max':10},
-                       'type'  : 'slider',
-                       'group' : 'quality'
+                       'default'   : 5,
+                       'range'     : { 'min': 0,'max': 10 },
+                       'type'      : 'slider',
+                       'group'     : 'quality'
                },
-               'starttime':{
-                       'type'  : "float",
-                       'group' : "range"                       
+               'starttime': {
+                       'type'      : "float",
+                       'group'     : "range"
                },
-               'endtime':{                     
-                       'type'  : "float",
-                       'group' : "range"       
+               'endtime': {
+                       'type'      : "float",
+                       'group'     : "range"
                },
                'audioQuality': {
-                       'd'                     : 1,
-                       'range'  : {'min':-1,'max':10},
-                       'type'    : 'slider',
-                       'group'  : 'quality',
+                       'default'   : 1,
+                       'range'     : { 'min': -1, 'max': 10 },
+                       'type'      : 'slider',
+                       'group'     : 'quality',
                },
-               'videoCodec':{
-                       'd'                     : "theora",
-                       'selectVal'     : ['theora'],
-                       'type'          : "select",
-                       'group'         : "quality"
+               'videoCodec': {
+                       'default'   : "theora",
+                       'selectVal' : [ 'theora' ],
+                       'type'      : "select",
+                       'group'     : "quality"
                },
-               'audioCodec':{
-                       'd'                     : "vorbis",
-                       'selectVal'     : ['vorbis'],
-                       'type'          : "select",
-                       'group'         : "quality"
+               'audioCodec': {
+                       'default'   : "vorbis",
+                       'selectVal' : [ 'vorbis' ],
+                       'type'      : "select",
+                       'group'     : "quality"
                },
                'width': {
-                       'range'  : {'min':0,'max':1080},
-                       'step'          : 4,
-                       'type'    : 'slider',
-                       'group'  : "quality"
+                       'range'     : { 'min': 0, 'max': 1080 },
+                       'step'      : 4,
+                       'type'      : 'slider',
+                       'group'     : "quality"
                },
                'height': {
-                       'range'  : {'min':0,'max':1080},
-                       'step'          : 4,
-                       'type'          : "slider",
-                       'group'         : "quality"
+                       'range'     : { 'min': 0, 'max' : 1080 },
+                       'step'      : 4,
+                       'type'      : "slider",
+                       'group'     : "quality"
                },
-               //advanced Video control configs:
-               'videoBitrate':{
-                       'range'         : {'min':1, 'max':16778},
-                       'type'          : "slider",
-                       'group'         : "advVideo",
+
+               // Advanced video control
+               'videoBitrate': {
+                       'range'     : { 'min' : 1, 'max' : 16778 },
+                       'type'      : "slider",
+                       'group'     : "advVideo",
                } ,
-               'twopass':{
-                       'type'  : "boolean",
-                       'group' : "advVideo"
+               'twopass': {
+                       'type'      : "boolean",
+                       'group'     : "advVideo"
                },
-               'framerate':{
-                       'd'                     : '24',
-                       'selectVal'     : ['12', '16', {'24000:1001':'23.97'}, '24', '25', {'30000:1001':'29.97'}, '30'],
-                       'type'             : "select",
-                       'group'         : "advVideo"
+               'framerate': {
+                       'default'   : '24',
+                       'selectVal' : [ '12', '16', { '24000:1001' : '23.97' }, '24', '25', 
+                               { '30000:1001' : '29.97' }, '30' ],
+                       'type'      : "select",
+                       'group'     : "advVideo"
                },
-               'aspect':{
-                       'd'                     : '4:3',
-                       'type'          : "select",
-                       'selectVal'     : ['4:3', '16:9'],
-                       'group'         : "advVideo"
+               'aspect': {
+                       'default'   : '4:3',
+                       'type'      : "select",
+                       'selectVal' : [ '4:3', '16:9' ],
+                       'group'     : "advVideo"
                },
-               'keyframeInterval':{
-                       'd'                     : '64',
-                       'range'  : {'min':0,'max':65536},
+               'keyframeInterval': {
+                       'default'   : '64',
+                       'range'     : { 'min': 0, 'max': 65536 },
                        'numberType': 'force keyframe every $1 frames',
-                       'type'           : 'int',
-                       'group'         : 'advVideo'
+                       'type'      : 'int',
+                       'group'     : 'advVideo'
                },
-               'denoise':{
-                       'type'          : "boolean",
-                       'group'         : 'advVideo'
+               'denoise': {
+                       'type'      : "boolean",
+                       'group'     : 'advVideo'
                },
-               'novideo':{
-                       'type'          : "boolean",
-                       'group'         : 'advVideo'
+               'novideo': {
+                       'type'      : "boolean",
+                       'group'     : 'advVideo'
                },
 
-               //advanced Audio control Config:
-               'audioBitrate':{
-                       'range'         : {'min':32,'max':500},
+               // Advanced audio control
+               'audioBitrate': {
+                       'range'     : { 'min': 32, 'max': 500 },
                        'numberType': '$1 kbs',
-                       'type'          : 'slider'
+                       'type'      : 'slider'
                },
-               'samplerate':{
-                       'type'          : 'select',
-                       'selectVal'     : [{'22050':'22 kHz'}, {'44100':'44 khz'}, {'48000':'48 khz'}],
-                       'formatSelect'  : function(val){
-                               return (Math.round(val/100)*10) + ' Hz';
+               'samplerate': {
+                       'type'      : 'select',
+                       'selectVal' : [ { '22050': '22 kHz' }, { '44100': '44 khz' }, { '48000': '48 khz' } ],
+                       'formatSelect' : function( val ) {
+                               return ( Math.round( val / 100 ) * 10 ) + ' Hz';
                        }
                },
-               'noaudio':{
-                       'type'          : 'boolean',
-                       'group'         : 'advAudio'
+               'noaudio': {
+                       'type'      : 'boolean',
+                       'group'     : 'advAudio'
                },
 
-               //meta tags:
-               'title':{
-                       'type'  : 'string',
-                       'group' : 'meta'
+               // Meta tags
+               'title': {
+                       'type'      : 'string',
+                       'group'     : 'meta'
                },
-               'artist':{
-                       'type'  : 'string',
-                       'group' : 'meta'
+               'artist': {
+                       'type'      : 'string',
+                       'group'     : 'meta'
                },
-               'date':{
-                       'group' : 'meta',
-                       'type'  : 'date'
+               'date': {
+                       'group'     : 'meta',
+                       'type'      : 'date'
                },
-               'location':{
-                       'type'  : 'string',
-                       'group' : 'meta'
+               'location': {
+                       'type'      : 'string',
+                       'group'     : 'meta'
                },
-               'organization':{
-                       'type'  : 'string',
-                       'group' : 'meta'
+               'organization': {
+                       'type'      : 'string',
+                       'group'     : 'meta'
                },
-               'copyright':{
-                       'type'  : 'string',
-                       'group' : 'meta'
+               'copyright':  {
+                       'type'      : 'string',
+                       'group'     : 'meta'
                },
-               'license':{
-                       'type'  : 'string',
+               'license': {
+                       'type'      : 'string',
                },
-               'contact':{
-                       'type'  : 'string',
-                       'group' : 'meta'
+               'contact': {
+                       'type'      : 'string',
+                       'group'     : 'meta'
                }
        },
-       init:function( iObj ){
-               //setup a "supported" iObj:
-               for(var i in iObj){
-                       if( typeof default_mvAdvFirefogg_config [i] != 'undefined' ){
-                               this[i] = iObj[i];
+
+       /**
+        * Initialise this object
+        */
+       init: function( options ) {
+               // Set up a supported object:
+               for ( var key in options ) {
+                       if ( typeof default_mvAdvFirefogg_config[key] != 'undefined' ) {
+                               this[key] = options[key];
                        }
                }
-               //inherit the base mvFirefogg class:
-               var myFogg = new mvFirefogg( iObj );
-               for(var i in myFogg){
-                       if( typeof this[i] != 'undefined'){
-                               this[ 'basefogg_' + i ] = myFogg[i];
-                       }else{
-                               this[ i ] = myFogg[i];
+               // Inherit the base mvFirefogg class:
+               var baseFirefogg = new mvFirefogg( options );
+               for ( var key in baseFirefogg ) {
+                       if ( typeof this[key] != 'undefined' ) {
+                               this[ 'basefogg_' + key ] = baseFirefogg[ key ];
+                       } else {
+                               this[ key ] = baseFirefogg[ key ];
                        }
                }
        },
-       setupForm:function(){
-               //call base firefogg form setup
-               basefogg_setupForm();
-
-               //gennerate the control html
-               this.doControlHTML();
-
-               //setup control bindings:
-               this.doControlBindings();
 
+       setupForm: function() {
+               basefogg_setupForm();
+               this.createControls();
+               this.bindControls();
        },
-       doControlHTML: function(){
-               js_log("adv doControlHTML");
+
+       createControls: function() {
+               js_log( "adv createControls" );
                var _this = this;
-               //load presets from cookie:
+               // Load presets from the cookie
                this.loadEncSettings();
 
-               //add base control buttons:
-               this.basefogg_doControlHTML();
-
-               //build the config group outpouts
-               var gdout ='';
-               $j.each(this.config_groups, function(inx, group_key){
-                       gdout+= '<div> '+
-                               '<h3><a href="#" class="gd_'+group_key+'" >' + gM('fogg-cg-'+group_key) + '</a></h3>'+
-                                       '<div>';
-                       //output that group control options:
-                       gdout+='<table width="' + ($j(_this.selector).width()-60) + '" ><tr><td width="35%"></td><td width="65%"></td></tr>';
-                       //output the special prset output
-                       if(group_key=='preset'){
-                               gdout += _this.proccessPresetControl();
+               // Add the base control buttons
+               this.basefogg_createControls();
+
+               // Build the config group output
+               var gdout = '';
+               $j.each( this.config_groups, function( inx, group_key ) {
+                       gdout += '<div> ' +
+                               '<h3><a href="#" class="gd_' + group_key + '" >' + 
+                               gM( 'fogg-cg-' + group_key ) + '</a></h3>' +
+                               '<div>';
+                       // Output this group's control options:
+                       gdout += '<table width="' + ( $j( _this.selector ).width() - 60 ) + '" >' + 
+                               '<tr><td width="35%"></td><td width="65%"></td></tr>';
+                       // If this is the preset group, output the preset control
+                       if ( group_key == 'preset' ) {
+                               gdout += _this.getPresetControlHtml();
                        }
-                       for(var cK in _this.default_encoder_config){
-                               var cConf = _this.default_encoder_config[cK];
-                               if(cConf.group == group_key){
-                                       gdout+= _this.proccessCkControlHTML( cK );
+                       // Output the encoder config controls
+                       for ( var configKey in _this.default_encoder_config ) {
+                               var confEntry = _this.default_encoder_config[ configKey ];
+                               if( confEntry.group == group_key ) {
+                                       gdout += _this.getConfigControlHtml( configKey );
                                }
                        }
-                       gdout+='</table>';
-                       gdout+=         '</div>' +
-                                '</div>';
-
+                       gdout += '</table></div></div>';
                });
-               //add the control container:
-               if(!this.target_control_container){
+               // Add the control container
+               if( !this.target_control_container ) {
                        this.target_control_container = this.selector + ' .control_container';
-                       //set the target contorl container to height
-                       $j(this.selector).append( '<p><div class="control_container"></div>' );
+                       $j( this.selector ).append( '<p><div class="control_container"></div>' );
                }
-               //hide the container and add the output
-               $j(this.target_control_container).hide();
-               $j(this.target_control_container).html( gdout );
-
+               // Hide the container and add the output
+               $j( this.target_control_container ).hide();
+               $j( this.target_control_container ).html( gdout );
        },
-       //custom advanced target rewrites:
-       getTargetHtml:function(target){
-               if(     target=='target_btn_select_file' ||
-                       target=='target_btn_select_new_file'||
-                       target=='target_btn_save_local_file'){
-                       var icon = (target=='target_btn_save_local_file')?'ui-icon-video':'ui-icon-folder-open';
-                       return   '<a class="ui-state-default ui-corner-all ui-icon_link '+
-                                               target +'" href="#"><span class="ui-icon ' + icon + '"/>' +
-                                               gM( 'fogg-' + target.substring(11) ) +
-                                       '</a>';
-               }else if(  target=='target_btn_select_url'){
-                       //return the btnHtml:
-                       return $j.btnHtml( gM( 'fogg-' + target.substring(11) ), target,  'link');
-
-               }else if(       target=='target_use_latest_fox' ||
-                                       target=='target_please_install' ||
-                                       target == 'target_passthrough_mode'){
-                       return '<div style="margin-top:1em;padding: 0pt 0.7em;" class="ui-state-error ui-corner-all ' +
-                                       target + '">' +
-                                       '<p><span style="float: left; margin-right: 0.3em;" class="ui-icon ui-icon-alert"/>'+
-                                       gM( 'fogg-' + target.substring(7)) +'</p>'+
-                               '</div>';
-               }else if( target == 'target_input_file_name'){
-                       return '<br><br><input style="" class="text ui-widget-content ui-corner-all ' + target + '" '+
-                                       'type="text" value="' + gM( 'fogg-' + target.substring(11)) + '" size="60" /> ';
-               }else{
-                       js_log('call : basefogg_getTargetHtml');
-                       return this.basefogg_getTargetHtml(target);
+
+       // Custom advanced target rewrites
+       getControlHtml: function( target ) {
+               switch ( target ) {
+                       case 'target_btn_select_file':
+                       case 'target_btn_select_new_file':
+                       case 'target_btn_save_local_file':
+                               var icon;
+                               if ( target == 'target_btn_save_local_file' ) {
+                                       icon = 'ui-icon-video'
+                               } else {
+                                       icon = 'ui-icon-folder-open';
+                               }
+                               var linkText = gM( target.replace( /^target_btn_/, 'fogg-' ) );
+                               return '<a class="ui-state-default ui-corner-all ui-icon_link ' +
+                                                       target + '" href="#"><span class="ui-icon ' + icon + '"/>' +
+                                                       linkText +
+                                               '</a>';
+                       case 'target_btn_select_url':
+                               return $j.btnHtml( gM( 'fogg-select_url' ), target,  'link' );
+                       case 'target_use_latest_firefox':
+                       case 'target_please_install':
+                       case 'target_passthrough_mode':
+                               var text = gM( target.replace( '/^target_', 'fogg-' ) );
+                               return 
+                                       '<div ' + 
+                                               'style="margin-top:1em;padding: 0pt 0.7em;" ' + 
+                                               'class="ui-state-error ui-corner-all ' +
+                                               target + '">' +
+                                       '<p>' + 
+                                       '<span style="float: left; margin-right: 0.3em;" ' + 
+                                               'class="ui-icon ui-icon-alert"/>' +
+                                       text + 
+                                       '</p>' +
+                                       '</div>';
+                       case 'target_input_file_name':
+                               var text = gM( 'fogg-input_file_name' );
+                               return '<br><br><input style="" ' + 
+                                       'class="text ui-widget-content ui-corner-all ' + target + '" ' +
+                                       'type="text" value="' + text + '" size="60" /> ';
+                       default:
+                               js_log( 'call : basefogg_getTargetHtml' );
+                               return this.basefogg_getTargetHtml( target );
                }
        },
-       proccessPresetControl:function(){
-               var out='';
+
+       getPresetControlHtml: function() {
+               var out = '';
                var _this = this;
-               js_log('proccessPresetControl::');
-               if(typeof this.local_settings.pSet!= 'undefined' ){
-                       out+= '<select class="_preset_select">';
-                       $j.each(this.local_settings.pSet, function(pKey, pSet){
-                               var pDesc = (pSet.descKey) ? gM(pSet.descKey) : pSet.desc;
-                               var sel = (_this.local_settings.d == pKey)?' selected':'';
-                               out+='<option value="'+pKey+'" '+sel+'>'+ pDesc+'</option>';
+               js_log( 'getPresetControlHtml::' );
+               if ( typeof this.local_settings.presets != 'undefined' ) {
+                       out += '<select class="_preset_select">';
+                       $j.each( this.local_settings.presets, function( presetKey, preset ) {
+                               var presetDesc = preset.descKey ? gM( preset.descKey ) : preset.desc;
+                               var sel = ( _this.local_settings['default'] == presetKey ) ? ' selected' : '';
+                               out += '<option value="' + presetKey + '" ' + sel + '>' + presetDesc + '</option>';
                        });
-                       out+='</select>';
-                       }
+                       out += '</select>';
+               }
                return out;
        },
-       proccessCkControlHTML:function( cK ){
-               var cConf =  this.default_encoder_config[cK];
-               var out ='';
-               out+='<tr><td valign="top">'+
-                       '<label for="_' + cK + '">' +
-                        gM( 'fogg-' + cK + '-title') + ':' +
-                        '<span title="' + gM('fogg-help-sticky') + '" class="help_'+ cK + ' ui-icon ui-icon-info" style="float:left"></span>'+
-                        '</label></td><td valign="top">';
-               //if we don't value for this:
-               var dv = ( this.default_encoder_config[cK].d ) ? this.default_encoder_config[cK].d : '';
-               //switch on the config type
-               switch( cConf.type ){
+
+       getConfigControlHtml : function( configKey ) {
+               var configEntry = this.default_encoder_config[configKey];
+               var out = '';
+               out += '<tr><td valign="top">' +
+                       '<label for="_' + configKey + '">' +
+                       gM( 'fogg-' + configKey + '-title' ) + ':' +
+                       '<span title="' + gM( 'fogg-help-sticky' ) + '" ' + 
+                               'class="help_' + configKey + ' ui-icon ui-icon-info" style="float:left">' + 
+                       '</span>' +
+                       '</label></td><td valign="top">';
+               // Get the default value (or an empty string if there is no default)
+
+               var defaultValue = this.default_encoder_config[configKey]['default'];
+               if ( !defaultValue ) {
+                       defaultValue = '';
+               }
+               var type = configEntry.type; // shortcut
+
+               // Switch on the config type
+               switch( type ) {
                        case 'string':
                        case 'date':
                        case 'int':
                        case 'float':
-                               var size = ( cConf.type =='string' ||cConf.type == 'date' )?'14':'4';
-                               out+= '<input size="' + size + '" type="text" class="_' + cK + ' text ui-widget-content ui-corner-all" value="' + dv + '" >' ;
-                       break;
+                               var size = ( type == 'string' || type == 'date' ) ? '14' : '4';
+                               out += '<input ' + 
+                                       'size="' + size + '" ' + 
+                                       'type="text" ' + 
+                                       'class="_' + configKey + ' text ui-widget-content ui-corner-all" ' + 
+                                       'value="' + defaultValue + '" >';
+                               break;
                        case 'boolean':
-                               var checked_attr = (dv===true)?' checked="true"':'';
-                               out+='<input type="checkbox" class="_'+cK+ ' ui-widget-content ui-corner-all" ' + checked_attr + '>';
-                       break;
+                               var checked_attr = ( defaultValue === true ) ? ' checked="true"' : '';
+                               out += '<input ' + 
+                                       'type="checkbox" ' + 
+                                       'class="_' + configKey + ' ui-widget-content ui-corner-all" ' + 
+                                       checked_attr + '>';
+                               break;
                        case 'slider':
-                               var strMax = this.default_encoder_config[ cK ].range.max + '';
-                               maxdigits = strMax.length +1;
-                               out+= '<input type="text" maxlength="'+maxdigits+'" size="' +maxdigits + '" '+
-                                       'class="_'+cK+ ' text ui-widget-content ui-corner-all" style="display:inline;border:0; color:#f6931f; font-weight:bold;" ' +
-                                       'value="' + dv + '" >' +
-                                       '<div class="slider_' + cK + '"></div>';
-                       break;
+                               var strMax = this.default_encoder_config[ configKey ].range.max + '';
+                               maxDigits = strMax.length + 1;
+                               out += '<input ' + 
+                                       'type="text" ' + 
+                                       'maxlength="' + maxDigits + '" ' + 
+                                       'size="' + maxDigits + '" ' +
+                                       'class="_' + configKey + ' text ui-widget-content ui-corner-all" ' + 
+                                       'style="display:inline;border:0; color:#f6931f; font-weight:bold;" ' +
+                                       'value="' + defaultValue + '" >' +
+                                       '<div class="slider_' + configKey + '"></div>';
+                               break;
                        case 'select':
-                               out+= '<select class="_' + cK + '">'+
+                               out += '<select class="_' + configKey + '">' +
                                                '<option value=""> </option>';
-                               for(var i in cConf.selectVal){
-                                       var val = cConf.selectVal[i];
-                                       if(typeof val == 'string'){
-                                               var sel = (     cConf.selectVal[i] == val)?' selected':'';
-                                               out+= '<option value="'+val+'"'+sel+'>'+val+'</option>';
-                                       }else if(typeof val == 'object'){
-                                               for(var key in val){
+                               for ( var i in configEntry.selectVal ) {
+                                       var val = configEntry.selectVal[i];
+                                       if ( typeof val == 'string' ) {
+                                               var sel = ( configEntry.selectVal[i] == val ) ? ' selected' : '';
+                                               out += '<option value="' + val + '"'+sel+'>' + val + '</option>';
+                                       } else if ( typeof val == 'object' ) {
+                                               for ( var key in val ) {
                                                        hr_val = val[key];
                                                }
-                                               var sel = ( cConf.selectVal[i] == key )?' selected':'';
+                                               var sel = ( configEntry.selectVal[i] == key ) ? ' selected' : '';
 
-                                               out+= '<option value="'+key+'"'+sel+'>'+hr_val+'</option>';
+                                               out += '<option value="' + key + '"' + sel + '>' + hr_val + '</option>';
                                        }
                                }
-                               out+='</select>';
-                       break;
+                               out += '</select>';
+                               break;
                }
-               //output the help row:          
-               out+='<div class="helpRow_' + cK + '">'+
-                               '<span class="helpClose_' + cK + ' ui-icon ui-icon-circle-close" '+
-                               'title="Close Help"'+
-                               'style="float:left"/>'+
-                               gM('fogg-'+ cK + '-help') +
-                        '</div>';              
-               out+='</td></tr><tr><td colspan="2" height="10"></td></tr>';
+               // output the help row:
+               out += '<div class="helpRow_' + configKey + '">' +
+                               '<span class="helpClose_' + configKey + ' ui-icon ui-icon-circle-close" ' +
+                               'title="Close Help"' +
+                               'style="float:left"/>' +
+                               gM( 'fogg-'+ configKey + '-help' ) +
+                               '</div>';
+               out += '</td></tr><tr><td colspan="2" height="10"></td></tr>';
                return out;
        },
-       selectByUrl:function(){
-               var urlValue = prompt("Please enter the source media url you would like to transcode from.","http://");
-               if( urlValue ){
-                       //update the mode:
-                       this.sourceMode = 'url';
-                       this.sourceUrl = urlValue;
-                       this.selectFoggActions();
-                       this.autoEncoderSettings();
-                       //update the input target
-                       $j(this.target_input_file_name).unbind().val( urlValue ).removeAttr('readonly');
+
+       /**
+        * Show a dialog box asking the user to select a source URL.
+        * FIXME: half-written, doesn't work at all. 
+        */
+       selectSourceUrl: function() {
+               // FIXME: i18n
+               var url = prompt( "Please enter the source media url you would like " + 
+                               "to transcode from.", "http://" );
+               if ( !url ) {
+                       return;
                }
+
+               // update the mode:
+               this.sourceMode = 'url';
+               this.sourceUrl = url;
+               this.clearSourceInfoCache();
+               this.updateSourceFileUI();
+               // update the input target
+               $j( this.target_input_file_name ) 
+                       .unbind()
+                       .val( url )
+                       .removeAttr( 'readonly' );
        },
-       doControlBindings:function(){
+
+       bindControls: function() {
                var _this = this;
-               _this.basefogg_doControlBindings();
-               //show the select by url if present:
-               /*$j( this.target_btn_select_url ).unbind(
-                       ).attr('disabled', false
-                       ).css({'display':'inline'}
-                       ).click(function(){
-                               _this.selectByUrl();
-               });
+               _this.basefogg_bindControls();
+
+               // Show the select by URL if present
+               /*$j( this.target_btn_select_url ).unbind()
+                       .attr( 'disabled', false )
+                       .css( { 'display': 'inline' } )
+                       .click( function() {
+                               _this.selectSourceUrl();
+                       });
                */
 
-
-               //hide the base advanced controls untill a file is selected:
-               $j(this.target_control_container).hide();
+               // Hide the base advanced controls until a file is selected:
+               $j( this.target_control_container ).hide();
 
                var helpState = {};
-               //do some display tweeks:
-               js_log('tw:' + $j(this.selector).width() +
-                               'ssf:' + $j(this.target_btn_select_new_file).width() +
-                               'sf:' +  $j(this.target_btn_save_local_file).width() );
+               // Do some display tweaks
+               js_log( 'tw:' + $j( this.selector ).width() +
+                       ' ssf:' + $j( this.target_btn_select_new_file ).width() +
+                       ' sf:' + $j( this.target_btn_save_local_file ).width() );
 
-               //set width to 250
-               $j(this.target_input_file_name).width( 250 );
+               // Set width to 250
+               $j( this.target_input_file_name ).width( 250 );
 
-               //special preset action:
-               $j(this.selector + ' ._preset_select').change(function(){
-                       _this.updatePresetSelection( $j(this).val() );
+               // Special preset action
+               $j( this.selector + ' ._preset_select' ).change( function() {
+                       _this.updatePresetSelection( $j( this ).val() );
                });
 
-               //bind control actions
-               for(var cK in this.default_encoder_config){
-                       var cConf =  this.default_encoder_config[cK];
-                               
-                       //initial state is hidden:
-                       $j( this.selector + ' .helpRow_' + cK).hide();
-                       $j(this.selector + ' .help_' + cK).click(function(){
-                               //get the ckId (assume its the last class)
-                               var cK = _this.getClassId(this, 'help_');
-
-                               if(helpState[cK]){
-                                       $j(_this.selector + ' .helpRow_' + cK).hide('slow');
-                                       helpState[cK] = false;
-                               }else{
-                                       $j(_this.selector + ' .helpRow_' + cK).show('slow');
-                                       helpState[cK] = true;
-                               }
-                               return false;
-                       }).hover(
-                               function(){
-                                       //get the ckId (assume its the last class)
-                                       var cK = _this.getClassId(this, 'help_');
-                                       $j( _this.selector + ' .helpRow_' + cK).show('slow');
-                               },function(){
-                                       var cK = _this.getClassId(this, 'help_');
-                                       if(!helpState[cK])
-                                               $j( _this.selector + ' .helpRow_' + cK).hide('slow')
-                               }
-                       );
-                       $j( _this.selector + ' .helpClose_' + cK).click(function(){
-                               js_log("close help: " +cK);
-                               //get the ckId (assume its the last class)
-                               var cK = _this.getClassId(this, 'helpClose_');
-                               $j(_this.selector + ' .helpRow_' + cK).hide('slow');
-                               helpState[cK] = false;
-                               return false;
-                       }).css('cursor', 'pointer');                    
-
-                       //setup bindings for change values: (validate input)
-       
-                       switch( cConf.type ){
+               // Bind control actions
+               for ( var configKey in this.default_encoder_config ) {
+                       var confEntry =  this.default_encoder_config[configKey];
+
+                       // Initial state is hidden
+                       $j( this.selector + ' .helpRow_' + configKey ).hide();
+
+                       $j( this.selector + ' .help_' + configKey )
+                               .click(
+                                       function() {
+                                               // Get the config key (assume it's the last class)
+                                               var configKey = _this.getClassId( this, 'help_' );
+
+                                               if ( helpState[configKey] ) {
+                                                       $j( _this.selector + ' .helpRow_' + configKey ).hide( 'slow' );
+                                                       helpState[configKey] = false;
+                                               } else {
+                                                       $j( _this.selector + ' .helpRow_' + configKey ).show( 'slow' );
+                                                       helpState[configKey] = true;
+                                               }
+                                               return false;
+                                       }
+                               )
+                               .hover(
+                                       function() {
+                                               // get the config key (assume it's the last class)
+                                               var configKey = _this.getClassId( this, 'help_' );
+                                               $j( _this.selector + ' .helpRow_' + configKey ).show( 'slow' );
+                                       },
+                                       function() {
+                                               var configKey = _this.getClassId( this, 'help_' );
+                                               if( !helpState[configKey] )
+                                                       $j( _this.selector + ' .helpRow_' + configKey ).hide( 'slow' )
+                                       }
+                               );
+
+                       $j( this.selector + ' .helpClose_' + configKey )
+                               .click(
+                                       function() {
+                                               js_log( "close help: " + configKey );
+                                               // get the config key (assume it's the last class)
+                                               var configKey = _this.getClassId( this, 'helpClose_' );
+                                               $j( _this.selector + ' .helpRow_' + configKey ).hide( 'slow' );
+                                               helpState[configKey] = false;
+                                               return false;
+                                       }
+                               )
+                               .css( 'cursor', 'pointer' );
+
+                       // Set up bindings for the change events (validate input)
+
+                       switch ( confEntry.type ) {
                                case 'boolean':
-                                       $j(_this.selector + ' ._'+cK).click(function(){
-                                               _this.updateLocalValue(  _this.getClassId(this), $j(this).is(":checked") );
-                                               _this.updatePresetSelection('custom');
-                                       })
-                               break;
+                                       $j( this.selector + ' ._' + configKey)
+                                               .click( function() {
+                                                       _this.updateLocalValue( _this.getClassId( this ), 
+                                                               $j( this ).is( ":checked" ) );
+                                                       _this.updatePresetSelection( 'custom' );
+                                               });
+                                       break;
                                case 'select':
                                case 'string':
                                case 'int':
                                case 'float':
                                        //@@check if we have a validate function on the string
-                                       $j(_this.selector + ' ._'+cK).change(function(){
-                                               $j(this).val( _this.updateLocalValue(
-                                                       _this.getClassId(this),
-                                                       $j(this).val() ));
-                                               _this.updatePresetSelection('custom');
+                                       $j( this.selector + ' ._' + configKey ).change( function() {
+                                               $j( this ).val( _this.updateLocalValue(
+                                                       _this.getClassId( this ),
+                                                       $j( this ).val() ) );
+                                               _this.updatePresetSelection( 'custom' );
                                        })
-                               break;
+                                       break;
                                case 'date':
-                                       $j(_this.selector + ' ._'+cK).datepicker({
+                                       $j( this.selector + ' ._' + configKey ).datepicker({
                                                        changeMonth: true,
                                                        changeYear: true,
                                                        dateFormat: 'd MM, yy',
-                                                       onSelect: function(dateText) {
-                                                               _this.updateInterfaceValue(_this.getClassId(this), dateText);
+                                                       onSelect: function( dateText ) {
+                                                               _this.updateInterfaceValue( _this.getClassId( this ), dateText );
                                                        }
                                        });
-                               break;
+                                       break;
                                case 'slider':
-                                       $j(this.selector + ' .slider_' + cK ).slider({
+                                       var sliderId = _this.getClassId( this, 'slider_' );
+                                       $j( this.selector + ' .slider_' + configKey ).slider({
                                                range: "min",
                                                animate: true,
-                                               step: (cConf.step)?cConf.step:1,
-                                               value: $j( this.selector +' ._' + cK ).val(),
-                                               min: this.default_encoder_config[ cK ].range.min,
-                                               max: this.default_encoder_config[ cK ].range.max,
-                                               slide: function(event, ui) {
-                                                       $j( _this.selector + ' ._' + _this.getClassId(this, 'slider_') ).val( ui.value );
-       
-                                                       //maintain source video aspect ratio:
-                                                       if(_this.getClassId(this, 'slider_') == 'width'){
-                                                               var hv = parseInt((_this.sourceFileInfo.video[0]['height']/_this.sourceFileInfo.video[0]['width'])* ui.value );
-                                                               //update the height value:        the new height value is > that original the slider:
-                                                               if(hv > _this.updateInterfaceValue('height', hv))
+                                               step: confEntry.step ? confEntry.step : 1,
+                                               value: $j( this.selector + ' ._' + configKey ).val(),
+                                               min: this.default_encoder_config[ configKey ].range.min,
+                                               max: this.default_encoder_config[ configKey ].range.max,
+                                               slide: function( event, ui ) {
+                                                       $j( _this.selector + ' ._' + sliderId ).val( ui.value );
+
+                                                       // Maintain source video aspect ratio
+                                                       if ( sliderId == 'width' ) {
+                                                               var sourceHeight = _this.sourceFileInfo.video[0]['height'];
+                                                               var sourceWidth = _this.sourceFileInfo.video[0]['width'];
+                                                               var newHeight = parseInt( sourceHeight / sourceWidth * ui.value );
+                                                               // Reject the update if the new height is above the maximum
+                                                               if ( newHeight > _this.updateInterfaceValue( 'height', newHeight ) )
                                                                        return false;
                                                        }
-                                                       if(_this.getClassId(this, 'slider_') == 'height'){
-                                                               var wv = parseInt((_this.sourceFileInfo.video[0]['width']/_this.sourceFileInfo.video[0]['height'])* ui.value );
-                                                               //update the height value:        the new height value is > that original the slider:
-                                                               if(wv > _this.updateInterfaceValue('width', wv))
+                                                       if ( sliderId == 'height' ) {
+                                                               var sourceHeight = _this.sourceFileInfo.video[0]['height'];
+                                                               var sourceWidth = _this.sourceFileInfo.video[0]['width'];
+                                                               var newWidth = parseInt( sourceWidth / sourceHeight * ui.value );
+                                                               // Reject the update if the new width is above the maximum
+                                                               if ( newWidth > _this.updateInterfaceValue( 'width', wv ) )
                                                                        return false;
                                                        }
                                                },
-                                               change: function(event, ui){
-                                                       //update the local settings
-                                                       _this.updateLocalValue( _this.getClassId(this, 'slider_'), ui.value);
-                                                       _this.updatePresetSelection('custom');
+                                               change: function( event, ui ) {
+                                                       _this.updateLocalValue( sliderId, ui.value );
+                                                       _this.updatePresetSelection( 'custom' );
                                                }
-                                       })
-                                       $j( this.selector +' ._' + cK).change(function(){
-                                               var scid = _this.getClassId(this);
-                                               var valdVal = _this.updateLocalValue(scid.substr(1),$j(this).val() );
-                                               _this.updatePresetSelection('custom');
-                                               //(validate user form input)
-                                               $j(this).val(valdVal);
-                                               //update the slider
-                                               js_log("update: " + _this.selector + ' .slider' + scid);
-                                               $j(_this.selector + ' .slider'+ scid).slider('option', 'value', valdVal );
                                        });
-                               break
+
+                                       $j( this.selector + ' ._' + configKey ).change( function() {
+                                               var classId = _this.getClassId( this );
+                                               var validValue = _this.updateLocalValue( classId.substr( 1 ), 
+                                                       $j( this ).val() );
+                                               _this.updatePresetSelection( 'custom' );
+                                               // Change it to the validated value
+                                               $j( this ).val( validValue );
+                                               // update the slider
+                                               js_log( "update: " + _this.selector + ' .slider' + classId );
+                                               $j( _this.selector + ' .slider' + classId )
+                                                       .slider( 'option', 'value', validValue );
+                                       });
+                                       break;
                        }
                }
-               
-               $j(this.target_control_container).accordion({
+
+               $j( this.target_control_container ).accordion({
                        header: "h3",
                        collapsible: true,
                        active: false,
                        fillSpace: true
                });
 
-               //do config value updates if any
+               // Do the config value updates if there are any
                this.updateValuesInHtml();
        },
-       updatePresetSelection:function( pKey ){
-               //update the local key:
-               this.local_settings.d = pKey;
-                //js_log('update preset desc: '+ pKey);
-               var pset_desc = '';
-               if(this.local_settings.pSet[ pKey  ].desc){
-                       pset_desc = this.local_settings.pSet[ pKey  ].desc;
-               }else{
-                       pset_desc = gM('fogg-preset-'+ pKey);
+
+       /**
+        * Update the UI due to a change in preset
+        */
+       updatePresetSelection: function( presetKey ) {
+               // Update the local configuration
+               this.local_settings['default'] = presetKey;
+               // js_log( 'update preset desc: ' + presetKey );
+               var presetDesc = '';
+               if ( this.local_settings.presets[presetKey].desc ) {
+                       presetDesc = this.local_settings.presets[presetKey].desc;
+               } else {
+                       presetDesc = gM( 'fogg-preset-' + presetKey );
                }
-               //update the preset title:
-               $j( this.selector + ' .gd_preset' ).html(
-                       gM('fogg-cg-preset', pset_desc)
-               );
-               //update the selector
-               $j(this.selector + ' ._preset_select').val(pKey);
+               // Update the preset title
+               $j( this.selector + ' .gd_preset' )
+                       .html( gM( 'fogg-cg-preset', presetDesc ) );
+               // update the selector
+               $j( this.selector + ' ._preset_select' ).val( presetKey );
        },
+
        /*
-        * updates the interface
+        * Update the interface due to a change in a particular config key
         */
-       updateInterfaceValue:function(confKey, val){
+       updateInterfaceValue: function( confKey, val ) {
                var _this = this;
-               if(!val){
-                       return ;
+               if ( !val ) {
+                       return;
                }
-               //js_log('updateInterfaceValue:: ' + confKey + ' v:' + val + ' cv:'+ _this.selector + '._'+ confKey+' len:' + $j(_this.selector + ' ._'+confKey).length );
-               //lookup the type
-               if(typeof this.default_encoder_config[confKey] == 'undefined'){
-                       js_error('error: missing default key: '+ confKey);
+               // Look up the type
+               if ( typeof this.default_encoder_config[confKey] == 'undefined' ) {
+                       js_error( 'error: missing default key: ' + confKey );
                        return false;
                }
 
-               //update the local value (if not already up-to-date
-               if( this.local_settings.pSet['custom']['conf'][confKey] != val ){
-                       val = this.updateLocalValue(confKey, val);
+               // Update the local value (if it's not already up-to-date)
+               if ( this.local_settings.presets['custom']['conf'][confKey] != val ) {
+                       val = this.updateLocalValue( confKey, val );
                }
-               //update the text filed:
-               $j(_this.selector + ' ._'+confKey).val( val );
-               //update the interaface widget:
-               switch(this.default_encoder_config[confKey].type){
+               // Update the text field
+               $j( _this.selector + ' ._' + confKey ).val( val );
+               // Update the interface widget
+               switch ( this.default_encoder_config[confKey].type ) {
                        case 'slider':
-                               $j(_this.selector + ' .slider_' + confKey).slider('option',
-                                               'value', $j(_this.selector + ' ._'+ confKey).val() );
-                       break;
+                               $j( _this.selector + ' .slider_' + confKey )
+                                       .slider( 'option', 'value', $j( _this.selector + ' ._' + confKey ).val() );
+                               break;
                }
                return val;
        },
-       updateLocalValue:function(confKey, value){
-               //update the local value (return the value we acutally set)
-               if(typeof this.default_encoder_config[confKey] == 'undefined'){
-                 js_log("Error:could not update conf key:" + confKey)
-                 return value;
+
+       /**
+        * Validate the new config setting, fixing its type and bounding it within a 
+        * range if required. Update the configuration with the validated value and 
+        * return it.
+        */
+       updateLocalValue: function( confKey, value ) {
+               if ( typeof this.default_encoder_config[confKey] == 'undefined' ) {
+                       js_log( "Error: could not update conf key: " + confKey )
+                       return value;
                }
-               dec = this.default_encoder_config[confKey];
-               if(dec.range){
-                       value = parseInt(value);
-                       var min = ( dec.range.local_min) ? dec.range.local_min  :dec.range.min;
-                       if(value < min)
+               var confEntry = this.default_encoder_config[confKey];
+               var range = confEntry.range;
+               if ( range ) {
+                       value = parseInt( value );
+                       var min = ( range.local_min ) ? range.local_min : range.min;
+                       if ( value < min )
                                value = min;
-                       var max = ( dec.range.local_max) ? dec.range.local_max : dec.range.max
-                       if(value > max)
+                       var max = ( range.local_max ) ? range.local_max : range.max;
+                       if (value > max )
                                value = max;
                }
-               if(dec.type=='int')
-                       value = parseInt(value);
+               if ( confEntry.type == 'int' )
+                       value = parseInt( value );
 
-               //step value:
-               /*if(dec.step){
-                       if((value % dec.step)!=0){
-                               value = value - (value % dec.step);
+               // step value:
+               /* if( confEntry.step ) {
+                       if ( ( value % confEntry.step ) != 0 ) {
+                               value = value - (value % confEntry.step);
                        }
                }*/
 
-               js_log('update:local_settings:custom:conf:'+ confKey + ' = ' + value);
-               this.local_settings.pSet['custom']['conf'][confKey] = value;
+               js_log( 'update:local_settings:custom:conf:' + confKey + ' = ' + value );
+               this.local_settings.presets['custom']['conf'][confKey] = value;
 
                return value;
        },
-       getLocalValue:function(confKey){
-               return this.local_settings.pSet['custom']['conf'][confKey];
+
+       /**
+        * Get a local config value from the custom preset
+        */
+       getLocalValue: function( confKey ) {
+               return this.local_settings.presets['custom']['conf'][confKey];
        },
-       getClassId:function(elm, rmstr){
-               var elmclass = $j(elm).attr("class").split(' ').slice(0,1).toString();
-               if(rmstr){
-                       return elmclass.replace( rmstr, '' );
-               }else{
-                       //strip leading underscore:
-                       return (elmclass[0]=='_')?elmclass.substr(1):elmclass;
+
+       /**
+        * Given an element or selector, get its primary class, and strip a given 
+        * prefix from it.
+        *
+        * If no prefix is given, "_" is assumed.
+        */
+       getClassId: function( element, prefix ) {
+               var eltClass = $j( element ).attr( "class" ).split( ' ' ).slice( 0, 1 ).toString();
+
+               if ( !prefix ) {
+                       prefix = '_';
+               }
+               if ( eltClass.substr( 0, prefix.length ) == prefix ) {
+                       eltClass = eltClass.substr( prefix.length );
                }
+               return eltClass;
        },
-       /*
-        * sets up the autoEncoder settings
+
+       /**
+        * Get the appropriate encoder settings for the current Firefogg object, 
+        * into which a video has already been selected. Overrides the base method.
         */
-       autoEncoderSettings:function(){
-               var _this = this;
-               //do the base encoder settings setup:
-               this.basefogg_autoEncoderSettings();
-               
-               //special case see if we already have ogg video in adv encoder expose encode settings anyway: 
-               if( _this.isOggFormat() ){
-                       _this.encoder_settings['passthrough'] = false;
+       getEncoderSettings: function() {
+               if ( this.current_encoder_settings != null ) {
+                       return this.current_encoder_settings;
                }
-               
-               //make sure we are "encoding" if not display not a video file eror:
-               if( this.encoder_settings['passthrough'] ){
-                       js_log("in passthrough mode (hide control)");
-                       //hide all controls
-                       //display not encodable video
-                       $j(this.target_control_container).hide('slow');
-                       $j(this.target_passthrough_mode).show('slow');
-                       return ;
+
+               // Call the base function
+               // Note that settings will be a reference and can be modified
+               var settings = this.basefogg_getEncoderSettings();
+
+               // Allow re-encoding of files that are already ogg (unlike in the base class)
+               if ( this.isOggFormat() ) {
+                       settings['passthrough'] = false;
                }
-               //restore display:
-               $j(this.target_control_container).show('slow');
-               $j(this.target_passthrough_mode).hide('slow');
-
-               //do setup settings based on local_settings /default_encoder_config with sourceFileInfo
-               //see: http://firefogg.org/dev/sourceInfo_example.html
-               var setValues = function(k, val, maxVal) {
-                       if( k !== false){
-                               //update the value if unset:
-                               _this.updateLocalValue(k, val);
+       },
+
+       /**
+        * Do the necessary UI updates due to the source file changing.
+        * Overrides the parent method.
+        */
+       updateSourceFileUI: function() {
+               var _this = this;
+
+               // Call the parent
+               _this.basefogg_updateSourceFileUI();
+
+               var settings = this.getEncoderSettings();
+               var fileInfo = this.getSourceFileInfo();
+
+               // In passthrough mode, hide encoder controls
+               if ( settings['passthrough'] ) {
+                       js_log( "in passthrough mode (hide control)" );
+                       $j( this.target_control_container ).hide( 'slow' );
+                       $j( this.target_passthrough_mode ).show( 'slow' );
+                       return;
+               }
+
+               // Show encoder controls
+               $j( this.target_control_container ).show( 'slow' );
+               $j( this.target_passthrough_mode ).hide( 'slow' );
+
+               // do set up settings based on local_settings /default_encoder_config with sourceFileInfo
+               // see: http://firefogg.org/dev/sourceInfo_example.html
+               var setValues = function( k, val, maxVal ) {
+                       if ( k !== false ) {
+                               // update the value if unset:
+                               _this.updateLocalValue( k, val );
                        }
-                       if( maxVal ){
-                                //update the local range:
-                               if(_this.default_encoder_config[k].range){
+                       if ( maxVal ) {
+                               // update the local range:
+                               if ( _this.default_encoder_config[k].range ) {
                                        _this.default_encoder_config[k].range.local_max = maxVal;
                                }
                        }
                }
-               //container level settings
-               for(var i in this.sourceFileInfo){
-                       var val = this.sourceFileInfo[i];
+               // container level settings
+               for ( var i in fileInfo ) {
+                       var val = fileInfo[i];
                        var k = false;
-                       var maxVal= false;
-                       switch(i){
-                               //do nothing with these:
+                       var maxVal = false;
+                       switch ( i ) {
+                               // do nothing with these:
                                case 'bitrate':
                                        k = 'videoBitrate';
-                                       maxVal = (val*2 > this.default_encoder_config[k])?this.default_encoder_config[k]:val*2;
-                               break;
+                                       if ( val * 2 > this.default_encoder_config[k] ) {
+                                               maxVal = this.default_encoder_config[k];
+                                       } else {
+                                               maxVal = val * 2;
+                                       }
+                                       break;
                        }
-                       setValues(k, val, maxVal);
+                       setValues( k, val, maxVal );
                }
-               //video stream settings
-               for(var i in this.sourceFileInfo.video[0]){
-                       var val = this.sourceFileInfo.video[0][i];
+               // video stream settings
+               for ( var i in fileInfo.video[0] ) {
+                       var val = fileInfo.video[0][i];
                        var k = false;
                        var maxVal= false;
-                       switch(i){
+                       switch( i ) {
                                case 'width':
                                case 'height':
                                        k = i;
                                        maxVal = val;
-                               break;
+                                       break;
                        }
-                       setValues(k, val, maxVal);
+                       setValues( k, val, maxVal );
                }
-               //audio stream settings, assumes for now there is only one stream
-               for(var i in this.sourceFileInfo.audio[0]){
-                       var val = this.sourceFileInfo.audio[0][i];
+               // audio stream settings, assumes for now thare is only one stream
+               for ( var i in fileInfo.audio[0] ) {
+                       var val = fileInfo.audio[0][i];
                        var k = false;
-                       var maxVal= false;
-                       switch(i){
+                       var maxVal = false;
+                       switch ( i ) {
                                case 'bitrate':
                                        k = 'audioBitrate';
-                                       maxVal = (val*2 > this.default_encoder_config[k])?this.default_encoder_config[k]:val*2;
-                               break;
+                                       if ( val * 2 > this.default_encoder_config[k] ) {
+                                               maxVal = this.default_encoder_config[k];
+                                       } else {
+                                               maxVal = val * 2;
+                                       }
+                                       break;
                        }
-                       setValues(k, val, maxVal);
+                       setValues( k, val, maxVal );
                }
 
-               //set all values to new default ranges & update slider:
-               $j.each(this.default_encoder_config, function(inx, val){
-                       if($j(_this.selector + ' ._'+inx).length!=0){
-                               if(typeof val.range != 'undefined'){
-                                       //udate slider range
-                                       var new_max = (val.range.local_max)?val.range.local_max: val.range.max
-                                       $j( _this.selector + ' .slider_'+inx).slider('option', 'max', new_max);
-
-                                       //update slider/input value:
-                                       _this.updateInterfaceValue(inx, _this.local_settings.pSet['custom']['conf'][inx]);
+               // set all values to new default ranges & update slider:
+               $j.each( this.default_encoder_config, function( inx, val ) {
+                       if ( $j( _this.selector + ' ._' + inx ).length != 0 ) {
+                               if ( typeof val.range != 'undefined' ) {
+                                       // update slider range
+                                       var new_max = (val.range.local_max) ? val.range.local_max : val.range.max
+                                       $j( _this.selector + ' .slider_' + inx ).slider( 'option', 'max', new_max );
+
+                                       // update slider/input value:
+                                       _this.updateInterfaceValue( inx, 
+                                               _this.local_settings.presets['custom']['conf'][inx] );
                                }
                        }
                });
-               //update values
+               // update values
                this.updateValuesInHtml();
        },
-       doEncode:function(){
-               //update the encoder settings (from local settings)
-               pKey = this.local_settings.d;
-               this.encoder_settings = this.local_settings.pSet[ pKey ].conf;
+
+       doEncode: function() {
+               // update the encoder settings (from local settings)
+               pKey = this.local_settings['default'];
+               this.encoder_settings = this.local_settings.presets[ pKey ].conf;
                this.basefogg_doEncode();
        },
-       updateValuesInHtml:function(){
-               js_log('updateValuesInHtml::');
+
+       /**
+        * Set the HTML control values to whatever is currently present in this.local_settings
+        */
+       updateValuesInHtml: function() {
+               js_log( 'updateValuesInHtml::' );
                var _this = this;
-               var pKey = this.local_settings.d;
+               var pKey = this.local_settings['default'];
                this.updatePresetSelection( pKey );
 
-               //set the actual HTML & widgets based on any local settings values:
-               $j.each(_this.local_settings.pSet['custom']['conf'], function(inx, val){
-                       if($j(_this.selector + ' ._'+inx).length !=0){
-                               $j(_this.selector + ' ._'+inx).val( val );
+               // set the actual HTML & widgets based on any local settings values:
+               $j.each( _this.local_settings.presets['custom']['conf'], function( inx, val ) {
+                       if ( $j( _this.selector + ' ._' + inx ).length != 0 ) {
+                               $j( _this.selector + ' ._' + inx ).val( val );
                        }
                });
        },
-       //restors settings from a cookie if you have them)
-       loadEncSettings:function( force ){
-               if($j.cookie('fogg_encoder_config')){
-                       js_log("load:fogg_encoder_config from cookie ");
-                       this.local_settings = JSON.parse( $j.cookie('fogg_settings') );
+
+       /**
+        * Restore settings from a cookie (if available)
+        */
+       loadEncSettings: function( force ) {
+               if ( $j.cookie( 'fogg_encoder_config' ) ) {
+                       js_log( "load:fogg_encoder_config from cookie " );
+                       this.local_settings = JSON.parse( $j.cookie( 'fogg_settings' ) );
                }
-               //set to default if not loaded yet:
-               if( this.local_settings &&  this.local_settings.pSet && this.local_settings.pSet['custom']['conf']){
-                       js_log('local settings already populated');
-               }else{
-                       this.local_settings  = this.default_local_settings;
+               // set to default if not loaded yet:
+               if ( this.local_settings && this.local_settings.presets 
+                       && this.local_settings.presets['custom']['conf'] ) 
+               {
+                       js_log( 'local settings already populated' );
+               } else {
+                       this.local_settings = this.default_local_settings;
                }
-
        },
-       //clear preset settings:
-       clearSettings:function(force){
 
+       /**
+        * Clear preset settings
+        * FIXME: not called, does nothing
+        */
+       clearSettings: function( force ) {
        },
-       //save settings to the cookie
-       saveEncSettings:function(){
-               $j.cookie('fogg_settings', JSON.stringify( this.local_settings ) );
+
+       /**
+        * Save the current encoder settings to a cookie.
+        */
+       saveEncSettings: function() {
+               $j.cookie( 'fogg_settings', JSON.stringify( this.local_settings ) );
        }
 };
index 39de0e7..d9c01d7 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * The base Upload Interface for uploading.
+ * The base upload interface.
  *
  * This base upload class is optionally extended by Firefogg
  *
@@ -9,7 +9,7 @@ loadGM({
        "mwe-upload-in-progress" : "Upload in progress (do not close this window)",
        "mwe-upload-transcoded-status" : "Transcoded",
        "mwe-uploaded-status" : "Uploaded",
-       "mwe-upload-stats-fileprogres" : "$1 of $2",
+       "mwe-upload-stats-fileprogress" : "$1 of $2",
        "mwe-upload_completed" : "Your upload is complete",
        "mwe-upload_done" : "<a href=\"$1\">Your upload <i>should be<\/i> accessible<\/a>.",
        "mwe-upload-unknown-size" : "Unknown size",
@@ -30,414 +30,562 @@ loadGM({
 });
 
 var default_bui_options = {
-       'api_url':null,
-       'parent_uploader':null,
-       'edit_from':null,
+       'api_url': null,
+       'parent_uploader': null,
+       'form': null,
        'done_upload_cb': null,
-       'target_edit_from':null,
+       'form_selector': null,
 
        // Default upload mode is 'api'
        'upload_mode': 'api'
 
 }
-var mvBaseUploadInterface = function( iObj ){
-       return this.init( iObj );
+var mvBaseUploadInterface = function( options ) {
+       return this.init( options );
 }
+
 mvBaseUploadInterface.prototype = {
-       parent_uploader:false,
-       formData:{}, // The form data to be submitted
-       warnings_sessionkey:null,
-       chunks_supported:true,
-       form_post_override:false,
-       http_copy_upload : false,
-       action_done:false,
-       // The edit token:
-       etoken:false,
-       init: function( iObj ){
-               if(!iObj)
-                       iObj = {};
-               // Inherit iObj properties:
-               $j.extend( this, default_bui_options, iObj);            
-               js_log( "init mvBaseUploadInterface:: " + this.api_url);                
+       parent_uploader: false,
+       formData: {}, // The form data to be submitted
+       warnings_sessionkey: null,
+       chunks_supported: true,
+       form_post_override: false,
+       http_copy_upload : null,
+       action_done: false,
+       editToken: false,
+
+       // The DOM node for the upload form
+       form: false,
+
+       /**
+        * Object initialisation
+        */
+       init: function( options ) {
+               if ( !options )
+                       options = {};
+               $j.extend( this, default_bui_options, options );
+               js_log( "init mvBaseUploadInterface:: " + this.api_url );
        },
-       setupForm:function(){
-               js_log("Base::setupForm::");
+
+       /**
+        * Set up the upload form, register onsubmit handler.
+        * May remap it to use the API field names.
+        */
+       setupForm: function() {
+               js_log( "Base::setupForm::" );
                var _this = this;
                // Set up the local pointer to the edit form:
-               _this.editForm = _this.getEditForm();           
-               if( _this.editForm ){
-                                               
-                       // If in api re-map the upload form to api: (we have to do this BEFORE the users selects a file) 
-                       if( _this.upload_mode == 'api'){
-                               _this.doRemapFormToApi();
-                       }                                       
-                       
-                       // Set up the org_onsubmit if not set:
-                       if( typeof( _this.org_onsubmit ) == 'undefined' &&  _this.editForm.onsubmit )
-                               _this.org_onsubmit = _this.editForm.onsubmit;   
-                       
-                       
-                       // Set up the submit action:
-                       $j( _this.editForm ).submit( function(){
-                               js_log('setupForm.onSubmit:');
-                                                               
-                               // Set the upload mode: 
-                               _this.setWgUploadSelect();
-                               
-                               // Run the original onsubmit (if not run yet set flag to avoid excessive chaining )
-                               if( typeof( _this.org_onsubmit ) == 'function' ){
-                                       if( ! _this.org_onsubmit() ){
-                                               //error in org submit return false;
-                                               return false;
-                                       }
-                               }
-                               // Check for post action override:
-                               if( _this.form_post_override ){
-                                       js_log('form_post_override is true do form proccesing:');
-                                       return true;
-                               }
-                               // Get the input form data in flat json:
-                               js_log('update formData::');
-                               var tmpAryData = $j( _this.editForm ).serializeArray();
-                               for(var i=0; i < tmpAryData.length; i++){
-                                       if( tmpAryData[i]['name'] )
-                                               _this.formData[ tmpAryData[i]['name'] ] = tmpAryData[i]['value'];
-                               }
-                               // Put into a try catch so we are sure to return false:
-                               try{
-                                       debugger;
-                                       // Get a clean loader:
-                                       _this.dispProgressOverlay();
-
-                                       // For some unknown reason we have to drop down the #p-search z-index:
-                                       $j('#p-search').css('z-index', 1);
-
-                                       // Select upload mode:                                  
-                                       _this.detectUploadMode();
-                               }catch(e){
-                                       js_log('::error in dispProgressOverlay or detectUploadMode');
-                               }
-                               
-                               // Don't submit the form we will do the post in ajax
-                               return false;
-                       });
-               }               
-               $j('#testcat').click(function(){
-                       $j( _this.editForm ).submit();
-               });
+               this.form = this.getForm();
+               if ( !this.form ) {
+                       js_log( "Upload form not found!" );
+                       return;
+               }
+
+               // If we're in API mode, re-map the upload form to API.
+               if ( this.upload_mode == 'api' ) {
+                       this.remapFormToApi();
+               }
+
+               // Set up the orig_onsubmit if not set:
+               if ( typeof( this.orig_onsubmit ) == 'undefined' && this.form.onsubmit ) {
+                       this.orig_onsubmit = this.form.onsubmit;
+               }
+
+               // Set up the submit action:
+               $j( this.form ).submit( function() {
+                       _this.onSubmit();
+               } );
        },
-       detectUploadMode:function( callback ){
+
+       /**
+        * onsubmit handler for the upload form
+        */
+       onSubmit: function() {
+               js_log( 'Base::onSubmit:' );
+
+               // Run the original onsubmit (if not run yet set flag to avoid excessive chaining)
+               if ( typeof( this.orig_onsubmit ) == 'function' ) {
+                       if ( ! this.orig_onsubmit() ) {
+                               //error in orig submit return false;
+                               return false;
+                       }
+               }
+               // Check for post action override
+               if ( this.form_post_override ) {
+                       js_log( 'form_post_override is true, do ordinary form submit' );
+                       return true;
+               }
+
+               // Get the input form data into an array
+               js_log( 'update formData::' );
+               var data = $j( this.form ).serializeArray();
+               this.formData = {};
+               for ( var i = 0; i < data.length; i++ ) {
+                       if ( data[i]['name'] )
+                               this.formData[ data[i]['name'] ] = data[i]['value'];
+               }
+               // Put into a try catch so we are sure to return false:
+               try {
+                       // Get a clean loader:
+                       // FIXME: this function does not exist in this class
+                       this.displayProgressOverlay();
+
+                       // For some unknown reason we have to drop down the #p-search z-index:
+                       $j( '#p-search' ).css( 'z-index', 1 );
+
+                       var _this = this;
+                       this.detectUploadMode( function( mode ) {
+                               _this.doUpload();
+                       } );
+               } catch( e ) {
+                       js_log( '::error in displayProgressOverlay or doUpload' );
+               }
+
+               // Don't submit the form we will do the post in ajax
+               return false;
+       }
+
+       /**
+        * Determine the correct upload mode.
+        *
+        * If this.upload_mode is autodetect, this runs an API call to find out if MW
+        * supports uploading. It then sets the upload mode when this call returns.
+        *
+        * When done detecting, or if detecting is unnecessary, it calls the callback 
+        * with the upload mode as the first parameter.
+        */
+       detectUploadMode: function( callback ) {
                var _this = this;
-               js_log('detectUploadMode::' +  _this.upload_mode);
-               // Check the upload mode:
-               if( _this.upload_mode == 'autodetect' ){
-                       js_log('detectUploadMode::' + _this.upload_mode + ' api:' + _this.api_url);
-                       if( ! _this.api_url )
-                               return js_error( 'Error: can\'t autodetect mode without api url' );
-                       do_api_req( {
-                               'data': { 'action' : 'paraminfo', 'modules' : 'upload' },
-                               'url' : _this.api_url
-                       }, function(data){
-                               if( typeof data.paraminfo == 'undefined' || typeof data.paraminfo.modules == 'undefined' )
-                                       return js_error( 'Error: bad api results' );
-                               if( typeof data.paraminfo.modules[0].classname == 'undefined'){
-                                       js_log( 'Autodetect Upload Mode: \'post\' ');
-                                       _this.upload_mode = 'post';
-                               }else{
-                                       js_log( 'Autodetect Upload Mode: api ' );
-                                       _this.upload_mode = 'api';
-                                       //check to see if chunks are supported:
-                                       for( var i in data.paraminfo.modules[0].parameters ){
-                                               var pname = data.paraminfo.modules[0].parameters[i].name;
-                                               if( pname == 'enablechunks' ){
-                                                       js_log( 'this.chunks_supported = true' );
-                                                       _this.chunks_supported = true;
-                                                       break;
+               js_log( 'detectUploadMode::' +  _this.upload_mode );
+               // Check the upload mode
+               if ( _this.upload_mode == 'detect_in_progress' ) {
+                       // Don't send another request, wait for the pending one.
+               } else if ( !_this.isCopyUpload() ) {
+                       callback( 'post' );
+               } else if ( _this.upload_mode == 'autodetect' ) {
+                       js_log( 'detectUploadMode::' + _this.upload_mode + ' api:' + _this.api_url );
+                       if( !_this.api_url ) {
+                               js_error( 'Error: can\'t autodetect mode without api url' );
+                               return;
+                       }
+
+                       // Don't send multiple requests
+                       _this.upload_mode = 'detect_in_progress';
+
+                       // FIXME: move this to configuration and avoid this API request
+                       do_api_req(
+                               {
+                                       'data': { 'action' : 'paraminfo', 'modules' : 'upload' },
+                                       'url' : _this.api_url
+                               },
+                               function( data ) {
+                                       if ( typeof data.paraminfo == 'undefined'
+                                               || typeof data.paraminfo.modules == 'undefined' )
+                                       {
+                                               return js_error( 'Error: bad api results' );
+                                       }
+                                       if ( typeof data.paraminfo.modules[0].classname == 'undefined' ) {
+                                               js_log( 'Autodetect Upload Mode: \'post\' ' );
+                                               _this.upload_mode = 'post';
+                                               callback( 'post' );
+                                       } else {
+                                               js_log( 'Autodetect Upload Mode: api ' );
+                                               _this.upload_mode = 'api';
+                                               // Check to see if chunks are supported
+                                               for ( var i in data.paraminfo.modules[0].parameters ) {
+                                                       var pname = data.paraminfo.modules[0].parameters[i].name;
+                                                       if( pname == 'enablechunks' ) {
+                                                               js_log( 'this.chunks_supported = true' );
+                                                               _this.chunks_supported = true;
+                                                               break;
+                                                       }
                                                }
+                                               callback( 'api' );
                                        }
                                }
-                               js_log("do call: doUploadSwitch");
-                               _this.doUploadSwitch();
-                       });
-               }else{
-                       _this.doUploadSwitch();
+                       );
+               } else if ( _this.upload_mode == 'api' ) {
+                       callback( 'api' );
+               } else if ( _this.upload_mode == 'post' ) {
+                       callback( 'post' );
+               } else {
+                       js_error( 'Error: unrecongized upload mode: ' + _this.upload_mode );
                }
        },
-       //@@NOTE this could probably be deprecated in favor of automated input
-       doRemapFormToApi:function(){
-               var _this = this;
-               if( !_this.api_url )
+
+       /**
+        * Do an upload, with the mode given by this.upload_mode
+        */
+       doUpload: function() {
+               if ( this.upload_mode == 'api' ) {
+                       _this.doApiCopyUpload();
+               } else if ( this.upload_mode == 'post' ) {
+                       _this.doPostUpload();
+               } else {
+                       js_error( 'Error: unrecongized upload mode: ' + this.upload_mode );
+               }
+       }
+
+       /**
+        * Change the upload form so that when submitted, it sends a request to
+        * the MW API.
+        *
+        * This is rather ugly, but solutions are constrained by the fact that 
+        * file inputs can't be moved around or recreated after the user has 
+        * selected a file in them, which they may well do before DOM ready.
+        */
+       remapFormToApi: function() {
+               if ( !this.api_url )
                        return false;
-                       
-               //add the action api 
-               //$j(_this.editForm).attr('action', _this.api_url);
-               
-               //add api url 
-               //add api action:
-               if( $j(_this.editForm).find("[name='action']").length == 0)
-                       $j(_this.editForm).append('<input type="hidden" name="action" value="upload">');
-
-               //add json format
-               if( $j(_this.editForm).find("[name='format']").length == 0)
-                       $j(_this.editForm).append('<input type="hidden" name="format" value="jsonfm">');
-
-               //map a new hidden form
-               $j(_this.editForm).find("[name='wpUploadFile']").attr('name', 'file');
-               $j(_this.editForm).find("[name='wpDestFile']").attr('name', 'filename');
-               $j(_this.editForm).find("[name='wpUploadDescription']").attr('name', 'comment');
-               $j(_this.editForm).find("[name='wpEditToken']").attr('name', 'token');
-               $j(_this.editForm).find("[name='wpIgnoreWarning']").attr('name', 'ignorewarnings');
-               $j(_this.editForm).find("[name='wpWatchthis']").attr('name', 'watch');
-                               
+
+               var form = $j( this.form );
+
+               // Set the form action
+               form.attr('action', _this.api_url);
+
+               // Add API action
+               if ( form.find( "[name='action']" ).length == 0 )
+                       form.append( '<input type="hidden" name="action" value="upload">' );
+
+               // Add JSON format
+               if ( form.find( "[name='format']" ).length == 0 )
+                       form.append( '<input type="hidden" name="format" value="jsonfm">' );
+
+               // Map a new hidden form
+               form.find( "[name='wpUploadFile']" ).attr( 'name', 'file' );
+               form.find( "[name='wpDestFile']" ).attr( 'name', 'filename' );
+               form.find( "[name='wpUploadDescription']" ).attr( 'name', 'comment' );
+               form.find( "[name='wpEditToken']" ).attr( 'name', 'token' );
+               form.find( "[name='wpIgnoreWarning']" ).attr( 'name', 'ignorewarnings' );
+               form.find( "[name='wpWatchthis']" ).attr( 'name', 'watch' );
        },
-       setWgUploadSelect: function(){
-               if( $j('#wpSourceTypeFile').length ==  0 || $j('#wpSourceTypeFile').get(0).checked ){
-                       this.http_copy_upload = false;
-               }else if(  $j('#wpSourceTypeUrl').get(0).checked ){
-                       this.http_copy_upload = true;
+
+       /**
+        * Returns true if the current form has copy upload selected, false otherwise.
+        */
+       isCopyUpload: function() {
+               if ( this.http_copy_upload == null ) {
+                       if ( $j( '#wpSourceTypeFile' ).length ==  0
+                               || $j( '#wpSourceTypeFile' ).get( 0 ).checked )
+                       {
+                               this.http_copy_upload = false;
+                       } else if ( $j('#wpSourceTypeURL').get( 0 ).checked ) {
+                               this.http_copy_upload = true;
+                       }
                }
+               return this.http_copy_upload;
        },
-       doUploadSwitch:function(){
+
+       /**
+        * Do an upload by submitting the form
+        */
+       doPostUpload: function() {
                var _this = this;
-               js_log('mvUPload:doUploadSwitch():' + _this.upload_mode);
-               //issue a normal post request
-               if( _this.upload_mode == 'api' && ! _this.http_copy_upload ){
-                       //get the token from the page: 
-                       _this.etoken = $j("#wpEditToken").val();
-                       
-                       //@@TODO check for sendAsBinnary to support firefox/html5 progress on upload
-
-                       //set the form target to iframe target: 
-                       _this.iframeId = 'f_' + ($j('iframe').length + 1);      
-                                                       
-                       //add the iframe
-                       $j("body").append('<iframe src="javascript:false;" id="' + _this.iframeId + '" ' +
-                               'name="' + _this.iframeId + '" style="display:none;" ></iframe>');      
-                       $j(_this.editForm).attr('target', _this.iframeId);
-
-                       //set up the done binding
-                       $j('#' + _this.iframeId).load(function(){
-                               _this.proccessIframeResult(  $j(this).get(0) );
-                       });
-                       //set the action to the api url:
-                       $j(_this.editForm).attr('action', _this.api_url );
-                       
-                       js_log('do iframe form submit to: ' +  $j(_this.editForm).attr('target') );
-                       js_log(' destName:' + $j(_this.editForm).find("[name='filename']").val() );                                     
-                       
-                       
-                       //do post override
-                       _this.form_post_override = true;
-                       //reset the done with action flag:
-                       _this.action_done = false;
-                       
-                       /*js_log('run editForm submit()');
-                       var tmpAryData = $j(_this.editForm).serializeArray();
-                       for(var i=0; i < tmpAryData.length; i++){
-                               if( tmpAryData[i]['name'] )
-                                       js_log('name: ' + tmpAryData[i]['name'] + ' = ' + tmpAryData[i]['value']);
-                       }*/
-                       $j( _this.editForm ).submit();
+               var form = $j( _this.form );
+               js_log( 'mvBaseUploadInterface.doPostUpload' );
 
-                       return false;
-               }else if( _this.upload_mode == 'api' ){
-                       js_log('doHttpUpload (no form submit) ');
-                       //if the api is supported.. && source type is http do upload with http status updates
-                       var httpUpConf ={
-                           'url'               : $j('#wpUploadFileURL').val(),
-                           'filename'  : $j('#wpDestFile').val(),
-                           'comment'   : $j('#wpUploadDescription').val(),
-                               'watch'         : ($j('#wpWatchthis').is(':checked'))?'true':'false',
-                               'ignorewarnings': ($j('#wpIgnoreWarning').is(':checked'))?'true':'false'
-                       }                       
-                       //check for editToken
-                       _this.etoken = $j("#wpEditToken").val();
-                       _this.doHttpUpload( httpUpConf );
-               }else{
-                       js_error( 'Error: unrecongized upload mode: ' + _this.upload_mode );
+               // Issue a normal post request
+               // Get the token from the page
+               _this.editToken = $j( "#wpEditToken" ).val();
+
+               //@@TODO check for sendAsBinary to support Firefox/HTML5 progress on upload
+
+
+               // Add the iframe
+               _this.iframeId = 'f_' + ( $j( 'iframe' ).length + 1 );
+               $j( "body" ).append( '<iframe src="javascript:false;" id="' + _this.iframeId + '" ' +
+                       'name="' + _this.iframeId + '" style="display:none;" ></iframe>' );
+
+               // Set the form target to the iframe
+               form.attr( 'target', _this.iframeId );
+
+               // Set up the completion callback
+               $j( '#' + _this.iframeId ).load( function() {
+                       _this.processIframeResult( $j( this ).get( 0 ) );
+               });
+
+               // Set the action to the API URL:
+               form.attr( 'action', _this.api_url );
+
+               js_log( 'Do iframe form submit to: ' +  form.attr( 'target' ) );
+               js_log( ' destName:' + form.find( "[name='filename']" ).val() );
+
+               // Do post override
+               _this.form_post_override = true;
+               // Reset the done with action flag
+               _this.action_done = false;
+
+               form.submit();
+       },
+
+       /**
+        * Do an upload by submitting an API request
+        */
+       doApiCopyUpload: function() {
+               js_log( 'mvBaseUploadInterface.doApiCopyUpload' );
+               js_log( 'doHttpUpload (no form submit) ' );
+               var httpUpConf = {
+                       'url'       : $j( '#wpUploadFileURL' ).val(),
+                       'filename'  : $j( '#wpDestFile' ).val(),
+                       'comment'   : $j( '#wpUploadDescription' ).val(),
+                       'watch'     : ( $j( '#wpWatchthis' ).is( ':checked' ) ) ? 'true' : 'false',
+                       'ignorewarnings': ($j('#wpIgnoreWarning' ).is( ':checked' ) ) ? 'true' : 'false'
                }
-               return false;
+               //check for editToken
+               this.editToken = $j( "#wpEditToken" ).val();
+               this.doHttpUpload( httpUpConf );
        },
-       proccessIframeResult:function(iframe){
+
+       /**
+        * Process the result of the form submission, returned to an iframe.
+        * This is the iframe's onload event.
+        */
+       processIframeResult: function( iframe ) {
                var _this = this;
                var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document;
-               // fixing Opera 9.26
-               if (doc.readyState && doc.readyState != 'complete'){
+               // Fix for Opera 9.26
+               if ( doc.readyState && doc.readyState != 'complete' ) {
                        return;
                }
-               // fixing Opera 9.64
-               if (doc.body && doc.body.innerHTML == "false"){
+               // Fix for Opera 9.64
+               if ( doc.body && doc.body.innerHTML == "false" ) {
                        return;
                }
                var response;
-               if (doc.XMLDocument){
-                       // response is a xml document IE property
+               if ( doc.XMLDocument ) {
+                       // The response is a document property in IE
                        response = doc.XMLDocument;
-               } else if (doc.body){
-                       // get the json str:
-                       json_str = $j(doc.body).find('pre').html();
-                       js_log('iframe:json::' + json_str + "\nbody:" + $j(doc.body).html() );
-                       //htmlentties
-                       if (json_str) {
-                               response = window["eval"]("(" +json_str + ")");
+               } else if ( doc.body ) {
+                       // Get the json string
+                       json = $j( doc.body ).find( 'pre' ).text();
+                       js_log( 'iframe:json::' + json_str + "\nbody:" + $j( doc.body ).html() );
+                       if ( json ) {
+                               response = window["eval"]( "(" + json + ")" );
                        } else {
                                response = {};
                        }
                } else {
                        // response is a xml document
-                       var response = doc;
+                       response = doc;
                }
-               //do proccess the api result
-               _this.processApiResult( response );
+               // Process the API result
+               _this.processApiResult( response );
        },
-       doHttpUpload:function( opt ){
+
+       /**
+        * Do a generic action=upload API request and monitor its progress
+        */
+       doHttpUpload: function( params ) {
                var _this = this;
-               //make sure to display the progress win:
-               _this.dispProgressOverlay();
-               
-               //set the http box to loading (in case we don't get an update for some time)
-               $j('#dlbox-centered').html( '<h5>' + _this.getProgressTitle() + '</h5>' +
-                       mv_get_loading_img( 'left:40%;top:20%')
-               );              
-               //setup request:
-               var req = {
-                       'action'                : 'upload',
-                       'asyncdownload' : true  //do async download
+               // Display the progress overlay (again)
+               _this.displayProgressOverlay();
+
+               // Set the HTTP box to "loading", in case we don't get an update for some time
+               $j( '#dlbox-centered' ).html( '<h5>' + _this.getProgressTitle() + '</h5>' +
+                       mv_get_loading_img( 'left:40%;top:20%' )
+               );
+
+               // Set up the request
+               var request = {
+                       'action'        : 'upload',
+                       'asyncdownload' : true // Do async download
                };
-               //set config from options:
-               $j.extend(req, opt);
 
-               //else try and get a token:
-               if(!_this.etoken  && _this.api_url){
-                       js_log('Error:doHttpUpload: missing token');
-               }else{
-                       req['token'] =_this.etoken;
+               // Add any parameters specified by the caller
+               for ( key in params ) {
+                       if ( !request[key] ) {
+                               request[key] = params[key];
+                       }
                }
-               //reset the done with action flag:
+
+               // Add the edit token (if available)
+               if( !_this.editToken && _this.api_url ) {
+                       js_log( 'Error:doHttpUpload: missing token' );
+               } else {
+                       request['token'] =_this.editToken;
+               }
+
+               // Reset the done with action flag
                _this.action_done = false;
-               //do the api req
+
+               //do the api request
                do_api_req({
-                       'data': req,
+                       'data': request,
                        'url' : _this.api_url
-               }, function( data ){
+               }, function( data ) {
                        _this.processApiResult( data );
                });
        },
-       doAjaxUploadStatus:function() {
-               var _this = this;       
-               
+
+       /**
+        * Start periodic checks of the upload status using XHR
+        */
+       doAjaxUploadStatus: function() {
+               var _this = this;
+
                //set up the progress display for status updates:
-               _this.dispProgressOverlay();
-               var req = {
-                       'action'         : 'upload',
+               this.displayProgressOverlay();
+               this.upload_status_request = {
+                       'action'     : 'upload',
                        'httpstatus' : 'true',
                        'sessionkey' : _this.upload_session_key
                };
-               //add token if present:
-               if(this.etoken)
-                       req['token'] = this.etoken;
-
-               var uploadStatus = function(){
-                       //do the api request:
-                       do_api_req({
-                               'data':req,
-                               'url' : _this.api_url
-                       }, function( data ){
-                               //@@check if we are done
-                               if( data.upload['apiUploadResult'] ){
-                                       //update status to 100%
-                                       _this.updateProgress( 1 );
-                                       //see if we need JSON
-                                       mvJsLoader.doLoad( [
-                                               'JSON'
-                                       ],function(){                                                   
-                                               var apiResult = {};
-                                               try{
-                                                       apiResult = JSON.parse ( data.upload['apiUploadResult'] ) ;
-                                               }catch (e){
-                                                       //could not parse api result
-                                                       js_log('errro: could not parse apiUploadResult ')
-                                               }
-                                               _this.processApiResult( apiResult );
-                                       });
-                                       return ;
-                               }
+               // Add token if present
+               if ( this.editToken )
+                       this.upload_status_request['token'] = this.editToken;
 
-                               //@@ else update status:
-                               if( data.upload['content_length'] &&  data.upload['loaded'] ){
-                                       //we have content length we can show percentage done:
-                                       var perc =  data.upload['loaded'] / data.upload['content_length'];
-                                       //update the status:
-                                       _this.updateProgress( perc );
-                                       //special case update the file progress where we have data size:
-                                       $j('#up-status-container').html(
-                                               gM('mwe-upload-stats-fileprogres', [
-                                                       $mw.lang.formatSize( data.upload['loaded'] ),
-                                                       $mw.lang.formatSize( data.upload['content_length'] )
-                                                       ]
-                                               )
-                                       );
-                               }else if( data.upload['loaded'] ){
-                                       _this.updateProgress( 1 );
-                                       js_log('just have loaded (no cotent length: ' + data.upload['loaded']);
-                                       //for lack of content-length requests:
-                                       $j('#up-status-container').html(
-                                               gM('mwe-upload-stats-fileprogres', [
-                                                       $mw.lang.formatSize( data.upload['loaded'] ),
-                                                       gM('mwe-upload-unknown-size')
-                                                       ]
-                                               )
-                                       );
-                               }
-                               if( _this.api_url == 'proxy'){
-                                       //do the updates a bit more sporadically every 4.2 seconds 
-                                       setTimeout(uploadStatus, 4200);
-                               }else{
-                                       //(we got a result) set it to 100ms + your server update interval (in our case 2s)
-                                       setTimeout(uploadStatus, 2100);
+               // Trigger an initial request (subsequent ones will be done by a timer)
+               this.onAjaxUploadStatusTimer();
+       }
+
+       /**
+        * This is called when the timer which separates XHR requests elapses.
+        * It starts a new request.
+        */
+       onAjaxUploadStatusTimer: function() {
+               var _this = this;
+               //do the api request:
+               do_api_req(
+                       {
+                               'data': this.upload_status_request,
+                               'url' : this.api_url
+                       },
+                       function ( data ) {
+                               _this.onAjaxUploadStatusResponse( data );
+                       }
+               );
+       },
+
+       /**
+        * Called when a response to an upload status query is available.
+        * Starts the timer for the next upload status check.
+        */
+       onAjaxUploadStatusResponse: function( data ) {
+               var _this = this;
+               //@@check if we are done
+               if ( data.upload['apiUploadResult'] ) {
+                       //update status to 100%
+                       _this.updateProgress( 1 );
+                       //see if we need JSON
+                       mvJsLoader.doLoad( [
+                               'JSON'
+                       ], function() {
+                               var apiResult = {};
+                               try {
+                                       apiResult = JSON.parse( data.upload['apiUploadResult'] ) ;
+                               } catch ( e ) {
+                                       //could not parse api result
+                                       js_log( 'errro: could not parse apiUploadResult' )
                                }
+                               _this.processApiResult( apiResult );
                        });
+                       return ;
+               }
+
+               //@@ else update status:
+               if ( data.upload['content_length'] && data.upload['loaded'] ) {
+                       //we have content length we can show percentage done:
+                       var fraction = data.upload['loaded'] / data.upload['content_length'];
+                       //update the status:
+                       _this.updateProgress( fraction );
+                       //special case update the file progress where we have data size:
+                       $j( '#up-status-container' ).html(
+                               gM( 'mwe-upload-stats-fileprogress',
+                                       [
+                                               $mw.lang.formatSize( data.upload['loaded'] ),
+                                               $mw.lang.formatSize( data.upload['content_length'] )
+                                       ]
+                               )
+                       );
+               } else if( data.upload['loaded'] ) {
+                       _this.updateProgress( 1 );
+                       js_log( 'just have loaded (no cotent length: ' + data.upload['loaded'] );
+                       //for lack of content-length requests:
+                       $j( '#up-status-container' ).html(
+                               gM( 'mwe-upload-stats-fileprogress',
+                                       [
+                                               $mw.lang.formatSize( data.upload['loaded'] ),
+                                               gM( 'mwe-upload-unknown-size' )
+                                       ]
+                               )
+                       );
+               }
+               if ( _this.api_url == 'proxy' ) {
+                       // Do the updates a bit less often: every 4.2 seconds
+                       var timeout = 4200;
+               } else {
+                       // We got a result: set timeout to 100ms + your server update
+                       // interval (in our case 2s)
+                       var timeout = 2100;
                }
-               uploadStatus();
+               setTimeout(
+                       function() {
+                               _this.onAjaxUploadStatusTimer();
+                       },
+                       timeout );
        },
-       apiUpdateErrorCheck:function( apiRes ){
+
+       /**
+        * Returns true if an action=upload API result was successful, false otherwise
+        */
+       isApiSuccess: function( apiRes ) {
+               if ( apiRes.error || ( apiRes.upload && apiRes.upload.result == "Failure" ) ) {
+                       return false;
+               }
+               if ( apiRes.upload && apiRes.upload.error ) {
+                       return false;
+               }
+               if ( apiRes.upload && apiRes.upload.warnings ) {
+                       return false;
+               }
+               return true;
+       },
+
+       /**
+        * Given the result of an action=upload API request, display the error message
+        * to the user.
+        */
+       showApiError: function( apiRes ) {
                var _this = this;
-               if( apiRes.error || ( apiRes.upload && apiRes.upload.result == "Failure" ) ){
-                       //gennerate the error button:
-                       var bObj = {};
-                       bObj[ gM('mwe-return-to-form') ] = function(){
-                                       _this.form_post_override = false;
-                                       $j(this).dialog('close');
-                        };
+               if ( apiRes.error || ( apiRes.upload && apiRes.upload.result == "Failure" ) ) {
+                       // Generate the error button
+                       var buttons = {};
+                       buttons[ gM( 'mwe-return-to-form' ) ] = function() {
+                               _this.form_post_override = false;
+                               $j( this ).dialog( 'close' );
+                       };
 
                        //@@TODO should be refactored to more specialUpload page type error handling
 
-                       //check a few places for the error code:
-                       var error_code=0;
-                       var errorReplaceArg='';
-                       if( apiRes.error && apiRes.error.code ){
+                       // Check a few places for the error code
+                       var error_code = 0;
+                       var errorReplaceArg = '';
+                       if ( apiRes.error && apiRes.error.code ) {
                                error_code = apiRes.error.code;
-                       }else if( apiRes.upload.code ){
-                               if(typeof apiRes.upload.code == 'object'){
-                                       if( apiRes.upload.code[0] ){
+                       } else if ( apiRes.upload.code ) {
+                               if ( typeof apiRes.upload.code == 'object' ) {
+                                       if ( apiRes.upload.code[0] ) {
                                                error_code = apiRes.upload.code[0];
                                        }
-                                       if( apiRes.upload.code['status'] ){
+                                       if ( apiRes.upload.code['status'] ) {
                                                error_code = apiRes.upload.code['status'];
-                                               if(apiRes.upload.code['filtered'])
-                                                       errorReplaceArg =apiRes.upload.code['filtered'];
+                                               if ( apiRes.upload.code['filtered'] )
+                                                       errorReplaceArg = apiRes.upload.code['filtered'];
                                        }
-                               }else{
+                               } else {
                                        apiRes.upload.code;
                                }
                        }
 
                        var error_msg = '';
-                       if(typeof apiRes.error == 'string')
+                       if ( typeof apiRes.error == 'string' )
                                error_msg = apiRes.error;
-                       //error space is too large so we don't front load it
-                       //this upload error space replicates code in: SpecialUpload.php::processUpload()
-                       //would be nice if we refactored that to the upload api.(problem is some need special actions)
+
+                       // There are many possible error messages here, so we don't load all
+                       // message text in advance, instead we use gMsgLoadRemote() for some.
+                       //
+                       // This code is similar to the error handling code formerly in
+                       // SpecialUpload::processUpload()
                        var error_msg_key = {
                                '2' : 'largefileserver',
                                '3' : 'emptyfile',
@@ -445,7 +593,7 @@ mvBaseUploadInterface.prototype = {
                                '5' : 'illegalfilename'
                        };
 
-                       //@@todo: need to write conditionals that mirror SpecialUpload for handling these error types:
+                       //@@todo: handle these error types
                        var error_onlykey = {
                                '1': 'BEFORE_PROCESSING',
                                '6': 'PROTECTED_PAGE',
@@ -456,332 +604,437 @@ mvBaseUploadInterface.prototype = {
                                '11': 'UPLOAD_VERIFICATION_ERROR',
                                '12': 'UPLOAD_WARNING',
                                '13': 'INTERNAL_ERROR',
-                               '14': 'MIN_LENGHT_PARTNAME'
+                               '14': 'MIN_LENGTH_PARTNAME'
                        }
 
-                       //do a remote call to get the error msg:
-                       if(!error_code || error_code == 'unknown-error'){
-                               if(typeof JSON != 'undefined'){
-                                       js_log('Error: apiRes: ' + JSON.stringify( apiRes) );
+                       if ( !error_code || error_code == 'unknown-error' ) {
+                               if ( typeof JSON != 'undefined' ) {
+                                       js_log( 'Error: apiRes: ' + JSON.stringify( apiRes ) );
                                }
-                               if( apiRes.upload.error == 'internal-error'){
+                               if ( apiRes.upload.error == 'internal-error' ) {
+                                       // Do a remote message load
                                        errorKey = apiRes.upload.details[0];
-                                       gMsgLoadRemote(errorKey, function(){
-                                               _this.updateProgressWin( gM( 'mwe-uploaderror' ), gM( errorKey ), bObj );
+                                       gMsgLoadRemote( errorKey, function() {
+                                               _this.updateProgressWin( gM( 'mwe-uploaderror' ), gM( errorKey ), buttons );
 
                                        });
                                        return false;
                                }
 
-                               _this.updateProgressWin( gM('mwe-uploaderror'), gM('mwe-unknown-error') + '<br>' + error_msg, bObj );
+                               _this.updateProgressWin(
+                                               gM('mwe-uploaderror'),
+                                               gM('mwe-unknown-error') + '<br>' + error_msg,
+                                               buttons );
                                return false;
-                       }else{
-                               if(apiRes.error && apiRes.error.info ){
-                                       _this.updateProgressWin(  gM('mwe-uploaderror'), apiRes.error.info ,bObj);
-                                       return false;
-                               }else{
-                                       if(typeof error_code == 'number' && typeof error_msg_key[error_code] == 'undefined' ){
-                                               if(apiRes.upload.code.finalExt){
-                                                       _this.updateProgressWin(  gM('mwe-uploaderror'), gM('mwe-wgfogg_warning_bad_extension', apiRes.upload.code.finalExt) , bObj);
-                                               }else{
-                                                       _this.updateProgressWin( gM('mwe-uploaderror'), gM('mwe-unknown-error') + ' : ' + error_code, bObj);
-                                               }
-                                       }else{
-                                               js_log('get key: ' + error_msg_key[ error_code ])
-                                               gMsgLoadRemote( error_msg_key[ error_code ], function(){
-                                                       _this.updateProgressWin(  gM('mwe-uploaderror'), gM(  error_msg_key[ error_code ], errorReplaceArg ), bObj);
-                                               });
-                                               js_log("api.error");
-                                       }
-                                       return false;
+                       }
+
+                       if ( apiRes.error && apiRes.error.info ) {
+                               _this.updateProgressWin( gM( 'mwe-uploaderror' ), apiRes.error.info, buttons );
+                               return false;
+                       }
+
+                       if ( typeof error_code == 'number'
+                               && typeof error_msg_key[error_code] == 'undefined' )
+                       {
+                               if ( apiRes.upload.code.finalExt ) {
+                                       _this.updateProgressWin(
+                                               gM( 'mwe-uploaderror' ),
+                                               gM( 'mwe-wgfogg_warning_bad_extension', apiRes.upload.code.finalExt ),
+                                               buttons );
+                               } else {
+                                       _this.updateProgressWin(
+                                               gM( 'mwe-uploaderror' ),
+                                               gM( 'mwe-unknown-error' ) + ' : ' + error_code,
+                                               buttons );
                                }
+                               return false;
                        }
+
+                       js_log( 'get key: ' + error_msg_key[ error_code ] )
+                       gMsgLoadRemote( error_msg_key[ error_code ], function() {
+                               _this.updateProgressWin(
+                                       gM( 'mwe-uploaderror' ),
+                                       gM( error_msg_key[ error_code ], errorReplaceArg ),
+                                       buttons );
+                       });
+                       js_log( "api.error" );
+                       return false;
                }
-               //check for upload.error type erros.
-               if( apiRes.upload && apiRes.upload.error){
-                       js_log(' apiRes.upload.error: ' +  apiRes.upload.error );
-                       _this.updateProgressWin( gM('mwe-uploaderror'), gM('mwe-unknown-error') + '<br>', bObj);
+
+               // Check upload.error
+               if ( apiRes.upload && apiRes.upload.error ) {
+                       js_log( ' apiRes.upload.error: ' +  apiRes.upload.error );
+                       _this.updateProgressWin(
+                               gM( 'mwe-uploaderror' ),
+                               gM( 'mwe-unknown-error' ) + '<br>',
+                               buttons );
                        return false;
                }
-               //check for known warnings:
-               if(apiRes.upload && apiRes.upload.warnings ){
-                       //debugger;
+
+               // Check for warnings:
+               if ( apiRes.upload && apiRes.upload.warnings ) {
                        var wmsg = '<ul>';
-                       for(var wtype in apiRes.upload.warnings){
+                       for ( var wtype in apiRes.upload.warnings ) {
                                var winfo = apiRes.upload.warnings[wtype]
-                               wmsg+='<li>';
-                               switch(wtype){
+                               wmsg += '<li>';
+                               switch ( wtype ) {
                                        case 'duplicate':
                                        case 'exists':
-                                               if(winfo[1] && winfo[1].title && winfo[1].title.mTextform){
-                                                       wmsg += gM('mwe-file-exists-duplicate') +' '+
-                                                                       '<b>' + winfo[1].title.mTextform + '</b>';
-                                               }else{
+                                               if ( winfo[1] && winfo[1].title && winfo[1].title.mTextform ) {
+                                                       wmsg += gM( 'mwe-file-exists-duplicate' ) + ' ' +
+                                                               '<b>' + winfo[1].title.mTextform + '</b>';
+                                               } else {
                                                        //misc error (weird that winfo[1] not present
-                                                       wmsg += gM('mwe-upload-misc-error') + ' ' + wtype;
+                                                       wmsg += gM( 'mwe-upload-misc-error' ) + ' ' + wtype;
                                                }
-                                       break;
+                                               break;
                                        case 'file-thumbnail-no':
-                                               wmsg += gM('mwe-file-thumbnail-no', winfo);
-                                       break;
+                                               wmsg += gM( 'mwe-file-thumbnail-no', winfo );
+                                               break;
                                        default:
-                                               wmsg += gM('mwe-upload-misc-error') + ' ' + wtype;
-                                       break;
+                                               wmsg += gM( 'mwe-upload-misc-error' ) + ' ' + wtype;
+                                               break;
                                }
-                               wmsg+='</li>';
+                               wmsg += '</li>';
                        }
-                       wmsg+='</ul>';
-                       if( apiRes.upload.sessionkey)
-                               _this.warnings_sessionkey = apiRes.upload.sessionkey;
+                       wmsg += '</ul>';
+                       if ( apiRes.upload.sessionkey )
+                               _this.warnings_sessionkey = apiRes.upload.sessionkey;
 
-                       var bObj = {};
-                       bObj[ gM('mwe-ignorewarning') ] =       function() {
-                               //check if we have a stashed key: 
-                               if( _this.warnings_sessionkey ){
-                                       //set to "loading" 
+                       // Create the "ignore warning" button
+                       var buttons = {};
+                       buttons[ gM( 'mwe-ignorewarning' ) ] = function() {
+                               //check if we have a stashed key:
+                               if ( _this.warnings_sessionkey ) {
+                                       //set to "loading"
                                        $j( '#upProgressDialog' ).html( mv_get_loading_img() );
                                        //setup loading:
                                        var req = {
-                                               'action' : 'upload',
+                                               'action': 'upload',
                                                'sessionkey': _this.warnings_sessionkey,
-                                               'ignorewarnings':1,
-                                               'filename': $j('#wpDestFile').val(),
-                                               'token' :  _this.etoken
-                                       };                                      
+                                               'ignorewarnings': 1,
+                                               'filename': $j( '#wpDestFile' ).val(),
+                                               'token' :  _this.editToken
+                                       };
                                        //run the upload from stash request
-                                       do_api_req({
-                                               'data': req,
-                                               'url' : _this.api_url
-                                       }, function( data ){
-                                               _this.processApiResult( data );
-                                       });
-                               }else{
-                                       js_log('No session key re-sending upload')
+                                       do_api_req(
+                                               {
+                                                       'data': req,
+                                                       'url' : _this.api_url
+                                               },
+                                               function( data ) {
+                                                       _this.processApiResult( data );
+                                               }
+                                       );
+                               } else {
+                                       js_log( 'No session key re-sending upload' )
                                        //do a stashed upload
-                                       $j('#wpIgnoreWarning').attr('checked', true);
+                                       $j( '#wpIgnoreWarning' ).attr( 'checked', true );
                                        $j( _this.editForm ).submit();
                                }
                        };
-                       bObj[ gM('mwe-return-to-form') ] = function(){
-                               $j(this).dialog('close');
+                       // Create the "return to form" button
+                       bObj[ gM( 'mwe-return-to-form' ) ] = function() {
+                               $j( this ).dialog( 'close' );
                                _this.form_post_override = false;
                        }
-                       _this.updateProgressWin( gM('mwe-uploadwarning'),  '<h3>' + gM('mwe-uploadwarning') + '</h3>' +wmsg + '<p>',bObj);
+                       // Show warning
+                       _this.updateProgressWin(
+                               gM( 'mwe-uploadwarning' ),
+                               '<h3>' + gM( 'mwe-uploadwarning' ) + '</h3>' + wmsg + '<p>',
+                               bObj );
                        return false;
                }
-               //should be "OK"
+               // No error!
                return true;
        },
-       processApiResult: function( apiRes ){
+
+       /**
+        * Process the result of an action=upload API request. Display the result
+        * to the user.
+        */
+       processApiResult: function( apiRes ) {
                var _this = this;
-               js_log('processApiResult::');           
-               //check for upload api error:
-               // {"upload":{"result":"Failure","error":"unknown-error","code":{"status":5,"filtered":"NGC2207%2BIC2163.jpg"}}}
-               if( _this.apiUpdateErrorCheck(apiRes) === false){
-                       //error returned false (updated and
+               js_log( 'processApiResult::' );
+               if ( !_this.isApiSuccess( apiRes ) ) {
+                       // Error detected, show it to the user
+                       _this.showApiError( apiRes );
                        return false;
-               }else{
-                       //check for upload_session key for async upload:
-                       if( apiRes.upload && apiRes.upload.upload_session_key ){
-                               //set the session key
-                               _this.upload_session_key = apiRes.upload.upload_session_key;
-
-                               //do ajax upload status:
-                               _this.doAjaxUploadStatus();
-                               js_log("set upload_session_key: " + _this.upload_session_key);
-                               return ;
+               }
+               if ( apiRes.upload && apiRes.upload.upload_session_key ) {
+                       // Async upload, do AJAX status polling
+                       _this.upload_session_key = apiRes.upload.upload_session_key;
+                       _this.doAjaxUploadStatus();
+                       js_log( "set upload_session_key: " + _this.upload_session_key );
+                       return;
+               }
+
+               if ( apiRes.upload.imageinfo && apiRes.upload.imageinfo.descriptionurl ) {
+                       var url = apiRes.upload.imageinfo.descriptionurl;
+
+                       // Upload complete.
+                       // Call the completion callback if available.
+                       if ( _this.done_upload_cb && typeof _this.done_upload_cb == 'function' ) {
+                               js_log( "call done_upload_cb" );
+                               // This overrides our normal completion handling so we close the
+                               // dialog immediately.
+                               $j( '#upProgressDialog' ).dialog( 'close' );
+                               _this.done_upload_cb( apiRes.upload );
+                               return false;
                        }
 
-                       if( apiRes.upload.imageinfo &&  apiRes.upload.imageinfo.descriptionurl ){
-                               var url = apiRes.upload.imageinfo.descriptionurl;
-                               //check done action:
-                               if( _this.done_upload_cb && typeof _this.done_upload_cb == 'function'){
-                                       js_log("call done_upload_cb");
-                                       //close up shop:
-                                       $j('#upProgressDialog').dialog('close');
-                                       //call the callback:
-                                       _this.done_upload_cb( apiRes.upload );
-                                       return false;
-                               }else{
-                                       var bObj = {};
-                                       bObj[ gM('mwe-return-to-form')] = function(){
-                                               $j(this).dialog('close');
-                                               _this.form_post_override = false;
-                                       }
-                                       bObj[ gM('mwe-go-to-resource') ] = function(){
-                                                       window.location = url;
-                                       };
-                                       _this.action_done = true;
-                                       _this.updateProgressWin( gM('mwe-successfulupload'),  gM( 'mwe-upload_done', url), bObj);
-                                       js_log('apiRes.upload.imageinfo::'+url);
-                                       return true;
-                               }
+                       var bObj = {};
+                       // "Return" button
+                       bObj[ gM( 'mwe-return-to-form' ) ] = function() {
+                               $j( this ).dialog( 'close' );
+                               _this.form_post_override = false;
                        }
+                       // "Go to resource" button
+                       bObj[ gM('mwe-go-to-resource') ] = function() {
+                               window.location = url;
+                       };
+                       _this.action_done = true;
+                       _this.updateProgressWin(
+                                       gM( 'mwe-successfulupload' ),
+                                       gM( 'mwe-upload_done', url),
+                                       bObj );
+                       js_log( 'apiRes.upload.imageinfo::' + url );
+                       return true;
                }
        },
-       updateProgressWin:function(title_txt, msg, buttons){
+
+       /**
+        * Update the progress window to display a given message, with a given
+        * list of buttons below it.
+        * @param title_txt Plain text
+        * @param msg HTML
+        * @param buttons See http://docs.jquery.com/UI/Dialog#option-buttons
+        */
+       updateProgressWin: function( title_txt, msg, buttons ) {
                var _this = this;
-                if(!title_txt)
-                  title_txt = _this.getProgressTitle();
-                if(!msg)
-                  msg = mv_get_loading_img( 'left:40%;top:40px;');
-                $j( '#upProgressDialog' ).dialog('option', 'title',  title_txt );
-                $j( '#upProgressDialog' ).html( msg );
-                if(buttons){
-                        $j('#upProgressDialog').dialog('option','buttons', buttons);
-                }else{
-                        //@@todo should fix jquery ui to not use object keys as user msg's
-                        var bObj = {};
-                        bObj[ gM('mwe-ok') ] =  function(){
-                                 $j(this).dialog('close');
-                        };
-                        $j('#upProgressDialog').dialog('option','buttons', bObj);
-                }
+
+               if ( !title_txt )
+                       title_txt = _this.getProgressTitle();
+
+               if ( !msg )
+                       msg = mv_get_loading_img( 'left:40%;top:40px;' );
+
+               if ( !buttons ) {
+                       // If no buttons are specified, add a close button
+                       buttons = {};
+                       buttons[ gM( 'mwe-ok' ) ] =  function() {
+                               $j( this ).dialog( 'close' );
+                       };
+               }
+
+               $j( '#upProgressDialog' ).dialog( 'option', 'title',  title_txt );
+               $j( '#upProgressDialog' ).html( msg );
+               $j( '#upProgressDialog' ).dialog( 'option', 'buttons', buttons );
        },
-       getProgressTitle:function(){
-               return gM('mwe-upload-in-progress');
+
+       /**
+        * Get the default title of the progress window
+        */
+       getProgressTitle: function() {
+               return gM( 'mwe-upload-in-progress' );
        },
-       getEditForm:function(){
-               if( this.target_edit_from && $j( this.target_edit_from ).length != 0){
-                       return $j( this.target_edit_from ).get(0);
+
+       /**
+        * Get the DOMNode of the form element we are rewriting.
+        * Returns false if it can't be found.
+        */
+       getForm: function() {
+               if ( this.form_selector && $j( this.form_selector ).length != 0 ) {
+                       return $j( this.form_selector ).get( 0 );
+               } else {
+                       js_log( "mvBaseUploadInterface.getForm(): no form_selector" );
+                       return false;
                }
-               //just return the first form fond on the page.
-               return $j('form :first').get(0);
        },
-       updateProgress:function( perc ){
-               //js_log('update progress: ' + perc);
-               $j( '#up-progressbar' ).progressbar('value', parseInt( perc * 100 ) );
-               $j( '#up-pstatus' ).html( parseInt( perc * 100 ) + '% - ' );
+
+       /**
+        * Update the progress bar to a given completion fraction (between 0 and 1)
+        */
+       updateProgress: function( fraction ) {
+               //js_log('update progress: ' + fraction);
+               $j( '#up-progressbar' ).progressbar( 'value', parseInt( fraction * 100 ) );
+               $j( '#up-pstatus' ).html( parseInt( fraction * 100 ) + '% - ' );
        },
-       /*update to jQuery.ui progress display type */
-       dispProgressOverlay:function(){
-         var _this = this;
-         
-         //remove old instance:
-         if($j('#upProgressDialog').length !=0 ){
-                $j('#upProgressDialog').dialog( 'destroy' ).remove();
-         }
-         //re add it:
-         $j('body').append('<div id="upProgressDialog" ></div>');
-
-         $j('#upProgressDialog').dialog({
-                 title:_this.getProgressTitle(),
-                 bgiframe: true,
-                 modal: true,
-                 draggable:true,
-                 width:400,
-                 heigh:200,
-                 beforeclose: function(event, ui) {
-                         if( event.button==0 && _this.action_done === false){
-                               return _this.cancel_action();
-                         }else{
-                                //click on button (don't do close action);
-                                return true;
-                         }
-                 },
-                 buttons: _this.cancel_button()
-         });
-         $j('#upProgressDialog').html(         
-               '<div id="up-pbar-container" style="width:90%;height:15px;" >' +                
-               '<div id="up-progressbar" style="height:15px;"></div>' +
-                       '<div id="up-status-container">'+
-                               '<span id="up-pstatus">0% - </span> ' +
-                               '<span id="up-status-state">' + gM('mwe-uploaded-status') + '</span> ' +
-                       '</div>'+
-               '</div>'
-         )
-         //just display an empty progress window
-         $j('#upProgressDialog').dialog('open');
-
-         //setup progress bar:
-         $j('#up-progressbar').progressbar({
-                 value:0
-         });
+
+       /**
+        * Show a dialog box reporting upload progress and status
+        */
+       displayProgressOverlay: function() {
+               var _this = this;
+
+               // Remove the old instance if present
+               if( $j( '#upProgressDialog' ).length != 0 ) {
+                       $j( '#upProgressDialog' ).dialog( 'destroy' ).remove();
+               }
+               // Add a new one
+               $j( 'body' ).append( '<div id="upProgressDialog" ></div>' );
+
+               $j( '#upProgressDialog' ).dialog( {
+                       title: _this.getProgressTitle(),
+                       bgiframe: true,
+                       modal: true,
+                       draggable: true,
+                       width: 400,
+                       heigh: 200,
+                       beforeclose: function( event, ui ) {
+                               // If the upload is not complete, ask the user if they want to cancel
+                               if ( event.button == 0 && _this.action_done === false ) {
+                                       _this.onCancel();
+                                       return false;
+                               } else {
+                                       // Complete already, allow close
+                                       return true;
+                               }
+                       },
+                       buttons: _this.getCancelButton()
+               } );
+               $j( '#upProgressDialog' ).html(
+                       '<div id="up-pbar-container" style="width:90%;height:15px;" >' +
+                       '<div id="up-progressbar" style="height:15px;"></div>' +
+                               '<div id="up-status-container">' +
+                                       '<span id="up-pstatus">0% - </span> ' +
+                                       '<span id="up-status-state">' + gM( 'mwe-uploaded-status' ) + '</span> ' +
+                               '</div>'+
+                       '</div>'
+               );
+               // Open the empty progress window
+               $j( '#upProgressDialog' ).dialog( 'open' );
+
+               // Create progress bar
+               $j( '#up-progressbar' ).progressbar({
+                       value: 0
+               });
        },
-       cancel_button:function(){
-          var _this = this;
-          var cancelBtn = new Array();
-          cancelBtn[ gM('mwe-cancel') ] =  function(){
-                       return _this.cancel_action(this)
-          };
-          return cancelBtn;
+
+       /**
+        * Get a standard cancel button in the jQuery.ui dialog format
+        */
+       getCancelButton: function() {
+               var _this = this;
+               var cancelBtn = new Array();
+               cancelBtn[ gM( 'mwe-cancel' ) ] = function() {
+                       return _this.onCancel( this )
+               };
+               return cancelBtn;
        },
-       cancel_action : function( dlElm ){
+
+       /**
+        * UI cancel button handler.
+        * Show a dialog box asking the user whether they want to cancel an upload.
+        * FIXME: doesn't work at all.
+        */
+       onCancel: function( dlElm ) {
                //confirm:
-               if( confirm( gM('mwe-cancel-confim') )){
+               if ( confirm( gM( 'mwe-cancel-confim' ) ) ) {
                        //@@todo (cancel the encode / upload)
-                       $j(this).dialog('close');                               
+                       $j( this ).dialog( 'close' );
                }
        }
 };
 
-//add some jquery binding helpers
-(function($) {
+// jQuery plugins
+
+( function( $ ) {
        /**
-        * doDestCheck checks the destination
+        * Check the upload destination filename for conflicts and show a conflict
+        * error message if there is one
         */
-       $.fn.doDestCheck = function( opt ){
+       $.fn.doDestCheck = function( opt ) {
                var _this = this;
-               js_log('doDestCheck::' + _this.selector);
+               js_log( 'doDestCheck::' + _this.selector );
 
-               //set up option defaults;
-               if(!opt.warn_target)
+               // Set up option defaults
+               if ( !opt.warn_target )
                        opt.warn_target = '#wpDestFile-warning';
-               
-               //add the wpDestFile-warning target:
-               if( $j( '#wpDestFile-warning' ).length == 0 )
-                       $j('#mw-htmlform-options tr:last').after('<tr><td></td><td id="wpDestFile-warning"></td></tr>');                        
-                                                               
-               //empty target warn:
+
+               // Add the wpDestFile-warning row
+               if ( $j( '#wpDestFile-warning' ).length == 0 ) {
+                       $j( '#mw-htmlform-options tr:last' )
+                               .after( '<tr><td></td><td id="wpDestFile-warning"></td></tr>' );
+               }
+
+               // Remove any existing warning
                $j( opt.warn_target ).empty();
-               
-               //show loading          
-               $j( _this.selector ).append('<img id="mw-spinner-wpDestFile" src ="'+ stylepath + '/common/images/spinner.gif" />');
-               
-               //try and get a thumb of the current file (check its destination)
-               do_api_req({
-                       'data':{
-                               'titles': 'File:' + $j(_this.selector).val(),//@@todo we may need a more clever way to get a the filename
-                               'prop':  'imageinfo',
-                               'iiprop':'url|mime|size',
-                               'iiurlwidth': 150
-                       }
-               },function(data){
-                       //remove spinner:
-                       $j('#mw-spinner-wpDestFile').remove();
-                       if(data && data.query && data.query.pages){
-                               if( data.query.pages[-1] ){
-                                       //all good no file there
-                               }else{
-                                       for( var page_id in data.query.pages ) {
-                                               if( data.query.pages[ page_id ].imageinfo ) {
-                                                       var ntitle = ( data.query.normalized)? data.query.normalized[0].to : data.query.pages[ page_id ].title
-                                                       var img = data.query.pages[ page_id ].imageinfo[0];
-                                                       $j('#wpDestFile-warning').html(                                                         
-                                                                       gM('mwe-fileexists', ntitle) +
-                                                                       '<div class="thumb tright">' +
-                                                                               '<div style="width: ' + ( parseInt(img.thumbwidth)+2 ) + 'px;" class="thumbinner">' +
-                                                                                       '<a title="' + ntitle + '" class="image" href="' + img.descriptionurl + '">' +
-                                                                                               '<img width="' + img.thumbwidth + '" height="' + img.thumbheight + '" border="0" class="thumbimage" ' +
-                                                                                               'src="' + img.thumburl + '"' +
-                                                                                               '        alt="' + ntitle + '"/>' +
-                                                                                       '</a>' +
-                                                                                       '<div class="thumbcaption">' +
-                                                                                               '<div class="magnify">' +
-                                                                                                       '<a title="' + gM('thumbnail-more') + '" class="internal" ' +
-                                                                                                               'href="' + img.descriptionurl +'"><img width="15" height="11" alt="" ' +
-                                                                                                               'src="' + stylepath + "/common/images/magnify-clip.png\" />" +
-                                                                                                       '</a>'+
-                                                                                               '</div>'+
-                                                                                               gM('mwe-fileexists-thumb') +
-                                                                                       '</div>' +
-                                                                               '</div>'+
-                                                                       '</div>'
-                                                       );
-                                               }
+
+               // Show the AJAX spinner
+               $j( _this.selector )
+                       .append( '<img id="mw-spinner-wpDestFile" ' +
+                               'src ="' + stylepath + '/common/images/spinner.gif" />' );
+
+               // Do the destination check
+               do_api_req(
+                       {
+                               'data': {
+                                       //@@todo we may need a more clever way to get a the filename
+                                       'titles': 'File:' + $j( _this.selector ).val(),
+                                       'prop':  'imageinfo',
+                                       'iiprop': 'url|mime|size',
+                                       'iiurlwidth': 150
+                               }
+                       },
+                       function( data ) {
+                               // Remove spinner
+                               $j( '#mw-spinner-wpDestFile' ).remove();
+
+                               if ( !data || !data.query || !data.query.pages ) {
+                                       // Ignore a null result
+                                       return;
+                               }
+
+                               if ( data.query.pages[-1] ) {
+                                       // No conflict found
+                                       return;
+                               }
+                               for ( var page_id in data.query.pages ) {
+                                       if ( !data.query.pages[ page_id ].imageinfo ) {
+                                               continue;
                                        }
+
+                                       // Conflict found, show warning
+                                       if ( data.query.normalized ) {
+                                               var ntitle = data.query.normalized[0].to;
+                                       } else {
+                                               var ntitle = data.query.pages[ page_id ].title
+                                       }
+                                       var img = data.query.pages[ page_id ].imageinfo[0];
+                                       $j( '#wpDestFile-warning' ).html(
+                                               gM( 'mwe-fileexists', ntitle ) +
+                                               '<div class="thumb tright">' +
+                                               '<div ' +
+                                                       'style="width: ' + ( parseInt( img.thumbwidth ) + 2 ) + 'px;" ' +
+                                                       'class="thumbinner">' +
+                                               '<a ' +
+                                                       'title="' + ntitle + '" ' +
+                                                       'class="image" ' +
+                                                       'href="' + img.descriptionurl + '">' +
+                                               '<img ' +
+                                                       'width="' + img.thumbwidth + '" ' +
+                                                       'height="' + img.thumbheight + '" ' +
+                                                       'border="0" ' +
+                                                       'class="thumbimage" ' +
+                                                       'src="' + img.thumburl + '" ' +
+                                                       'alt="' + ntitle + '"/>' +
+                                               '</a>' +
+                                               '<div class="thumbcaption">' +
+                                               '<div class="magnify">' +
+                                               '<a title="' + gM('thumbnail-more') + '" class="internal" ' +
+                                                       'href="' + img.descriptionurl +'">' +
+                                               '<img width="15" height="11" alt="" ' +
+                                                       'src="' + stylepath + "/common/images/magnify-clip.png\" />" +
+                                               '</a>' +
+                                               '</div>' +
+                                               gM( 'mwe-fileexists-thumb' ) +
+                                               '</div>' +
+                                               '</div>' +
+                                               '</div>'
+                                       );
                                }
                        }
-               });
+               );
        }
-})(jQuery);
+})( jQuery );
index c83d296..3d532bd 100644 (file)
@@ -1,5 +1,5 @@
-/* adds firefogg support.
-* autodetects: new upload api or old http POST.
+/* Firefogg support.
+ * autodetects: new upload api or old http POST.
  */
 
 loadGM({
@@ -7,11 +7,11 @@ loadGM({
        "fogg-select_new_file" : "Select new file",
        "fogg-select_url" : "Select URL",
        "fogg-save_local_file" : "Save Ogg",
-       "fogg-check_for_fogg" : "Checking for Firefogg...",
+       "fogg-check_for_firefogg" : "Checking for Firefogg...",
        "fogg-installed" : "Firefogg is installed",
-       "fogg-for_improved_uplods" : "For improved uploads:",
+       "fogg-for_improved_uploads" : "For improved uploads:",
        "fogg-please_install" : "<a href=\"$1\">Install Firefogg<\/a>. More <a href=\"http:\/\/commons.wikimedia.org\/wiki\/Commons:Firefogg\">about Firefogg<\/a>.",
-       "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>",
+       "fogg-use_latest_firefox" : "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>",
        "fogg-passthrough_mode" : "Your selected file is already Ogg or not a video file",
        "fogg-transcoding" : "Encoding video to Ogg...",
        "fogg-encoding-done" : "Encoding complete",
@@ -20,599 +20,876 @@ loadGM({
        "fogg-hidepreview" : "Hide preview"
 });
 
-var firefogg_install_links =  {
-       'macosx':       'http://firefogg.org/macosx/Firefogg.xpi',
-       'win32':        'http://firefogg.org/win32/Firefogg.xpi',
-       'linux' :       'http://firefogg.org/linux/Firefogg.xpi'
+var firefogg_install_links = {
+       'macosx': 'http://firefogg.org/macosx/Firefogg.xpi',
+       'win32': 'http://firefogg.org/win32/Firefogg.xpi',
+       'linux': 'http://firefogg.org/linux/Firefogg.xpi'
 };
 
 var default_firefogg_options = {
-       // What to do when finished uploading
-       'done_upload_cb':false,
-       // If firefoog is enabled
-       'fogg_enabled':false,
-       // The api url to upload to
-       'api_url':null,
-       // The passthrough flag (enables un-modified uploads)
+       // Callback for upload completion
+       'done_upload_cb': false,
+
+       // True if Firefogg is enabled in the client
+       'have_firefogg': false,
+
+       // The API URL to upload to
+       'api_url': null,
+
+       // True when a file is uploaded without re-encoding
        'passthrough': false,
-       // If we will be showing the encoder interface
+
+       // True if we will be showing the encoder interface
        'encoder_interface': false,
-       // If we want to limit the library functionality to "only firefoog" (no upload or progress bars)
-       'only_fogg': false,
 
-       // Callbacks:
-       'new_source_cb': false, //called on source name update passes along source name
+       // True if we want to limit the library functionality to "only firefogg" 
+       // (no upload or progress bars)
+       'only_firefogg': false,
 
-       // Target control container or form (can't be left null)
+       // Callback which is called when the source name changes
+       'new_source_cb': false,
+
+       // CSS selector identifying the target control container or form (can't be left null)
        'selector': '',
 
-       // If not rewriting a form we are encoding local.
-       'form_rewrite': false,
+       // May be "upload" to if we are rewriting an upload form, or "local" if we are encoding a local file    
+       'form_type': 'local',
 
-       // Target buttons:
+       // CSS selector for the select file button
        'target_btn_select_file': false,
+
+       // CSS selector for the select new file button
        'target_btn_select_new_file': false,
 
-       //'target_btn_select_url': false,
+       // CSS selector for the save local file button
        'target_btn_save_local_file': false,
+
+       // CSS selector for the input file name button
        'target_input_file_name': false,
 
+       // CSS selector for the "checking for firefogg..." message div
+       'target_check_for_firefogg': false,
 
-       // Target install descriptions
-       'target_check_for_fogg': false,
+       // CSS selector for the "firefogg is installed" message div
        'target_installed': false,
+
+       // CSS selector for the "please install firefogg" message div
        'target_please_install': false,
-       'target_use_latest_fox': false,
-       
-       // Status:
-       'target_passthrough_mode':false,
-
-       // If firefogg should take over the form submit action
-       'firefogg_form_action':true,
-       
-       // If we should show a preview of encoding progress 
-       'show_preview':false
-}
-
-
-var mvFirefogg = function(iObj){
-       return this.init( iObj );
-}
-mvFirefogg.prototype = { //extends mvBaseUploadInterface
-
-       min_firefogg_version : '0.9.9.5',
-       fogg_enabled : false,            //if firefogg is enabled or not.
-       encoder_settings:{                      //@@todo allow server to set this
+
+       // CSS selector for the "please use Firefox 3.5" message div
+       'target_use_latest_firefox': false,
+
+       // CSS selector for the message div warning that passthrough mode is enabled
+       'target_passthrough_mode': false,
+
+       // True if firefogg should take over the form submit action
+       'firefogg_form_action': true,
+
+       // True if we should show a preview of the encoding progress
+       'show_preview': false
+};
+
+
+var mvFirefogg = function( options ) {
+       return this.init( options );
+};
+
+mvFirefogg.prototype = { // extends mvBaseUploadInterface
+       min_firefogg_version: '0.9.9.5',
+       default_encoder_settings: { // @@todo allow the server to set these
                'maxSize'        : '400',
         'videoBitrate'   : '544',
         'audioBitrate'   : '96',
         'noUpscaling'    : true
        },
-       sourceFileInfo: {},
-       ogg_extensions: ['ogg', 'ogv', 'oga'],
-       video_extensions: ['avi', 'mov', 'mp4', 'mp2', 'mpeg', 'mpeg2', 'mpeg4', 'dv', 'wmv'],
+       have_firefogg: null, // lazy initialised, use getFirefogg()
+       current_encoder_settings: null, // lazy initialised, use getEncoderSettings()
+       sourceFileInfo: null, // lazy initialised, use getSourceFileInfo()
+       ogg_extensions: [ 'ogg', 'ogv', 'oga' ],
+       video_extensions: [ 'avi', 'mov', 'mp4', 'mp2', 'mpeg', 'mpeg2', 'mpeg4', 'dv', 'wmv' ],
 
        passthrough: false,
        sourceMode: 'file',
 
-       init: function( iObj ){
-               if(!iObj)
-                       iObj = {};
+       /**
+        * Object initialisation
+        */
+       init: function( options ) {
+               if ( !options )
+                       options = {};
 
-               // If we have no api_url set upload to "post"
-               if(!iObj.api_url)
-                       iObj.upload_mode = 'post';
+               // If we have no api_url, set upload mode to "post"
+               if ( !options.api_url )
+                       options.upload_mode = 'post';
 
-               // Inherit iObj properties:
-               for(var i in default_firefogg_options){
-                       if(iObj[i]){
-                               this[i] = iObj[i];
-                       }else{
+               // Set options
+               for ( var i in default_firefogg_options ) {
+                       if ( options[i] ) {
+                               this[i] = options[i];
+                       } else {
                                this[i] = default_firefogg_options[i];
                        }
                }
-               // Check if we want to limit the usage:
-               if(!this.only_fogg){
-                       var myBUI = new mvBaseUploadInterface( iObj );
 
-                       // Standard extends code:
-                       for(var i in myBUI){
-                               if(this[i]){
+               // Inherit from mvBaseUploadInterface (unless we're in only_firefogg mode)
+               if ( !this.only_firefogg ) {
+                       var myBUI = new mvBaseUploadInterface( options );
+
+                       // Prefix conflicting members with pe_
+                       for ( var i in myBUI ) {
+                               if ( this[i] ) {
                                        this['pe_'+ i] = myBUI[i];
-                               }else{
+                               } else {
                                        this[i] =  myBUI[i];
                                }
                        }
                }
 
-               if(!this.selector){
+               if ( !this.selector ) {
                        js_log('firefogg: missing selector ');
                }
        },
-       doRewrite:function( callback ){
-               var _this = this;
-               js_log('sel len: ' + this.selector + '::' + $j(this.selector).length + ' tag:'+ $j(this.selector).get(0).tagName);
-               if( $j(this.selector).length >=0 ){
 
-                       if( $j(this.selector).get(0).tagName.toLowerCase() == 'input' ){
-                               _this.form_rewrite = true;
+       /**
+        * Rewrite the upload form, or create our own upload controls for local transcoding.
+        * Called from $j.firefogg(), in mv_embed.js.
+        */
+       doRewrite: function( callback ) {
+               var _this = this;
+               js_log( 'sel len: ' + this.selector + '::' + $j( this.selector ).length + 
+                               ' tag:' + $j( this.selector ).get( 0 ).tagName );
+               if ( $j( this.selector ).length >= 0 ) {
+                       if ( $j( this.selector ).get( 0 ).tagName.toLowerCase() == 'input' ) {
+                               _this.form_type = 'upload';
                        }
                }
-               // Check if we are rewriting an input or a form:
-               if( this.form_rewrite ){
+               if ( this.form_type == 'upload' ) {
+                       // Initialise existing upload form
                        this.setupForm();
-               }else{
-                       this.doControlHTML();
-                       this.doControlBindings();
+               } else {
+                       // Create our own form controls
+                       this.createControls();
+                       this.bindControls();
                }
 
-               // doRewrite is done:
-               if(callback)
+               if ( callback )
                        callback();
        },
-       doControlHTML: function( ){
+
+       /**
+        * Create controls for local transcoding and add them to the page
+        */
+       createControls: function() {
                var _this = this;
                var out = '';
-               $j.each(default_firefogg_options, function(target, na){
-                       if(target.substring(0, 6)=='target'){
-                               //js_log('check for target html: ' + target);
-                               // Check for the target if missing add to the output:
-                               if( _this[target] === false){
-                                       out += _this.getTargetHtml(target) + ' ';
+               $j.each( default_firefogg_options, function( target, na ) {
+                       if ( /^target/.test( target ) ) {
+                               // Create the control if it doesn't already exist
+                               if( _this[target] === false ) {
+                                       out += _this.getControlHtml(target) + ' ';
                                        // Update the target selector
-                                   _this[target] = _this.selector + ' .' + target;
+                                       _this[target] = _this.selector + ' .' + target;
                                }
                        }
                });
                $j( this.selector ).append( out ).hide();
        },
-       getTargetHtml:function(target){
-               if( target.substr(7,3)=='btn'){
-                       return '<input style="" class="' + target + '" type="button" value="' + gM( 'fogg-' + target.substring(11)) + '"/> ';
-               }else if(target.substr(7,5)=='input'){
-                       return '<input style="" class="' + target + '" type="text" value="' + gM( 'fogg-' + target.substring(11)) + '"/> ';
-               }else{
-                       return '<div style="" class="' + target + '" >'+ gM('fogg-'+ target.substring(7)) + '</div> ';
+
+       /**
+        * Get the HTML for the control with a particular name
+        */
+       getControlHtml: function( target ) {
+               if ( /^target_btn_/.test( target ) ) {
+                       // Button
+                       var msg = gM( target.replace( /^target_btn_/, 'fogg-' ) );
+                       return '<input style="" ' + 
+                               'class="' + target + '" ' + 
+                               'type="button" ' + 
+                               'value="' + msg + '"/> ';
+               } else if ( /^target_input_/.test( target ) ) {
+                       // Text input
+                       var msg = gM( target.replace( /^target_input_/, 'fogg-' ) );
+                       return '<input style="" ' + 
+                               'class="' + target + '" ' + 
+                               'type="text" ' + 
+                               'value="' + msg + '"/> ';
+               } else if ( /^target_/.test( target ) ) {
+                       // Message
+                       var msg = gM( target.replace( '/^target_/', 'fogg-' ) );
+                       return '<div style="" class="' + target + '" >' + msg + '</div> ';
+               } else {
+                       js_error( 'Invalid target: ' + target );
+                       return '';
                }
        },
-       doControlBindings: function(){
+
+       /**
+        * Set up events for the controls which were created with createControls()
+        */
+       bindControls: function() {
                var _this = this;
 
-               // Hide all targets:
-               var hide_target_list='';
-               var coma='';
-               $j.each( default_firefogg_options, function(target, na) {
-                       if(target.substring(0, 6)=='target'){
-                               hide_target_list+=coma + _this[target];
-                               coma=',';
+               // Hide all controls
+               var hide_target_list = '';
+               var comma = '';
+               $j.each( default_firefogg_options, function( target, na ) {
+                       if ( /^target/.test( target ) ) {
+                               hide_target_list += comma + _this[target];
+                               comma = ',';
                        }
                });
-               
-               // Hide all but check-for-fogg
                $j( hide_target_list ).hide();
-               // Now that the proper set of items has been hiiden show:
+
+               // Now show the form
                $j( _this.selector ).show();
-               
-               // Check for firefogg
-               if( _this.firefoggCheck() ){
 
-                       // If rewriting the form lets keep the text input around:
-                       if( _this.form_rewrite )
+               if ( _this.firefoggCheck() ) {
+                       // Firefogg enabled
+                       // If we're in upload mode, show the input filename
+                       if ( _this.form_type == 'upload' )
                                $j( _this.target_input_file_name ).show();
 
-                       // Show select file:
-                       $j( this.target_btn_select_file ).unbind(
-                               ).attr('disabled', false
-                               ).css({'display':'inline'}
-                               ).click(function(){
-                                       _this.selectFogg();
-                               });
+                       // Show the select file button
+                       $j( this.target_btn_select_file )
+                               .unbind()
+                               .attr( 'disabled', false )
+                               .css( { 'display': 'inline' } )
+                               .click( function() {
+                                       _this.selectSourceFile();
+                               } );
 
-                   //also setup the text file display on Click to select file:
-                   $j(this.target_input_file_name).unbind().attr('readonly', 'readonly').click(function(){
-                       _this.selectFogg();
-                   })
+                       // Set up the click handler for the filename box
+                       $j( this.target_input_file_name )
+                               .unbind()
+                               .attr( 'readonly', 'readonly' )
+                               .click( function() {
+                                       _this.selectSourceFile();
+                               });
+               } else {
+                       // Firefogg disabled
+                       // FIXME: move this elsewhere. None of this is related to binding.
 
-               }else{
-                       // First check firefox version:
-                       if(!( $j.browser.mozilla && $j.browser.version >= '1.9.1' )) {
-                               js_log( 'show use latest::' + _this.target_use_latest_fox );
-                               if( _this.target_use_latest_fox ){
-                                       if( _this.form_rewrite )
-                                               $j( _this.target_use_latest_fox ).prepend( gM('fogg-for_improved_uplods') );
+                       // Show the "use latest Firefox" message if necessary
+                       if ( !( $j.browser.mozilla && $j.browser.version >= '1.9.1' ) ) {
+                               js_log( 'show use latest::' + _this.target_use_latest_firefox );
+                               if ( _this.target_use_latest_firefox ) {
+                                       if ( _this.form_type == 'upload' )
+                                               $j( _this.target_use_latest_firefox )
+                                                       .prepend( gM( 'fogg-for_improved_uploads' ) );
 
-                                       $j( _this.target_use_latest_fox ).show();
+                                       $j( _this.target_use_latest_firefox ).show();
                                }
-                               return ;
+                               return;
                        }
 
-                       // If rewriting form use upload msg text
-                       var upMsg = (_this.form_rewrite) ? gM('fogg-for_improved_uplods') : '';
-                       $j( _this.target_please_install ).html( upMsg + gM('fogg-please_install', _this.getOSlink() )).css('padding', '10px').show();
+                       // Otherwise show the "install Firefogg" message
+                       // FIXME: getFirefoggInstallUrl() may return false, this is not handled
+                       var upMsg = ( _this.form_type == 'upload' ) ? gM( 'fogg-for_improved_uploads' ) : '';
+                       $j( _this.target_please_install )
+                               .html( upMsg + gM( 'fogg-please_install', _this.getFirefoggInstallUrl() ) )
+                               .css( 'padding', '10px' )
+                               .show();
                }
-               // Setup the target save local file bindings:
-               $j( _this.target_btn_save_local_file ).unbind().click(function(){
-                       _this.saveLocalFogg();
-               });
+
+               // Set up the click handler for the "save local file" button
+               $j( _this.target_btn_save_local_file )
+                       .unbind()
+                       .click( function() {
+                               _this.doLocalEncodeAndSave();
+                       } );
        },
+
        /*
-        * returns the firefogg link for your os:
+        * Get the URL for installing firefogg on the client OS
         */
-       getOSlink:function(){
+       getFirefoggInstallUrl: function() {
                var os_link = false;
-               if(navigator.oscpu){
-                       if(navigator.oscpu.search('Linux') >= 0)
+               if ( navigator.oscpu ) {
+                       if ( navigator.oscpu.search( 'Linux' ) >= 0 )
                                os_link = firefogg_install_links['linux'];
-                       else if(navigator.oscpu.search('Mac') >= 0)
-                                 os_link = firefogg_install_links['macosx'];
-                       else if(navigator.oscpu.search('Win') >= 0)
-                                 os_link = firefogg_install_links['win32'];
+                       else if ( navigator.oscpu.search( 'Mac' ) >= 0 )
+                               os_link = firefogg_install_links['macosx'];
+                       else if (navigator.oscpu.search( 'Win' ) >= 0 )
+                               os_link = firefogg_install_links['win32'];
                }
-               return os_link
+               return os_link;
        },
-       firefoggCheck:function(){
-               if(typeof(Firefogg) != 'undefined' && Firefogg().version >= this.min_firefogg_version){
-                       this.fogg = new Firefogg();
-                       this.fogg_enabled = true;
-                       return true;
-               }else{
-                       return false;
+
+       /**
+        * Get the Firefogg instance (or false if firefogg is unavailable)
+        */
+       getFirefogg: function() {
+               if ( this.have_firefogg == null ) {
+                       if ( typeof( Firefogg ) != 'undefined' 
+                               && Firefogg().version >= this.min_firefogg_version ) 
+                       {
+                               this.have_firefogg = true;
+                               this.fogg = new Firefogg();
+                       } else {
+                               this.have_firefogg = false;
+                               this.fogg = false;
+                       }
                }
+               return this.fogg;
        },
-       // Assume input target
-       setupForm: function(){
-               js_log('firefogg::setupForm::');
-               //to parent form setup if we want http updates
-               if( this.form_rewrite ){
-                       //do parent form setup:
+
+       /**
+        * Set up the upload form
+        */
+       setupForm: function() {
+               js_log( 'firefogg::setupForm::' );
+
+               // Set up the parent if we are in upload mode
+               if ( this.form_type == 'upload' ) {
                        this.pe_setupForm();
                }
 
-               // Check if we have firefogg (if not just add a link and stop processing)
-               if( !this.firefoggCheck() ){
-                       //add some status indicators if not provided:
-                       if(!this.target_please_install){
-                               $j(this.selector).after ( this.getTargetHtml('target_please_install') );
+               // If Firefogg is not available, just show a "please install" message
+               if ( !this.firefoggCheck() ) {
+                       if ( !this.target_please_install ) {
+                               $j( this.selector ).after( this.getControlHtml( 'target_please_install' ) );
                                this.target_please_install = this.selector + ' ~ .target_please_install';
                        }
-                       if(!this.target_use_latest_fox){
-                               $j(this.selector).after ( this.getTargetHtml('target_use_latest_fox') );
-                               this.target_use_latest_fox = this.selector + ' ~ .target_use_latest_fox';
+                       if ( !this.target_use_latest_firefox ) {
+                               $j( this.selector ).after( this.getControlHtml( 'target_use_latest_firefox' ) );
+                               this.target_use_latest_firefox = this.selector + ' ~ .target_use_latest_firefox';
                        }
-                       // Update download link:
-                       this.doControlBindings();
-                       return ;
+                       // Show download link
+                       this.bindControls();
+                       return;
                }
 
-               // Change the file browser to type text: (can't directly change input from "file" to "text" so longer way:
-               var inTag = '<input ';
-               $j.each($j(this.selector).get(0).attributes, function(i, attr){
+               // Change the file browser to type text. We can't simply change the attribute so 
+               // we have to delete and recreate.
+               var inputTag = '<input ';
+               $j.each( $j( this.selector ).get( 0 ).attributes, function( i, attr ) {
                        var val = attr.value;
-                       if( attr.name == 'type')
+                       if ( attr.name == 'type' )
                                val = 'text';
-                       inTag += attr.name + '="' + val + '" ';
-               });
-               if(!$j(this.selector).attr('style'))
-                       inTag += 'style="display:inline" ';
+                       inputTag += attr.name + '="' + val + '" ';
+               } );
+               if ( !$j( this.selector ).attr( 'style' ) )
+                       inputTag += 'style="display:inline" ';
 
-               inTag+= '/><span id="' + $j(this.selector).attr('name') + '_fogg-control"></span>';
+               var id = $j( this.selector ).attr( 'name' ) + '_firefogg-control';
+               inputTag += '/><span id="' + id + '"></span>';
 
-               js_log('set input: ' + inTag);
-               $j(this.selector).replaceWith(inTag);
+               js_log( 'set input: ' + inputTag );
+               $j( this.selector ).replaceWith( inputTag );
 
-               this.target_input_file_name = 'input[name=' + $j(this.selector).attr('name') + ']';
-               
-               // Update the selector to the control target:
-               this.selector = '#' + $j(this.selector).attr('name') +  "_fogg-control";
+               this.target_input_file_name = 'input[name=' + $j( this.selector ).attr( 'name' ) + ']';
 
-               this.doControlHTML();
+               // Point the selector at the span we just created
+               this.selector = '#' + id;
 
-               // Update the bindings:
-               this.doControlBindings();
+               // Create controls for local transcoding
+               this.createControls();
+               this.bindControls();
        },
-       // Do firefogg specific additions: 
-       dispProgressOverlay:function(){
-               this.pe_dispProgressOverlay();                  
-               // If we are uploading video (not in passthrough mode show preview button)
-               if( this.fogg_enabled && ! this.encoder_settings['passthrough']  && ! this.http_copy_upload ){ 
-                       this.doPreviewControl();        
+
+       /**
+        * Display an upload progress overlay. Overrides the function in mvBaseUploadInterface.
+        */
+       displayProgressOverlay: function() {
+               this.pe_dispProgressOverlay();
+               // If we are uploading video (not in passthrough mode), show preview button
+               if( this.getFirefogg() && !this.getEncoderSettings()['passthrough']  
+                       && !this.isCopyUpload() ) 
+               {
+                       this.createPreviewControls();
                }
        },
-       doPreviewControl:function(){
+
+       /**
+        * Create controls for showing a transcode/crop/resize preview
+        */
+       createPreviewControls: function() {
                var _this = this;
-               // Prepend preview (if fogg)                            
-               $j('#upProgressDialog').append(         
-                       '<div style="clear:both;height:3em"/>'+                                                 
-                       $j.btnHtml(gM('fogg-preview'), 'fogg_preview', 'triangle-1-e') + 
-                       '<div style="padding:10px;">' +                                 
+               // Add the preview button and canvas
+               $j( '#upProgressDialog' ).append(
+                       '<div style="clear:both;height:3em"/>' +
+                       $j.btnHtml( gM( 'fogg-preview' ), 'fogg_preview', 'triangle-1-e' ) +
+                       '<div style="padding:10px;">' +
                                '<canvas style="margin:auto;" id="fogg_preview_canvas" />' +
                        '</div>'
                );
-               // Set initial state
-               if( _this.show_preview == true){
-                       $j('#fogg_preview_canvas').show();
-               }else{
-                       // Update icon:
-                       $j(this).children('.ui-icon')
-                               .removeClass('ui-icon-triangle-1-s')
-                               .addClass('ui-icon-triangle-1-e');                                                                      
-                       // Update text:
-                       $j(this).children('.btnText').text( gM('fogg-preview') );                               
-                       $j('#fogg_preview_canvas').hide();
-               }
-               // Apply preview binding:
-               $j('#upProgressDialog .fogg_preview').btnBind().click( function(){
-                       js_log("click .foog_preview" + $j(this).children('.ui-icon').attr('class') );
-                       // Check state: 
-                       if( $j(this).children('.ui-icon').hasClass('ui-icon-triangle-1-e') ){
-                               _this.show_preview = true;                      
-                               // Update icon:
-                               $j(this).children('.ui-icon')
-                                       .removeClass('ui-icon-triangle-1-e')
-                                       .addClass('ui-icon-triangle-1-s'); 
-                               // Update text
-                               $j(this).children('.btnText').text( gM('fogg-hidepreview') );
-                                
-                               // Show preview window                  
-                               $j('#fogg_preview_canvas').show('fast');
-                       }else{                                  
-                               _this.show_preview = false;                                             
-                               // Update icon:
-                               $j(this).children('.ui-icon')
-                                       .removeClass('ui-icon-triangle-1-s')
-                                       .addClass('ui-icon-triangle-1-e');                                                                      
-                               // Update text:
-                               $j(this).children('.btnText').text( gM('fogg-preview') );                               
-                               
-                               $j('#fogg_preview_canvas').hide('slow');
-                       }
-                       // Don't follow the #
-                       return false; 
+
+               // Set the initial state
+               if ( _this.show_preview == true ) {
+                       $j( '#fogg_preview_canvas' ).show();
+               } else {
+                       // Fix the icon class
+                       $j( this ).children( '.ui-icon' )
+                               .removeClass( 'ui-icon-triangle-1-s' )
+                               .addClass( 'ui-icon-triangle-1-e' );
+                       // Set the button text
+                       $j( this ).children( '.btnText' ).text( gM( 'fogg-preview' ) );
+                       $j( '#fogg_preview_canvas' ).hide();
+               }
+
+               // Bind the preview button
+               $j( '#upProgressDialog .fogg_preview' ).btnBind().click( function() {
+                       return _this.onPreviewClick( this );
                });
-       }, 
-       doRenderPreview:function(){
-               var _this = this;               
-               // Set up the hidden video to pull frames from: 
-               if( $j('#fogg_preview_vid').length == 0 )
-                       $j('body').append('<video id="fogg_preview_vid" style="display:none"></video>');        
-               var v = $j('#fogg_preview_vid').get(0);                                                 
-               
-               function seekToEnd(){                   
-                   var v = $j('#fogg_preview_vid').get(0);                     
-                   v.currentTime = v.duration-0.4;             
-               }
-               function getFrame() {
-                       var v = $j('#fogg_preview_vid').get(0);
-                       var canvas = $j('#fogg_preview_canvas').get(0);
-                       if( canvas ){
+       },
+
+       /**
+        * onclick handler for the hide/show preview button
+        */
+       onPreviewClick: function( sourceNode ) {
+               var button = $j( sourceNode );
+               var icon = button.children( '.ui-icon' );
+               js_log( "click .fogg_preview" + icon.attr( 'class' ) );
+
+               if ( icon.hasClass( 'ui-icon-triangle-1-e' ) ) {
+                       // Show preview
+                       // Toggle button class and set button text to "hide".
+                       this.show_preview = true;
+                       icon.removeClass( 'ui-icon-triangle-1-e' ).addClass( 'ui-icon-triangle-1-s' );
+                       button.children( '.btnText' ).text( gM( 'fogg-hidepreview' ) );
+                       $j( '#fogg_preview_canvas' ).show( 'fast' );
+               } else {
+                       // Hide preview
+                       // Toggle button class and set button text to "show".
+                       this.show_preview = false;
+                       icon.removeClass( 'ui-icon-triangle-1-s' ).addClass( 'ui-icon-triangle-1-e' );
+                       button.children( '.btnText' ).text( gM( 'fogg-preview' ) );
+                       $j( '#fogg_preview_canvas' ).hide( 'slow' );
+               }
+               // Don't follow the # link
+               return false;
+       },
+
+       /**
+        * Render the preview frame (asynchronously)
+        */
+       renderPreview: function() {
+               var _this = this;
+               // Set up the hidden video to pull frames from
+               if( $j( '#fogg_preview_vid' ).length == 0 )
+                       $j( 'body' ).append( '<video id="fogg_preview_vid" style="display:none"></video>' );
+               var v = $j( '#fogg_preview_vid' ).get( 0 );
+
+               function seekToEnd() {
+                       var v = $j( '#fogg_preview_vid' ).get( 0 );
+                       // TODO: document arbitrary 0.4s constant
+                       v.currentTime = v.duration - 0.4;
+               }
+               function renderFrame() {
+                       var v = $j( '#fogg_preview_vid' ).get( 0 );
+                       var canvas = $j( '#fogg_preview_canvas' ).get( 0 );
+                       if ( canvas ) {
                                canvas.width = 160;
-                               canvas.height = canvas.width * v.videoHeight/v.videoWidth;
-                               var ctx = canvas.getContext("2d");
-                               ctx.drawImage(v, 0, 0, canvas.width, canvas.height);
+                               canvas.height = canvas.width * v.videoHeight / v.videoWidth;
+                               var ctx = canvas.getContext( "2d" );
+                               ctx.drawImage( v, 0, 0, canvas.width, canvas.height );
                        }
-               }               
-               var previewI=null;
-               function preview() {                            
-                       // Initialize the video if not setup already:
-                       var v = $j('#fogg_preview_vid').get(0);                                         
-                       if( v.src != _this.fogg.previewUrl ){           
-                               js_log('init preview with url:' + _this.fogg.previewUrl);               
+               }
+               function preview() {
+                       // Initialize the video if it is not set up already
+                       var v = $j( '#fogg_preview_vid' ).get( 0 );
+                       if ( v.src != _this.fogg.previewUrl ) {
+                               js_log( 'init preview with url:' + _this.fogg.previewUrl );
                                v.src = _this.fogg.previewUrl;
-                               
-                               // Set the video to seek to the end of the video
-                               v.removeEventListener("loadedmetadata", seekToEnd, true);
-                               v.addEventListener("loadedmetadata", seekToEnd, true);
-                               
-                               // Render a frame once seek is complete: 
-                               v.removeEventListener("seeked", getFrame, true);
-                               v.addEventListener("seeked", getFrame, true);
-                               
-                               // Refresh the video duration/meta:
-                               clearInterval(previewI);
-                               var previewI = setInterval(function(){
-                                       if (_this.fogg.status() != "encoding"){
-                                               clearInterval(previewI);
+
+                               // Once it's loaded, seek to the end
+                               v.removeEventListener( "loadedmetadata", seekToEnd, true );
+                               v.addEventListener( "loadedmetadata", seekToEnd, true );
+
+                               // When the seek is done, render a frame
+                               v.removeEventListener( "seeked", renderFrame, true );
+                               v.addEventListener( "seeked", renderFrame, true );
+
+                               // Refresh the video duration and metadata
+                               var previewTimer = setInterval( function() {
+                                       if ( _this.fogg.status() != "encoding" ) {
+                                               clearInterval( previewTimer );
                                                _this.show_preview == false;
                                        }
-                                       if (_this.show_preview == true) {
+                                       if ( _this.show_preview == true ) {
                                                v.load();
                                        }
-                               }, 1000);                        
-                       } 
-               }               
-               preview();      
+                               }, 1000 );
+                       }
+               }
+               preview();
        },
-       getEditForm:function(){
-               if( this.target_edit_from )
-                       return this.pe_getEditForm();
-               // Else try to get the parent "from" of the file selector:
-               return $j(this.selector).parents('form:first').get(0);
+
+       /**
+        * Get the DOMNode of the form element we are rewriting.
+        * Returns false if it can't be found.
+        * Overrides mvBaseUploadInterface.getForm().
+        */
+       getForm: function() {
+               if ( this.form_selector ) {
+                       return this.pe_getForm();
+               } else {
+                       // No configured form selector
+                       // Use the first form descendant of the current container
+                       return $j( this.selector ).parents( 'form:first' ).get( 0 );
+               }
        },
-       selectFogg:function(){
+
+       /**
+        * Show a dialog box allowing the user to select the source file of the 
+        * encode/upload operation. The filename is stored by Firefogg until the 
+        * next encode/upload call.
+        *
+        * After a successful select, the UI is updated accordingly.
+        */
+       selectSourceFile: function() {
                var _this = this;
-               if(_this.fogg.selectVideo() ){
-                       this.selectFoggActions();
+               if( !_this.fogg.selectVideo() ) {
+                       // User clicked "cancel"
+                       return;
                }
+               _this.clearSourceInfoCache();
+               _this.updateSourceFileUI();
        },
-       selectFoggActions:function(){
-               var _this = this;
-               js_log('videoSelectReady');
-               // If not already hidden hide select file and show "select new":
-               $j(_this.target_btn_select_file).hide();
-
-               // Show and setup binding for select new file:
-               $j(_this.target_btn_select_new_file).show().unbind().click(function(){
-                       //create new fogg instance:
-                       _this.fogg = new Firefogg();
-                       _this.selectFogg();
-               });
 
-               // Update if we are in passthrough mode or going to encode
-               if( _this.fogg.sourceInfo && _this.fogg.sourceFilename  ){
-                       //update the source status
-                       try{
-                               _this.sourceFileInfo = JSON.parse( _this.fogg.sourceInfo ) ;
-                       }catch (e){
-                               js_error('error could not parse fogg sourceInfo');
+       /**
+        * Update the UI due to the source file changing
+        */
+       updateSourceFileUI: function() {
+               js_log( 'videoSelectReady' );
+
+               if ( !_this.fogg.sourceInfo || !_this.fogg.sourceFilename ) {
+                       // Something wrong with the source file?
+                       js_log( 'selectSourceFile: sourceInfo/sourceFilename missing' );
+                       return;
+               }
+
+               // Hide the "select file" button and show "select new"
+               $j( _this.target_btn_select_file ).hide();
+               $j( _this.target_btn_select_new_file)
+                       .show()
+                       .unbind()
+                       .click( function() {
+                               _this.fogg = new Firefogg();
+                               _this.selectSourceFile();
+                       } );
+
+               var settings = this.getEncoderSettings();
+
+               // If we're in passthrough mode, update the interface (if not a form)
+               if ( settings['passthrough'] == true && _this.form_type == 'local' ) {
+                       $j( _this.target_passthrough_mode ).show();
+               } else {
+                       $j( _this.target_passthrough_mode ).hide();
+                       // Show the "save file" button if this is a local form
+                       if ( _this.form_type == 'local' ) {
+                               $j( _this.target_btn_save_local_file ).show();
+                       } // else the upload will be done on form submit
+               }
+
+               // Update the input file name box and show it
+               js_log( " should update: " + _this.target_input_file_name + 
+                               ' to: ' + _this.fogg.sourceFilename );
+               $j( _this.target_input_file_name )
+                       .val( _this.fogg.sourceFilename )
+                       .show();
+
+
+               // Notify callback new_source_cb
+               if ( _this.new_source_cb ) {
+                       if ( settings['passthrough'] ) {
+                               var fName = _this.fogg.sourceFilename;
+                       } else {
+                               var oggExt = _this.isSourceAudio() ? 'oga' : 'ogg';
+                               oggExt = _this.isSourceVideo() ? 'ogv' : oggExt;
+                               oggExt = _this.isUnknown() ? 'ogg' : oggExt;
+                               oggName = _this.fogg.sourceFilename.substr( 0,
+                                       _this.fogg.sourceFilename.lastIndexOf( '.' ) );
+                               var fName = oggName + '.' + oggExt;
                        }
+                       _this.new_source_cb( _this.fogg.sourceFilename, fName );
+               }
+       },
 
-                       // Now setup encoder settings based source type:
-                       _this.autoEncoderSettings();
-
-                       // If set to passthough update the interface (if not a form) 
-                       if(_this.encoder_settings['passthrough'] == true && !_this.form_rewrite){
-                               $j(_this.target_passthrough_mode).show();
-                       }else{
-                               $j(_this.target_passthrough_mode).hide();
-                               // If set to encoder expose the encode button:
-                               if( !_this.form_rewrite ){
-                                       $j(_this.target_btn_save_local_file).show();
-                               }
+       /**
+        * Get the source file info for the current file selected into this.fogg
+        */
+       getSourceFileInfo: function() {
+               if ( this.sourceFileInfo == null ) {
+                       if ( !this.fogg.sourceInfo ) {
+                               js_error( 'No firefogg source info is available' );
+                               return false;
                        }
-                       //~otherwise the encoding will be triggered by the form~
-
-                       // Do source name update callback:
-                       js_log(" should update: " + _this.target_input_file_name + ' to: ' + _this.fogg.sourceFilename );
-                       $j(_this.target_input_file_name).val(_this.fogg.sourceFilename).show();
-
-                       if(_this.new_source_cb){
-                               if(_this.encoder_settings['passthrough']){
-                                       var fName = _this.fogg.sourceFilename
-                               }else{
-                                   var oggExt = (_this.isSourceAudio())?'oga':'ogg';
-                    oggExt = (_this.isSourceVideo())?'ogv':oggExt;
-                    oggExt = (_this.isUnknown())?'ogg':oggExt;
-                                   oggName = _this.fogg.sourceFilename.substr(0,
-                                                 _this.fogg.sourceFilename.lastIndexOf('.'));
-                                   var fName = oggName +'.'+ oggExt
-                               }
-                               _this.new_source_cb( _this.fogg.sourceFilename , fName);
+                       try {
+                               this.sourceFileInfo = JSON.parse( firefogg.sourceInfo );
+                       } catch ( e ) {
+                               js_error( 'error could not parse fogg sourceInfo' );
+                               return false;
                        }
                }
+               return this.sourceFileInfo;
        },
-       saveLocalFogg:function(){
-          // Request target location:
-          if(this.fogg){
-                  if(!this.fogg.saveVideoAs() )
-                          return false;
-
-                 // We have set a target now call the encode:
-                 this.doEncode();
-          }
+
+       /**
+        * Clear the cache of the source file info, presumably due to a new file
+        * being selected into this.fogg
+        */
+       clearSourceInfoCache: function() {
+               this.sourceFileInfo = null;
+               this.current_encoder_settings = null;
        },
-       // Simple auto encoder settings just enable passthough if file is not video or > 480 pixles tall
-       autoEncoderSettings:function(){
+
+       /**
+        * Save the result of the transcode as a local file
+        */
+       doLocalEncodeAndSave: function() {
                var _this = this;
-               // Grab the extension:
-               var sf = _this.fogg.sourceFilename;
-               var ext = '';
-               if(     sf.lastIndexOf('.') != -1)
-                       ext = sf.substring( sf.lastIndexOf('.')+1 ).toLowerCase();              
-
-               // Set to passthrough to true by default (images, arbitrary files that we want to send with http chunks)
-               this.encoder_settings['passthrough'] = true;
-
-               // See if we have video or audio:
-               if(  _this.isSourceAudio() || _this.isSourceVideo() )
-                        _this.encoder_settings['passthrough'] = false;         
-
-               // Special case see if we already have ogg video:
-               if( _this.isOggFormat() )
-                       _this.encoder_settings['passthrough'] = true;
-               
-               js_log('base autoEncoderSettings::' + _this.sourceFileInfo.contentType  + ' passthrough:' + _this.encoder_settings['passthrough']);
+               if ( !this.fogg ) {
+                       js_error( 'doLocalEncodeAndSave: no Firefogg object!' );
+                       return false;
+               }
+
+               // Set up the target location
+               // Firefogg shows the "save as" dialog box, and sets the path chosen as 
+               // the destination for a later encode() call.
+               if ( !this.fogg.saveVideoAs() ) {
+                       // User clicked "cancel"
+                       return false;
+               }
+
+               // We have a source file, now do the encode
+               this.doEncode(
+                       function /* onProgress */ ( progress ) {
+                               _this.updateProgress( progress );
+                       },
+                       function /* onDone */ () {
+                               js_log( "done with encoding (no upload) " );
+                               // Set status to 100% for one second
+                               // FIXME: this is either a hack or a waste of time, not sure which
+                               _this.updateProgress( 1 );
+                               setTimeout( function() {
+                                       _this.onLocalEncodeDone();
+                               }
+                       }
+               );
        },
-       isUnknown:function(){
-               return (this.sourceFileInfo.contentType.indexOf("unknown") != -1);
+
+       /**
+        * This is called when a local encode operation has completed. It updates the UI.
+        */
+       onLocalEncodeDone() {
+               var _this = this;
+               _this.updateProgressWin( gM( 'fogg-encoding-done' ),
+                       gM( 'fogg-encoding-done' ) + '<br>' +
+                       //show the video at full resolution upto 720px wide
+                       '<video controls="true" style="margin:auto" id="fogg_final_vid" src="' +
+                               _this.fogg.previewUrl + '"></video>'
+               );
+               //load the video and set a callback:
+               var v = $j( '#fogg_final_vid' ).get( 0 );
+               function resizeVid() {
+                       var v = $j( '#fogg_final_vid' ).get(0);
+                       if ( v.videoWidth > 720 ) {
+                               var vW = 720;
+                               var vH = 720 * v.videoHeight / v.videoWidth;
+                       } else {
+                               var vW = v.videoWidth;
+                               var vH = v.videoHeight;
+                       }
+                       //reize the video:
+                       $j( v ).css({
+                               'width': vW,
+                               'height': vH
+                       });
+                       //if large video resize the dialog box:
+                       if( vW + 5 > 400 ) {
+                               //also resize the dialog box
+                               $j( '#upProgressDialog' ).dialog( 'option', 'width', vW + 20 );
+                               $j( '#upProgressDialog' ).dialog( 'option', 'height', vH + 120 );
+
+                               //also position the dialog container
+                               $j( '#upProgressDialog') .dialog( 'option', 'position', 'center' );
+                       }
+               }
+               v.removeEventListener( "loadedmetadata", resizeVid, true );
+               v.addEventListener( "loadedmetadata", resizeVid, true );
+               v.load();
        },
-       isSourceAudio:function(){
-          return (this.sourceFileInfo.contentType.indexOf("audio/") != -1);
+
+       /**
+        * Get the appropriate encoder settings for the current Firefogg object, 
+        * into which a video has already been selected.
+        */
+       getEncoderSettings function() {
+               if ( this.current_encoder_settings == null ) {
+                       // Clone the default settings
+                       var defaults = function () {};
+                       var defaults.prototype = this.default_encoder_settings;
+                       var settings = new defaults();
+
+                       // Grab the extension
+                       var sf = this.fogg.sourceFilename;
+                       if ( !sf ) {
+                               js_error( 'getEncoderSettings(): No Firefogg source filename is available!' );
+                               return false;
+                       }
+                       var ext = '';
+                       if ( sf.lastIndexOf('.') != -1 )
+                               ext = sf.substring( sf.lastIndexOf( '.' ) + 1 ).toLowerCase();
+
+                       // Determine passthrough mode
+                       if ( this.isOggFormat() ) {
+                               // Already Ogg, no need to encode
+                               settings['passthrough'] = true;
+                       } else if ( this.isSourceAudio() || this.isSourceVideo() ) {
+                               // OK to encode
+                               settings['passthrough'] = false;
+                       } else {
+                               // Not audio or video, can't encode
+                               settings['passthrough'] = true;
+                       }
+
+                       js_log( 'base setupAutoEncoder::' + this.getSourceFileInfo().contentType  +
+                               ' passthrough:' + settings['passthrough'] );
+                       this.current_encoder_settings = settings;
+               }
+               return this.current_encoder_settings;
        },
-       isSourceVideo:function(){
-           return (this.sourceFileInfo.contentType.indexOf("video/") != -1);
+
+       isUnknown: function() {
+               return ( this.getSourceFileInfo().contentType.indexOf("unknown") != -1 );
+       },
+
+       isSourceAudio: function() {
+               return ( this.getSourceFileInfo().contentType.indexOf("audio/") != -1 );
        },
-       isOggFormat:function(){
-          return ( this.sourceFileInfo.contentType.indexOf("video/ogg") != -1 ||
-                       this.sourceFileInfo.contentType.indexOf("application/ogg") != -1   );
+
+       isSourceVideo: function() {
+               return ( this.getSourceFileInfo().contentType.indexOf("video/") != -1 );
+       },
+
+       isOggFormat: function() {
+               var contentType = this.getSourceFileInfo().contentType;
+               return ( contentType.indexOf("video/ogg") != -1 
+                       || contentType.indexOf("application/ogg") != -1 );
        },
-       getProgressTitle:function(){
-               js_log("fogg:getProgressTitle f:" + this.fogg_enabled  + ' rw:' + this.form_rewrite);
-               // Return the parent if we don't have fogg turned on:
-               if(! this.fogg_enabled || !this.firefogg_form_action )
+
+       /**
+        * Get the default title of the progress window
+        */
+       getProgressTitle: function() {
+               js_log( "fogg:getProgressTitle f:" +  ( this.getFirefogg() ? 'on' : 'off' ) + 
+                       ' mode:' + this.form_type );
+               // Return the parent's title if we don't have Firefogg turned on
+               if ( !this.getFirefogg() || !this.firefogg_form_action ) {
                        return this.pe_getProgressTitle();
-               if( !this.form_rewrite )
-                 return gM('fogg-transcoding');
-               // Else return our upload+transcode msg:
-               return gM('mwe-upload-transcode-in-progress');
+               } else if ( this.form_type == 'local' ) {
+                       return gM( 'fogg-transcoding' );
+               } else {
+                       return gM( 'mwe-upload-transcode-in-progress' );
+               }
        },
-       doUploadSwitch:function(){
-               var _this = this;               
-               js_log("firefogg: doUploadSwitch:: " + this.fogg_enabled + ' up mode:' +  _this.upload_mode);
-               // Make sure firefogg is enabled otherwise do parent UploadSwich:
-               if( !this.fogg_enabled || !this.firefogg_form_action )
-                       return _this.pe_doUploadSwitch();
-
-               // Check what mode to use firefogg in:
-               if( _this.upload_mode == 'post' ){
-                       _this.doEncode();
-               }else if( _this.upload_mode == 'api' ){ //if api mode and chunks supported do chunkUpload
+
+       /**
+        * Do an upload, with the mode given by this.upload_mode
+        */
+       doUpload: function() {
+               var _this = this;
+               js_log( "firefogg: doUpload:: " + 
+                       ( this.getFirefogg() ? 'on' : 'off' ) + 
+                       ' up mode:' + _this.upload_mode );
+
+               // If Firefogg is disabled, just invoke the parent method
+               if( !this.getFirefogg() || !this.firefogg_form_action ) {
+                       _this.pe_doUpload();
+                       return;
+               }
+
+               if ( _this.upload_mode == 'post' ) {
+                       // Encode and then do a post upload
+                       _this.doEncode(
+                               function /* onProgress */ ( progress ) {
+                                       _this.updateProgress( progress );
+                               },
+                               function /* onDone */ () {
+                                       js_log( 'done with encoding do POST upload:' + _this.editForm.action );
+                                       // ignore warnings & set source type
+                                       //_this.formData[ 'wpIgnoreWarning' ]='true';
+                                       _this.formData['wpSourceType'] = 'upload';
+                                       _this.formData['action'] = 'submit';
+                                       // wpUploadFile is set by firefogg
+                                       delete _this.formData['file'];
+
+                                       _this.fogg.post( _this.editForm.action, 'wpUploadFile', 
+                                               JSON.stringify( _this.formData ) );
+                                       _this.doUploadStatus();
+                               }
+                       );
+               } else if ( _this.upload_mode == 'api' ) {
+                       // We have the API so we can do a chunk upload
                        _this.doChunkUpload();
-               }else{
+               } else {
                        js_error( 'Error: unrecongized upload mode: ' + _this.upload_mode );
                }
        },
+
        /**
-       * doChunkUpload
-       * does both uploading and encoding at the same time and uploads one meg chunks
-       */
-       doChunkUpload : function(){
-               js_log('firefogg::doChunkUpload');
+        * Do both uploading and encoding at the same time. Uploads 1MB chunks as 
+        * they become ready.
+        */
+       doChunkUpload : function() {
+               js_log( 'firefogg::doChunkUpload' );
                var _this = this;
                _this.action_done = false;
-               
-               // File extension should already be ogg but since its user editable,
-               // (should not be needed for passthrough mode)
-               var sf = _this.formData['filename'];
-               var ext = '';
-               if(     sf.lastIndexOf('.') != -1){
-                       ext = sf.substring( sf.lastIndexOf('.') ).toLowerCase();
-               }
-               if( !_this.encoder_settings['passthrough'] && $j.inArray(ext.substr(1), _this.ogg_extensions) == -1 ){
-                       var extreg = new RegExp(ext + '$', 'i');
-                       _this.formData['filename'] = sf.replace(extreg, '.ogg');
-               }
-               // Add chunk response hook to build the resultURL when uploading chunks
-
-               // Check for editToken:
-               if(!this.etoken){
-                       js_log('missing token try ' + _this.formData['token']);
-                       if( _this.formData['token']){
-                               _this.etoken = _this.formData['token'];
-                               _this.doChunkWithFormData();
-                       }else{
-                               get_mw_token(
-                                       'File:'+ _this.formData['filename'],
-                                       _this.api_url,
-                                       function( eToken ){
-                                               if( !eToken || eToken == '+\\' ){
-                                                       _this.updateProgressWin( gM('fogg-badtoken'), gM('fogg-badtoken') );
-                                                       return false;
-                                               }
-                                               _this.etoken = eToken;
-                                               _this.doChunkWithFormData();
-                                       }
-                               );
+
+               if ( !_this.getEncoderSettings()['passthrough'] ) {
+                       // We are transcoding to Ogg. Fix the destination extension, it 
+                       // must be ogg/ogv/oga.
+                       var fileName = _this.formData['filename'];
+                       var ext = '';
+                       var dotPos = fileName.lastIndexOf( '.' );
+                       if ( dotPos != -1 ) {
+                               ext = fileName.substring( dotPos ).toLowerCase();
                        }
-               }else{
-                       js_log('we already have token: ' + this.etoken);
-                       _this.doChunkWithFormData();
+                       if ( $j.inArray( ext.substr( 1 ), _this.ogg_extensions ) == -1  ) {
+                               _this.formData['filename'] = fileName.substr(
+                                       0, 
+
+
+                               var extreg = new RegExp( ext + '$', 'i' );
+                               _this.formData['filename'] = fileName.replace( extreg, '.ogg' );
+                       }
+               }
+
+               // Get the edit token from formData if it's not set already
+               if ( !_this.editToken && _this.formData['token'] ) {
+                       _this.editToken = _this.formData['token'];
                }
+
+               if( _this.editToken ) {
+                       js_log( 'we already have an edit token: ' + _this.editToken );
+                       _this.doChunkUploadWithFormData();
+                       return;
+               }
+
+               // No edit token. Fetch it asynchronously and then do the upload.
+               get_mw_token(
+                       'File:'+ _this.formData['filename'],
+                       _this.api_url,
+                       function( editToken ) {
+                               if( !editToken || editToken == '+\\' ) {
+                                       _this.updateProgressWin( gM( 'fogg-badtoken' ), gM( 'fogg-badtoken' ) );
+                                       return false;
+                               }
+                               _this.editToken = editToken;
+                               _this.doChunkUploadWithFormData();
+                       }
+               );
        },
-       doChunkWithFormData:function(){
+
+       /**
+        * Internal function called from doChunkUpload() when the edit token is available
+        */
+       doChunkUploadWithFormData: function() {
                var _this = this;
-               js_log("firefogg::doChunkWithFormData"  + _this.etoken);
-               // Build the api url:
-               var aReq ={
+               js_log( "firefogg::doChunkUploadWithFormData"  + _this.editToken );
+               // Build the API URL
+               var aReq = {
                        'action': 'upload',
                        'format': 'json',
                        'filename': _this.formData['filename'],
@@ -620,223 +897,187 @@ mvFirefogg.prototype = { //extends mvBaseUploadInterface
                        'enablechunks': 'true'
                };
 
-               if( _this.etoken )
-                       aReq['token'] = this.etoken;
+               if ( _this.editToken )
+                       aReq['token'] = this.editToken;
 
-               if( _this.formData['watch'] )
-                       aReq['watch'] =  _this.formData['watch'];
+               if ( _this.formData['watch'] )
+                       aReq['watch'] = _this.formData['watch'];
 
-               if _this.formData['ignorewarnings'] )
+               if ( _this.formData['ignorewarnings'] )
                        aReq['ignorewarnings'] = _this.formData['ignorewarnings'];
 
-               js_log('do fogg upload/encode call: '+ _this.api_url + ' :: ' + JSON.stringify( aReq ) );
-               js_log('foggEncode: '+ JSON.stringify( _this.encoder_settings ) );
-               _this.fogg.upload( JSON.stringify( _this.encoder_settings ),  _this.api_url ,  JSON.stringify( aReq ) );
+               var encoderSettings = this.getEncoderSettings();
+               js_log( 'do fogg upload/encode call: ' + _this.api_url + ' :: ' + JSON.stringify( aReq ) );
+               js_log( 'foggEncode: ' + JSON.stringify( encoderSettings ) );
+               _this.fogg.upload( JSON.stringify( encoderSettings ), _this.api_url, 
+                       JSON.stringify( aReq ) );
 
-               // Update upload status:
+               // Start polling the upload status
                _this.doUploadStatus();
        },
-       // doEncode and monitor progress:
-       doEncode : function(){
+
+       /**
+        * Encode the video and monitor progress.
+        *
+        * Calls progressCallback() regularly with a number between 0 and 1 indicating progress.
+        * Calls doneCallback() when the encode is finished.
+        *
+        * Asynchronous, returns immediately.
+        */
+       doEncode : function( progressCallback, doneCallback ) {
                var _this = this;
                _this.action_done = false;
-               _this.dispProgressOverlay();
-               js_log('doEncode: with: ' +  JSON.stringify( _this.encoder_settings ) );
-               _this.fogg.encode( JSON.stringify( _this.encoder_settings ) );
+               _this.displayProgressOverlay();
+               var encoderSettings = this.getEncoderSettings();
+               js_log( 'doEncode: with: ' +  JSON.stringify( encoderSettings ) );
+               _this.fogg.encode( JSON.stringify( encoderSettings ) );
 
-                // Show transcode status:
-               $j('#up-status-state').html( gM('mwe-upload-transcoded-status') );
+               //show transcode status:
+               $j( '#up-status-state' ).html( gM( 'mwe-upload-transcoded-status' ) );
 
-               // Setup a local function for timed callback:
+               //setup a local function for timed callback:
                var encodingStatus = function() {
                        var status = _this.fogg.status();
 
-                       if( _this.show_preview == true && _this.fogg.state == 'encoding'){
-                               _this.doRenderPreview();
+                       if ( _this.show_preview == true && _this.fogg.state == 'encoding' ) {
+                               _this.renderPreview();
                        }
 
-                       // Update progress bar
-                       _this.updateProgress( _this.fogg.progress() );
+                       // Update progress
+                       progressCallback( _this.fogg.progress() );
 
-                       // Loop to get new status if still encoding
-                       if( _this.fogg.state == 'encoding' ) {
-                               setTimeout(encodingStatus, 500);
-                       }else if ( _this.fogg.state == 'encoding done' ) { //encoding done, state can also be 'encoding failed
-                               _this.encodeDone();
-                       }else if(_this.fogg.state == 'encoding fail'){
+                       //loop to get new status if still encoding
+                       if ( _this.fogg.state == 'encoding' ) {
+                               setTimeout( encodingStatus, 500 );
+                       } else if ( _this.fogg.state == 'encoding done' ) {
+                               _this.action_done = true;
+                               progressCallback( 1 );
+                               doneCallback();
+                       } else if ( _this.fogg.state == 'encoding fail' ) {
                                //@@todo error handling:
-                               js_error('encoding failed');
+                               js_error( 'encoding failed' );
                        }
                }
                encodingStatus();
        },
-       encodeDone:function(){
-               var _this = this;
-               js_log('::encodeDone::');
-               _this.action_done = true;
-               
-               // Send to the post url:
-               if( _this.form_rewrite && _this.upload_mode == 'post' ){
-                       js_log('done with encoding do POST upload:' + _this.editForm.action);
-                       // ignore warnings & set source type
-                       //_this.formData[ 'wpIgnoreWarning' ]='true';
-                       _this.formData[ 'wpSourceType' ] = 'upload';
-                       _this.formData[ 'action' ]               = 'submit';
-                       //wpUploadFile is set by firefogg
-                       delete _this.formData[ 'file' ];
-
-                       _this.fogg.post( _this.editForm.action, 'wpUploadFile', JSON.stringify( _this.formData ) );
-                       // Update upload status:
-                       _this.doUploadStatus();
-               }else{
-                       js_log("done with encoding (no upload) ");                                              
-                       // Set status to 100% for one second:
-                       _this.updateProgress( 1 );                      
-                       setTimeout(function(){
-                               _this.updateProgressWin(gM('fogg-encoding-done'),       
-                                       gM('fogg-encoding-done') + '<br>' +                             
-                                       // Show the video at full resolution up-to 720px wide
-                                       '<video controls="true" style="margin:auto" id="fogg_final_vid" src="' + 
-                                                _this.fogg.previewUrl + '"></video>'                                   
-                               );
-                               //load the video and set a callback: 
-                               var v = $j('#fogg_final_vid').get(0);
-                               function resizeVid(){
-                                       var v = $j('#fogg_final_vid').get(0);                                   
-                                       if( v.videoWidth > 720 ){
-                                               var vW = 720;
-                                               var vH = 720 * (v.videoHeight/v.videoWidth)                                                                                                     
-                                       }else{
-                                               var vW = v.videoWidth;
-                                               var vH = v.videoHeight;                                                                                         
-                                       }
-                                       // Resize the video:
-                                       $j(v).css({
-                                               'width' : vW,
-                                               'height': vH                                    
-                                       });
-                                       // If large video resize the dialog box:
-                                       if( vW + 5 > 400){ 
-                                               //also resize the dialog box
-                                               $j('#upProgressDialog').dialog('option', 'width', vW + 20);     
-                                               $j('#upProgressDialog').dialog('option', 'height',      vH + 120);                              
-                                               
-                                               //also position the dialog container                            
-                                               $j('#upProgressDialog').dialog('option', 'position', 'center');
-                                       }
-                               }                                                                
-                               v.removeEventListener("loadedmetadata", resizeVid, true);
-                               v.addEventListener("loadedmetadata", resizeVid, true);
-                               v.load();                               
-                       }, 1000);
-               }
-       },
-       doUploadStatus:function() {
+
+       /**
+        * Poll the upload progress and update the UI regularly until the upload is complete. 
+        *
+        * Asynchronous, returns immediately.
+        */
+       doUploadStatus: function() {
                var _this = this;
-               $j( '#up-status-state' ).html( gM('mwe-uploaded-status')  );
+               $j( '#up-status-state' ).html( gM( 'mwe-uploaded-status' ) );
 
                _this.oldResponseText = '';
-               // Setup a local function for timed callback:
-               var uploadStatus = function(){
-                       // Get the response text:
-                       var response_text =  _this.fogg.responseText;
-                       if(!response_text){
-                                  try{
-                                          var pstatus = JSON.parse( _this.fogg.uploadstatus() );
-                                          response_text = pstatus["responseText"];
-                                  }catch(e){
-                                          js_log("could not parse uploadstatus / could not get responseText");
-                                  }
+
+               // Create a local function for timed callback
+               var uploadStatus = function() {
+                       var response_text = _this.fogg.responseText;
+                       if ( !response_text ) {
+                               try {
+                                       var pstatus = JSON.parse( _this.fogg.uploadstatus() );
+                                       response_text = pstatus["responseText"];
+                               } catch( e ) {
+                                       js_log( "could not parse uploadstatus / could not get responseText" );
+                               }
                        }
 
-                       if( _this.oldResponseText != response_text){
-                               js_log('new result text:' + response_text + ' state:' + _this.fogg.state);
+                       if ( _this.oldResponseText != response_text ) {
+                               js_log( 'new result text:' + response_text + ' state:' + _this.fogg.state );
                                _this.oldResponseText = response_text;
-                               // Try and parse the response text and check for errors
-                               try{
+                               // Parse the response text and check for errors
+                               try {
                                        var apiResult = JSON.parse( response_text );
-                               }catch(e){
-                                       js_log("could not parse response_text::" + response_text + ' ...for now try with eval...');
-                                       try{
+                               } catch( e ) {
+                                       js_log( "could not parse response_text::" + response_text + 
+                                               ' ...for now try with eval...' );
+                                       try {
                                                var apiResult = eval( response_text );
-                                       }catch(e){
+                                       } catch( e ) {
                                                var apiResult = null;
-                                       }                                       
+                                       }
                                }
-                               if(apiResult && _this.apiUpdateErrorCheck( apiResult ) === false){
-                                       // Stop status update we have an error
+                               if ( apiResult && !_this.isApiSuccess( apiResult ) ) {
+                                       // Show the error and stop the upload
+                                       _this.showApiError( apiResult );
                                        _this.action_done = true;
                                        _this.fogg.cancel();
                                        return false;
                                }
                        }
-                       if( _this.show_preview == true ){
-                               if(  _this.fogg.state == 'encoding' ){
-                                       _this.doRenderPreview();
+                       if ( _this.show_preview == true ) {
+                               if ( _this.fogg.state == 'encoding' ) {
+                                       _this.renderPreview();
                                }
                        }
-                       
-                       // Update progress bar
+
+                       // Update the progress bar
                        _this.updateProgress( _this.fogg.progress() );
 
-                       // Loop to get new status if still uploading (could also be encoding if we are in chunk upload mode)
-                       if( _this.fogg.state == 'encoding' || _this.fogg.state == 'uploading') {
-                               setTimeout(uploadStatus, 100);
-                       }// Check upload state
-                       else if( _this.fogg.state == 'upload done' ||
-                                                _this.fogg.state == 'done' ||
-                                                _this.fogg.state == 'encoding done' ) {
-                                  // If in "post" upload mode read the html response (should be deprecated):
-                                  if( _this.upload_mode == 'api' ){
-                                          if( apiResult && apiResult.resultUrl ){
-                                                       var buttons ={};
-                                                       buttons[gM('mwe-go-to-resource')] =  function(){
-                                                               window.location = apiResult.resultUrl;
-                                                       }
-                                                       var go_to_url_txt = gM('mwe-go-to-resource');
-                                                       if( typeof _this.done_upload_cb == 'function' ){
-                                                               // If done action return 'true'
-                                                               if( _this.done_upload_cb( _this.formData ) ){
-                                                                       // Update status
-                                                                       _this.updateProgressWin( gM('mwe-successfulupload'),  gM( 'mwe-upload_done', apiResult.resultUrl),buttons);
-                                                               }else{
-                                                                       // If done action returns 'false' //close progress window
-                                                                       this.action_done = true;
-                                                               $j('#upProgressDialog').empty().dialog('close');
-                                                               }
-                                                       }else{
-                                                               // Update status (without done_upload_cb)
-                                                               _this.updateProgressWin( gM('mwe-successfulupload'),  gM( 'mwe-upload_done', apiResult.resultUrl),buttons);
-                                                       }
-                                          }else{
-                                                  // Done state with error? ..not really possible given how firefogg works
-                                                  js_log(" Upload done in chunks mode, but no resultUrl!");
-                                          }
-                                  }else{
-                                          js_log("Error:: not supported upload mode" +  _this.upload_mode);
-                                  }
-                       }else{
-                               // Upload error:
-                               js_log('Error:firefogg upload error: ' + _this.fogg.state );
-                  }
-          }
-          uploadStatus();
+                       // If we're still uploading or encoding, continue to poll the status
+                       if ( _this.fogg.state == 'encoding' || _this.fogg.state == 'uploading' ) {
+                               setTimeout( uploadStatus, 100 );
+                               return;
+                       }
+
+                       // Upload done?
+                       if ( -1 == $j.inArray( _this.fogg.state, [ 'upload done', 'done', 'encoding done' ] ) ) {
+                               js_log( 'Error:firefogg upload error: ' + _this.fogg.state );
+                               return;
+                       }
+
+                       if ( _this.upload_mode == 'api' ) {
+                               if ( apiResult && apiResult.resultUrl ) {
+                                       var buttons = {};
+                                       buttons[ gM( 'mwe-go-to-resource' ) ] =  function() {
+                                               window.location = apiResult.resultUrl;
+                                       }
+                                       var go_to_url_txt = gM( 'mwe-go-to-resource' );
+                                       var showMessage = true;
+                                       if ( typeof _this.done_upload_cb == 'function' ) {
+                                               // Call the callback
+                                               // It will return false if it doesn't want us to show our own "done" message
+                                               showMessage = _this.done_upload_cb( _this.formData );
+                                       }
+                                       if ( showMessage ) {
+                                               _this.updateProgressWin( gM( 'mwe-successfulupload' ), 
+                                                       gM( 'mwe-upload_done', apiResult.resultUrl ), buttons );
+                                       } else {
+                                               this.action_done = true;
+                                               $j( '#upProgressDialog' ).empty().dialog( 'close' );
+                                       }
+                               } else {
+                                       // Done state with error? Not really possible given how firefogg works...
+                                       js_log( " Upload done in chunks mode, but no resultUrl!" );
+                               }
+                       } else {
+                               js_log( "Error:: not supported upload mode" +  _this.upload_mode );
+                       }
+               }
+               uploadStatus();
        },
-       cancel_action:function( dlElm ){
-               if(!this.fogg_enabled){
+
+       /**
+        * This is the cancel button handler, referenced by getCancelButton() in the parent.
+        */
+       onCancel: function( dlElm ) {
+               if ( !this.have_firefogg ) {
                        return this.pe_cancel_action();
                }
-               js_log('firefogg:cancel')
-               if( confirm( gM('mwe-cancel-confim') )){
-                   if(navigator.oscpu && navigator.oscpu.search('Win') >= 0){
-                        alert( 'sorry we do not yet support cancel on windows' );
-                   }else{
-                       this.action_done = true;
-                       this.fogg.cancel();
-                       $j(dlElm).empty().dialog('close');                     
-                   }
-               }
-               // Dont' follow the link:
-               return false;
+               js_log( 'firefogg:cancel' )
+               if ( confirm( gM( 'mwe-cancel-confim' ) ) ) {
+                       // FIXME: sillyness
+                       if ( navigator.oscpu && navigator.oscpu.search( 'Win' ) >= 0 ) {
+                               alert( 'sorry we do not yet support cancel on windows' );
+                       } else {
+                               this.action_done = true;
+                               this.fogg.cancel();
+                               $j( dlElm ).empty().dialog( 'close' );
+                       }
+               }
+               // Don't follow the # link:
+               return false;
        }
 };
index 9d2a646..6963613 100644 (file)
@@ -141,11 +141,11 @@ $messages['en'] = array(
        'fogg-select_new_file' => 'Select new file',
        'fogg-select_url' => 'Select URL',
        'fogg-save_local_file' => 'Save Ogg',
-       'fogg-check_for_fogg' => 'Checking for Firefogg...',
+       'fogg-check_for_firefogg' => 'Checking for Firefogg...',
        'fogg-installed' => 'Firefogg is installed',
-       'fogg-for_improved_uplods' => 'For improved uploads:',
+       'fogg-for_improved_uploads' => 'For improved uploads:',
        'fogg-please_install' => '<a href="$1">Install Firefogg</a>. More <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">about Firefogg</a>.',
-       '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>',
+       'fogg-use_latest_firefox' => '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>',
        'fogg-passthrough_mode' => 'Your selected file is already Ogg or not a video file',
        'fogg-transcoding' => 'Encoding video to Ogg...',
        'fogg-encoding-done' => 'Encoding complete',
@@ -594,7 +594,7 @@ $messages['ar'] = array(
        'fogg-select_new_file' => 'اختر ملفًا جديدًا',
        'fogg-select_url' => 'اختر مسارًا',
        'fogg-save_local_file' => 'احفظ Ogg',
-       'fogg-check_for_fogg' => 'يلتمس Firefogg...',
+       'fogg-check_for_firefogg' => 'يلتمس Firefogg...',
        'fogg-installed' => 'Firefogg مُثبّت',
        'fogg-transcoding' => 'ترميز الفيديو إلى Ogg',
        'fogg-encoding-done' => 'انتهى الترميز',
@@ -775,11 +775,11 @@ $messages['be-tarask'] = array(
        'fogg-select_new_file' => 'Выберыце новы файл',
        'fogg-select_url' => 'Выберыце URL-адрас',
        'fogg-save_local_file' => 'Захаваць Ogg',
-       'fogg-check_for_fogg' => 'Праверка наяўнасьці Firefogg …',
+       'fogg-check_for_firefogg' => 'Праверка наяўнасьці Firefogg …',
        'fogg-installed' => 'Firefogg усталяваны',
-       'fogg-for_improved_uplods' => 'Для палепшаных загрузак:',
+       'fogg-for_improved_uploads' => 'Для палепшаных загрузак:',
        'fogg-please_install' => '<a href="$1">Усталяваць Firefogg</a>. Болей <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">пра Firefogg</a>',
-       'fogg-use_latest_fox' => 'Калі ласка, спачатку ўсталюйце <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (ці больш позьнюю вэрсію). <i>Потым зноў наведайце гэтую старонку і ўсталюйце пашырэньне <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Калі ласка, спачатку ўсталюйце <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (ці больш позьнюю вэрсію). <i>Потым зноў наведайце гэтую старонку і ўсталюйце пашырэньне <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => 'Выбраны Вамі файл ужо ў фармаце Ogg альбо не зьяўляецца відэа-файлам',
        'fogg-transcoding' => 'Перакадыроўка відэа ў фармат Ogg',
        'fogg-encoding-done' => 'Перакадыроўка скончаная',
@@ -1165,7 +1165,7 @@ $messages['bs'] = array(
        'fogg-select_new_file' => 'Odaberi novu datoteku',
        'fogg-select_url' => 'Odaberi URL',
        'fogg-save_local_file' => 'Sačuvaj Ogg',
-       'fogg-check_for_fogg' => 'Provjera za Firefogg ...',
+       'fogg-check_for_firefogg' => 'Provjera za Firefogg ...',
        'fogg-installed' => 'Firefogg je instaliran',
        'fogg-passthrough_mode' => 'Vaša odabrana datoteka je već Ogg ili nije video datoteka',
        'fogg-badtoken' => 'Token nije valjan',
@@ -1264,11 +1264,11 @@ $messages['cs'] = array(
        'mwe-loading_txt' => 'Načítá se …',
        'mwe-loading-add-media-wiz' => 'Načítá se průvodce pro přidání souboru',
        'mwe-cancel' => 'Storno',
-       'fogg-check_for_fogg' => 'Ověřuje se Firefogg…',
+       'fogg-check_for_firefogg' => 'Ověřuje se Firefogg…',
        'fogg-installed' => 'Firefogg je nainstalován',
-       'fogg-for_improved_uplods' => 'Pro vylepšené načítání:',
+       'fogg-for_improved_uploads' => 'Pro vylepšené načítání:',
        'fogg-please_install' => '<a href="$1">Nainstalujte si Firefogg.</a> <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg/cs">Další informace o&nbsp;Firefoggu</a>',
-       'fogg-use_latest_fox' => 'Nejprve si nainstalujte <a href="http://www.mozilla-europe.org/cs/firefox/?from=firefogg">Firefox 3.5</a> (nebo novější). <i>Poté se vraťte na tuto stránku, abyste si mohli nainstalovat rozšíření <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Nejprve si nainstalujte <a href="http://www.mozilla-europe.org/cs/firefox/?from=firefogg">Firefox 3.5</a> (nebo novější). <i>Poté se vraťte na tuto stránku, abyste si mohli nainstalovat rozšíření <b>Firefogg</b>.</i>',
        'mwe-add_media_wizard' => 'Průvodce pro přidání souboru',
        'mwe-media_search' => 'Hledání multimédií',
        'rsd_box_layout' => 'Ikony',
@@ -1437,11 +1437,11 @@ $messages['de'] = array(
        'fogg-select_new_file' => 'Wähle eine neue Datei',
        'fogg-select_url' => 'Wähle eine URL',
        'fogg-save_local_file' => 'Ogg speichern',
-       'fogg-check_for_fogg' => 'Suche nach Firefogg …',
+       'fogg-check_for_firefogg' => 'Suche nach Firefogg …',
        'fogg-installed' => 'Firefogg ist installiert',
-       'fogg-for_improved_uplods' => 'Für verbessertes Hochladen:',
+       'fogg-for_improved_uploads' => 'Für verbessertes Hochladen:',
        'fogg-please_install' => '<a href="$1">Installiere Firefogg</a>. Mehr <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">über Firefogg</a>',
-       'fogg-use_latest_fox' => 'Installiere bitte zuerst [http://de.www.mozilla.com/de/ Firefox 3.5] (oder eine spätere Version).
+       'fogg-use_latest_firefox' => 'Installiere bitte zuerst [http://de.www.mozilla.com/de/ Firefox 3.5] (oder eine spätere Version).
 <i>Besuche danach die Seite neu, um die <b>Firefogg</b>-Erweiterung zu installieren.</i>',
        'fogg-passthrough_mode' => 'Deine ausgewählte Datei ist bereits Ogg oder keine Videodatei',
        'fogg-transcoding' => 'Codiere Video nach Ogg',
@@ -1735,11 +1735,11 @@ $messages['diq'] = array(
        'fogg-select_new_file' => 'dosyaya neweyi bıweçin',
        'fogg-select_url' => 'URL bıweçin',
        'fogg-save_local_file' => 'Ogg qeyd bıker',
-       'fogg-check_for_fogg' => 'Firefogg kontrol beno...',
+       'fogg-check_for_firefogg' => 'Firefogg kontrol beno...',
        'fogg-installed' => 'Firefogg bar bı',
-       'fogg-for_improved_uplods' => 'qey barkerdışê dewlemend biyayeyani:',
+       'fogg-for_improved_uploads' => 'qey barkerdışê dewlemend biyayeyani:',
        'fogg-please_install' => '<a href="$1">Firefogg bar ker</a>. <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">derheqê firefoggi de</a>',
-       'fogg-use_latest_fox' => 'kerem kerê ewwil <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a>\'i barkerê. <i>u hema parçeyê <b>Firefogg</b> i bar kerê, qey barkerdışi no pel ziyaret bıkerê</i>',
+       'fogg-use_latest_firefox' => 'kerem kerê ewwil <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a>\'i barkerê. <i>u hema parçeyê <b>Firefogg</b> i bar kerê, qey barkerdışi no pel ziyaret bıkerê</i>',
        'fogg-passthrough_mode' => 'dosyaya ke şıma weçina ca ra yew dosyaya Oggi ya zi videoyi niyo',
        'fogg-transcoding' => 'Video Ogg ra kod beno',
        'fogg-encoding-done' => 'kodkerdış temam bı',
@@ -2045,11 +2045,11 @@ $messages['dsb'] = array(
        'fogg-select_new_file' => 'Nowu dataju wubraś',
        'fogg-select_url' => 'URL wubraś',
        'fogg-save_local_file' => 'Ogg składowaś',
-       'fogg-check_for_fogg' => 'Za Firefogg pśeglědaś ...',
+       'fogg-check_for_firefogg' => 'Za Firefogg pśeglědaś ...',
        'fogg-installed' => 'Firefogg jo instalěrowany.',
-       'fogg-for_improved_uplods' => 'Za pólěpšone nagraśa:',
+       'fogg-for_improved_uploads' => 'Za pólěpšone nagraśa:',
        'fogg-please_install' => '<a href="$1">Firefogg instalěrowaś</a>. Wjace <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">wó Firefogg</a>',
-       'fogg-use_latest_fox' => 'Pšosym instalěruj njepjerwjej <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (abo wuši). <i>Woglědaj pótom k toś tomu bokoju zasego, aby rozšyrjenje <b>Firefogg</b> instalěrował.</i>',
+       'fogg-use_latest_firefox' => 'Pšosym instalěruj njepjerwjej <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (abo wuši). <i>Woglědaj pótom k toś tomu bokoju zasego, aby rozšyrjenje <b>Firefogg</b> instalěrował.</i>',
        'fogg-passthrough_mode' => 'Twója wubrana dataja jo južo dataja Ogg abo njejo wideojowa dataja',
        'fogg-transcoding' => 'Wideo do Ogg koděrowaś',
        'fogg-encoding-done' => 'Koděrowanje skóńcone',
@@ -2317,7 +2317,7 @@ $messages['el'] = array(
        'fogg-select_url' => 'Επιλογή URL',
        'fogg-save_local_file' => 'Αποθήκευση Οgg',
        'fogg-installed' => 'Ο Firefogg είναι εγκατεστημένος',
-       'fogg-for_improved_uplods' => 'Για βελτιωμένες φορτώσεις:',
+       'fogg-for_improved_uploads' => 'Για βελτιωμένες φορτώσεις:',
        'fogg-transcoding' => 'Κωδικοποίηση βίντεο σε Ogg',
        'fogg-encoding-done' => 'Κωδικοποίηση πλήρης',
        'fogg-badtoken' => 'Το δείγμα δεν είναι έγκυρο',
@@ -2420,7 +2420,7 @@ $messages['eo'] = array(
        'fogg-select_new_file' => 'Elekti novan dosieron',
        'fogg-select_url' => 'Elekti URL-on',
        'fogg-installed' => 'Instalis Firefogg',
-       'fogg-use_latest_fox' => 'Bonvolu antaŭe instali <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox (Fajrvulpo) 3.5</a> (or later). <i>Poste revenu al ĉi tiu paĝo por instali la  kromprogramon <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Bonvolu antaŭe instali <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox (Fajrvulpo) 3.5</a> (or later). <i>Poste revenu al ĉi tiu paĝo por instali la  kromprogramon <b>Firefogg</b>.</i>',
        'fogg-hidepreview' => 'Kaŝi antaŭvidon',
        'fogg-videoQuality-title' => 'Videa kvalito',
        'fogg-starttime-title' => 'Komenca sekundo',
@@ -2545,11 +2545,11 @@ $messages['es'] = array(
        'fogg-select_new_file' => 'Seleccionar nuevo archivo',
        'fogg-select_url' => 'Seleccionar URL',
        'fogg-save_local_file' => 'Grabar Ogg',
-       'fogg-check_for_fogg' => 'Verificando Firefogg ...',
+       'fogg-check_for_firefogg' => 'Verificando Firefogg ...',
        'fogg-installed' => 'Firefogg está instalado',
-       'fogg-for_improved_uplods' => 'Para cargas mejoradas:',
+       'fogg-for_improved_uploads' => 'Para cargas mejoradas:',
        'fogg-please_install' => '<a href="$1">Instalar Firefogg</a>. Más <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">acerca de Firefogg</a>',
-       'fogg-use_latest_fox' => 'Por favor primero instala <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (o posterior). <i>Luego vuelve a visitar esta página para instalar la extensión <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Por favor primero instala <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (o posterior). <i>Luego vuelve a visitar esta página para instalar la extensión <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => 'Tu archivo seleccionado ya es Ogg o no es un archivo de video',
        'fogg-transcoding' => 'Codificando video a Ogg',
        'fogg-encoding-done' => 'Codificación completa',
@@ -2812,9 +2812,9 @@ $messages['fi'] = array(
        'fogg-select_url' => 'Valitse URL',
        'fogg-save_local_file' => 'Tallenna Ogg',
        'fogg-installed' => 'Firefogg on asennettu',
-       'fogg-for_improved_uplods' => 'Parannettua tallentamista varten:',
+       'fogg-for_improved_uploads' => 'Parannettua tallentamista varten:',
        'fogg-please_install' => '<a href="$1">Asenna Firefogg</a> – <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">Tietoja Firefoggista</a>.',
-       'fogg-use_latest_fox' => 'Asenna ensin <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (tai uudempi). <i>Tule sen jälkeen uudelleen tälle sivulle ja asenna <b>Firefogg</b>-laajennus.</i>',
+       'fogg-use_latest_firefox' => 'Asenna ensin <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (tai uudempi). <i>Tule sen jälkeen uudelleen tälle sivulle ja asenna <b>Firefogg</b>-laajennus.</i>',
        'fogg-preview' => 'Videon esikatselu',
        'fogg-hidepreview' => 'Piilota esikatselu',
        'fogg-audioQuality-title' => 'Äänenlaatu',
@@ -2971,11 +2971,11 @@ $messages['fr'] = array(
        'fogg-select_new_file' => 'Sélectionnez un nouveau fichier',
        'fogg-select_url' => 'Sélectionnez une URL',
        'fogg-save_local_file' => 'Sauvegarder au format Ogg',
-       'fogg-check_for_fogg' => 'Vérification de Firefogg ...',
+       'fogg-check_for_firefogg' => 'Vérification de Firefogg ...',
        'fogg-installed' => 'Firefogg est installé',
-       'fogg-for_improved_uplods' => 'Pour des téléversements améliorés :',
+       'fogg-for_improved_uploads' => 'Pour des téléversements améliorés :',
        'fogg-please_install' => '<a href="$1">Installer Firefogg</a>. Plus d\'infos <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">sur Firefogg</a>',
-       'fogg-use_latest_fox' => 'Veuillez d\'abord installer <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (ou plus récent). <i>Puis revenez sur cette page pour installer l\'extension <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Veuillez d\'abord installer <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (ou plus récent). <i>Puis revenez sur cette page pour installer l\'extension <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => "Le fichier que vous avez sélectionné est déjà au format Ogg ou n'est pas un fichier vidéo",
        'fogg-transcoding' => "Encodage d'une vidéo au format Ogg",
        'fogg-encoding-done' => 'Encodage terminé',
@@ -3282,11 +3282,11 @@ $messages['gl'] = array(
        'fogg-select_new_file' => 'Seleccione un ficheiro novo',
        'fogg-select_url' => 'Seleccione un enderezo URL',
        'fogg-save_local_file' => 'Gardar en formato Ogg',
-       'fogg-check_for_fogg' => 'Examinando en busca do Firefogg...',
+       'fogg-check_for_firefogg' => 'Examinando en busca do Firefogg...',
        'fogg-installed' => 'O Firefogg está instalado',
-       'fogg-for_improved_uplods' => 'Para cargas melloradas:',
+       'fogg-for_improved_uploads' => 'Para cargas melloradas:',
        'fogg-please_install' => '<a href="$1">Instalar o Firefogg</a>. Máis información <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">acerca do Firefogg</a>',
-       'fogg-use_latest_fox' => 'Por favor, instale primeiro o <a href="http://gl.www.mozilla.com/gl/">Firefox 3.5</a> (ou superior). <i>Logo diso, volte a esta páxina para instalar a extensión <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Por favor, instale primeiro o <a href="http://gl.www.mozilla.com/gl/">Firefox 3.5</a> (ou superior). <i>Logo diso, volte a esta páxina para instalar a extensión <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => 'O ficheiro que seleccionou xa está en formato Ogg ou non é un ficheiro de vídeo',
        'fogg-transcoding' => 'Codificando o vídeo en formato Ogg',
        'fogg-encoding-done' => 'Codificación completa',
@@ -3605,11 +3605,11 @@ $messages['gsw'] = array(
        'fogg-select_new_file' => 'Neji Datei uuswehle',
        'fogg-select_url' => 'URL uuswehle',
        'fogg-save_local_file' => 'Ogg spychere',
-       'fogg-check_for_fogg' => 'Am Priefe vu Firefogg ...',
+       'fogg-check_for_firefogg' => 'Am Priefe vu Firefogg ...',
        'fogg-installed' => 'Firefogg isch inschtalliert',
-       'fogg-for_improved_uplods' => 'Fir e verbesseret Uffelade:',
+       'fogg-for_improved_uploads' => 'Fir e verbesseret Uffelade:',
        'fogg-please_install' => '<a href="$1">Firefogg inschtalliere</a>. Meh <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">Informatione iber Firefogg</a>',
-       'fogg-use_latest_fox' => 'Bitte ischtallier zerscht <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (oder e nejeri Version). <i>DErno gang wider uf die Syte go d <b>Firefogg</b>-Erwyterig inschtalliere.</i>',
+       'fogg-use_latest_firefox' => 'Bitte ischtallier zerscht <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (oder e nejeri Version). <i>DErno gang wider uf die Syte go d <b>Firefogg</b>-Erwyterig inschtalliere.</i>',
        'fogg-passthrough_mode' => 'D Datei, wu Du uusgwehlt hesch, isch schon im Ogg-Format oder s het kei Video din',
        'fogg-transcoding' => 'Am Umwandle vum Video in s Ogg-Format',
        'fogg-encoding-done' => 'Umwandlig fertig',
@@ -3891,11 +3891,11 @@ $messages['he'] = array(
        'fogg-select_new_file' => 'בחירת קובץ חדש',
        'fogg-select_url' => 'בחירת כתובת',
        'fogg-save_local_file' => 'שמירת ה־Ogg',
-       'fogg-check_for_fogg' => 'מתבצעת בדיקה האם מותקן Firefogg ...',
+       'fogg-check_for_firefogg' => 'מתבצעת בדיקה האם מותקן Firefogg ...',
        'fogg-installed' => 'Firefogg מותקן',
-       'fogg-for_improved_uplods' => 'להעלאות משופרות:',
+       'fogg-for_improved_uploads' => 'להעלאות משופרות:',
        'fogg-please_install' => '<a href="$1">להתקנת Firefogg</a>. עוד <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">אודות Firefogg</a>',
-       'fogg-use_latest_fox' => 'ראשית יש להתקין את <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (ומעלה). <b>לאחר מכן יש לבקר בדף זה שוב כדי להתקין את ההרחבה <i>Firefogg</i>.</b>',
+       'fogg-use_latest_firefox' => 'ראשית יש להתקין את <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (ומעלה). <b>לאחר מכן יש לבקר בדף זה שוב כדי להתקין את ההרחבה <i>Firefogg</i>.</b>',
        'fogg-passthrough_mode' => 'הקובץ שנבחר הוא כבר קובץ Ogg או שאינו קובץ וידאו',
        'fogg-transcoding' => 'קידוד הווידאו ל־Ogg',
        'fogg-encoding-done' => 'הקידוד הושלם',
@@ -4080,11 +4080,11 @@ $messages['hsb'] = array(
        'fogg-select_new_file' => 'Nowu dataju wubrać',
        'fogg-select_url' => 'URL wubrać',
        'fogg-save_local_file' => 'Ogg składować',
-       'fogg-check_for_fogg' => 'Pruwowanje za Firefogg ...',
+       'fogg-check_for_firefogg' => 'Pruwowanje za Firefogg ...',
        'fogg-installed' => 'Firefogg so instaluje',
-       'fogg-for_improved_uplods' => 'Za polěpšene nahraća:',
+       'fogg-for_improved_uploads' => 'Za polěpšene nahraća:',
        'fogg-please_install' => '<a href="$1">Firefogg instalować</a>. Wjace <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">wo Firefoggu</a>',
-       'fogg-use_latest_fox' => 'Prošu instalu najprjedy <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (abo wyše). <i>Potom wopytaj tutu strona znowa, zo by rozšěrjenje <b>Firefogg</b> instalował.</i>',
+       'fogg-use_latest_firefox' => 'Prošu instalu najprjedy <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (abo wyše). <i>Potom wopytaj tutu strona znowa, zo by rozšěrjenje <b>Firefogg</b> instalował.</i>',
        'fogg-passthrough_mode' => 'Twoja wubrana dataja je hižo Ogg abo njeje widejowa dataja',
        'fogg-transcoding' => 'Kodowanje wideja do Ogg',
        'fogg-encoding-done' => 'Kodowanje hotowe',
@@ -4393,11 +4393,11 @@ $messages['hu'] = array(
        'fogg-select_new_file' => 'Új fájl kiválasztása',
        'fogg-select_url' => 'URL kiválasztása',
        'fogg-save_local_file' => 'Ogg mentése',
-       'fogg-check_for_fogg' => 'Firefogg keresése…',
+       'fogg-check_for_firefogg' => 'Firefogg keresése…',
        'fogg-installed' => 'Firefogg telepítve',
-       'fogg-for_improved_uplods' => 'Fejlettebb feltöltésekhez:',
+       'fogg-for_improved_uploads' => 'Fejlettebb feltöltésekhez:',
        'fogg-please_install' => '<a href="$1">Firefogg telepítése</a>. További információkat <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">itt</a> találsz róla.',
-       'fogg-use_latest_fox' => 'Először telepítsd a <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a>-ös, vagy újabb verzióját, <i>majd látogass el ide újra a <b>Firefogg</b>-kiterjesztés telepítéséhez.</i>',
+       'fogg-use_latest_firefox' => 'Először telepítsd a <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a>-ös, vagy újabb verzióját, <i>majd látogass el ide újra a <b>Firefogg</b>-kiterjesztés telepítéséhez.</i>',
        'fogg-passthrough_mode' => 'Az általad kiválasztott fájl már Ogg formátumban van, vagy nem videófájl',
        'fogg-transcoding' => 'Videó kódolása Ogg formátumba',
        'fogg-encoding-done' => 'A kódolás kész',
@@ -4704,11 +4704,11 @@ $messages['ia'] = array(
        'fogg-select_new_file' => 'Seliger nove file',
        'fogg-select_url' => 'Seliger URL',
        'fogg-save_local_file' => 'Immagazinar in Ogg',
-       'fogg-check_for_fogg' => 'Verifica presentia de Firefogg ...',
+       'fogg-check_for_firefogg' => 'Verifica presentia de Firefogg ...',
        'fogg-installed' => 'Firefogg es installate',
-       'fogg-for_improved_uplods' => 'Pro cargamentos meliorate:',
+       'fogg-for_improved_uploads' => 'Pro cargamentos meliorate:',
        'fogg-please_install' => '<a href="$1">Installar Firefogg</a>. Plus information <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">a proposito de Firefogg</a>',
-       'fogg-use_latest_fox' => 'Per favor primo installa <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (o plus recente). <i>Alora revisita iste pagina pro installar le extension <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Per favor primo installa <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (o plus recente). <i>Alora revisita iste pagina pro installar le extension <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => 'Le file que tu seligeva ja es in Ogg, o non es un file video',
        'fogg-transcoding' => 'Codification del video in Ogg',
        'fogg-encoding-done' => 'Codification complete',
@@ -5016,11 +5016,11 @@ $messages['id'] = array(
        'fogg-select_new_file' => 'Pilih berkas baru',
        'fogg-select_url' => 'Pilih URL',
        'fogg-save_local_file' => 'Simpan Ogg',
-       'fogg-check_for_fogg' => 'Mengecek Firefogg...',
+       'fogg-check_for_firefogg' => 'Mengecek Firefogg...',
        'fogg-installed' => 'Firefogg telah terinstal',
-       'fogg-for_improved_uplods' => 'Untuk pengunggahan canggih:',
+       'fogg-for_improved_uploads' => 'Untuk pengunggahan canggih:',
        'fogg-please_install' => '<a href="$1">Instal Firefogg.</a> Lebih lanjut <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">tentang Firefogg.</a>',
-       'fogg-use_latest_fox' => 'Silakan instal dulu <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (atau lebih baru). <i>Kemudian kunjungi kembali halaman ini untuk menginstal ekstensi <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Silakan instal dulu <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (atau lebih baru). <i>Kemudian kunjungi kembali halaman ini untuk menginstal ekstensi <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => 'Berkas yang dipilih sudah berformat Ogg atau bukan suatu berkas video',
        'fogg-transcoding' => 'Mengkodekan video ke Ogg...',
        'fogg-encoding-done' => 'Pengkodean selesai',
@@ -5376,11 +5376,11 @@ $messages['ja'] = array(
        'fogg-select_new_file' => '別のファイルを選択',
        'fogg-select_url' => 'URLを選択',
        'fogg-save_local_file' => 'Ogg を保存',
-       'fogg-check_for_fogg' => 'Firefogg を確認しています ...',
+       'fogg-check_for_firefogg' => 'Firefogg を確認しています ...',
        'fogg-installed' => 'Firefogg はインストールされています',
-       'fogg-for_improved_uplods' => 'アップロードをより便利にするには:',
+       'fogg-for_improved_uploads' => 'アップロードをより便利にするには:',
        'fogg-please_install' => '<a href="$1">Firefogg をインストール</a>。<a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">Firefogg について</a>。',
-       'fogg-use_latest_fox' => 'はじめに <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5 (以降)</a>をインストールしてください。<i>次にこのページを再読み込みし、 <b>Firefogg</b> 拡張機能をインストールしてください。</i>',
+       'fogg-use_latest_firefox' => 'はじめに <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5 (以降)</a>をインストールしてください。<i>次にこのページを再読み込みし、 <b>Firefogg</b> 拡張機能をインストールしてください。</i>',
        'fogg-passthrough_mode' => '選択したファイルはすでに Ogg 形式であるか、動画ファイルではありません',
        'fogg-transcoding' => '動画を Ogg に形式変換',
        'fogg-encoding-done' => '形式変換終了',
@@ -5733,11 +5733,11 @@ $messages['ksh'] = array(
        'fogg-select_new_file' => 'Neu Dattei ußwähle',
        'fogg-select_url' => '<i lang="en">URL</i> ußwähle',
        'fogg-save_local_file' => 'Ogg afshpeijshere',
-       'fogg-check_for_fogg' => 'Op <i lang="en">Firefogg</i> aam Prööve&nbsp;…',
+       'fogg-check_for_firefogg' => 'Op <i lang="en">Firefogg</i> aam Prööve&nbsp;…',
        'fogg-installed' => '<i lang="en">Firefogg</i> es ennjeresht',
-       'fogg-for_improved_uplods' => 'För e verbäßert Huhlaade:&nbsp;',
+       'fogg-for_improved_uploads' => 'För e verbäßert Huhlaade:&nbsp;',
        'fogg-please_install' => 'Donn <a href="$1"><i lang="en">Firefogg</i> ennreshte</a>. Kanns mieh <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">övver <i lang="en">Firefogg</i> lässe</a>.',
-       'fogg-use_latest_fox' => 'Donn eets dä <i lang="en"><a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a></i> (odder neuer) enshtalleere. Donoh jangk widder op hee di Sigg, öm et Zohsazprojramm <i lang="en"><b>Firefogg</b></i> ze enshtalleere.',
+       'fogg-use_latest_firefox' => 'Donn eets dä <i lang="en"><a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a></i> (odder neuer) enshtalleere. Donoh jangk widder op hee di Sigg, öm et Zohsazprojramm <i lang="en"><b>Firefogg</b></i> ze enshtalleere.',
        'fogg-passthrough_mode' => 'Ding ußjesöhk Dattei eß ald em <i lang="en">Ogg</i>-Fommaat, udder et eß jaa keine Viddejo drän.',
        'fogg-transcoding' => 'Dä Viddejo weedt jraadt noh em <i lang="en">Ogg</i>-Fommaat ömjewandelt',
        'fogg-encoding-done' => 'Ömwandlung es fäädesch',
@@ -5981,11 +5981,11 @@ $messages['lb'] = array(
        'fogg-select_new_file' => 'Neie Fichier eraussichen',
        'fogg-select_url' => 'URL eraussichen',
        'fogg-save_local_file' => 'Ogg späicheren',
-       'fogg-check_for_fogg' => 'Sichen no Firefogg ...',
+       'fogg-check_for_firefogg' => 'Sichen no Firefogg ...',
        'fogg-installed' => 'Firefogg ass installéiert',
-       'fogg-for_improved_uplods' => 'Fir verbessert Eroplueden:',
+       'fogg-for_improved_uploads' => 'Fir verbessert Eroplueden:',
        'fogg-please_install' => '<a href="$1">Installéiert Firefogg</a>. Méi <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">iwwer Firefogg</a>',
-       'fogg-use_latest_fox' => "Installéiert w.e.g. fir d'éischt <a href=\"http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg\">Firefox 3.5</a> (oder méi eng nei Versioun). <i>Kommt duerno zréck op dës Säit fir d'<b>Firefogg</b>-Erweiderung z'installéieren.</i>",
+       'fogg-use_latest_firefox' => "Installéiert w.e.g. fir d'éischt <a href=\"http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg\">Firefox 3.5</a> (oder méi eng nei Versioun). <i>Kommt duerno zréck op dës Säit fir d'<b>Firefogg</b>-Erweiderung z'installéieren.</i>",
        'fogg-preview' => 'Video kucken ouni ze späicheren',
        'mwe-imported_from' => "$1 huet vun [$2 $3] importéiert. Kuckt d'[$4 Originalquellsäit] fir méi Informatiounen.",
        'mwe-stream_title' => '$1 $2 bis $3',
@@ -6190,11 +6190,11 @@ $messages['ml'] = array(
        'fogg-select_new_file' => 'പുതിയ പ്രമാണം തിരഞ്ഞെടുക്കുക',
        'fogg-select_url' => 'യു.ആർ.എൽ. തിരഞ്ഞെടുക്കുക',
        'fogg-save_local_file' => 'ഓഗ് ആയി സേവ് ചെയ്യുക',
-       'fogg-check_for_fogg' => 'ഫയർഫോഗ് തിരയുന്നു...',
+       'fogg-check_for_firefogg' => 'ഫയർഫോഗ് തിരയുന്നു...',
        'fogg-installed' => 'ഫയർഫോഗ് ഇൻസ്റ്റോൾ ചെയ്തിട്ടുണ്ട്',
-       'fogg-for_improved_uplods' => 'മെച്ചപ്പെടുത്തിയ അപ്‌‌ലോഡുകൾക്കു വേണ്ടി:',
+       'fogg-for_improved_uploads' => 'മെച്ചപ്പെടുത്തിയ അപ്‌‌ലോഡുകൾക്കു വേണ്ടി:',
        'fogg-please_install' => '<a href="$1">ഫയർഫോഗ് ഇൻസ്റ്റോൾ ചെയ്യുക</a>. <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">ഫയർഫോഗിനെ കുറിച്ചു കൂടുതൽ</a>',
-       'fogg-use_latest_fox' => 'ദയവായി <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">ഫയർഫോക്സ് 3.5</a> (അല്ലങ്കിൽ ശേഷമുള്ളത്) ആദ്യം ഇൻസ്റ്റോൾ ചെയ്യുക. <i>പിന്നീട് <b>Firefogg</b> അനുബന്ധത്തിനായി ഈ താൾ ഒന്നുകൂടി സന്ദർശിക്കുക.</i>',
+       'fogg-use_latest_firefox' => 'ദയവായി <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">ഫയർഫോക്സ് 3.5</a> (അല്ലങ്കിൽ ശേഷമുള്ളത്) ആദ്യം ഇൻസ്റ്റോൾ ചെയ്യുക. <i>പിന്നീട് <b>Firefogg</b> അനുബന്ധത്തിനായി ഈ താൾ ഒന്നുകൂടി സന്ദർശിക്കുക.</i>',
        'fogg-passthrough_mode' => 'താങ്കൾ തിരഞ്ഞെടുത്ത പ്രമാണം ഓഗ് (Ogg) തന്നെയാണ് അല്ലങ്കിൽ വീഡിയോ പ്രമാണം അല്ല',
        'fogg-transcoding' => 'ചലച്ചിത്രം ഓഗ് ആയി എൻകോഡ് ചെയ്യുന്നു...',
        'fogg-encoding-done' => 'എൻകോഡിങ് പൂർണ്ണം',
@@ -6472,11 +6472,11 @@ Selecteer één te bewerken clip.',
        'fogg-select_new_file' => 'Kies nuwe lêer',
        'fogg-select_url' => 'URL selecteren',
        'fogg-save_local_file' => 'Ogg opslaan',
-       'fogg-check_for_fogg' => 'Firefogg aan het controleren ...',
+       'fogg-check_for_firefogg' => 'Firefogg aan het controleren ...',
        'fogg-installed' => 'Firefogg is geïnstalleerd',
-       'fogg-for_improved_uplods' => 'Voor verbeterde uploads:',
+       'fogg-for_improved_uploads' => 'Voor verbeterde uploads:',
        'fogg-please_install' => '<a href="$1">Installeer Firefogg</a>. Meer <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">over Firefogg</a>',
-       'fogg-use_latest_fox' => 'Installeer alstublieft eerst <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (of een latere versie).
+       'fogg-use_latest_firefox' => 'Installeer alstublieft eerst <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (of een latere versie).
 <i>Kom daarna terug naar deze pagina om de uitbreiding <b>Firefogg</b> te installeren.</i>',
        'fogg-passthrough_mode' => 'Het geselecteerde bestand is al een Ogg-bestand of geen videobestand',
        'fogg-transcoding' => 'Bezig met het converteren van video naar Ogg',
@@ -6778,11 +6778,11 @@ $messages['oc'] = array(
        'fogg-select_new_file' => 'Seleccionatz un fichièr novèl',
        'fogg-select_url' => 'Seleccionatz una URL',
        'fogg-save_local_file' => 'Salvar al format Ogg',
-       'fogg-check_for_fogg' => 'Verificacion de Firefogg ...',
+       'fogg-check_for_firefogg' => 'Verificacion de Firefogg ...',
        'fogg-installed' => 'Firefogg es installat',
-       'fogg-for_improved_uplods' => 'Per de telecargaments melhorats :',
+       'fogg-for_improved_uploads' => 'Per de telecargaments melhorats :',
        'fogg-please_install' => '<a href="$1">Installer Firefogg</a>. Mai d\'entresenhas <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">sus Firefogg</a>',
-       'fogg-use_latest_fox' => 'D\'en primièr, installatz <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (o mai recent). <i>Puèi tornatz sus aquesta pagina per installar l\'extension <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'D\'en primièr, installatz <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (o mai recent). <i>Puèi tornatz sus aquesta pagina per installar l\'extension <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => "Lo fichièr qu'avètz seleccionat es ja al format Ogg o es pas un fichièr vidèo",
        'fogg-transcoding' => "Encodatge d'una vidèo al format Ogg",
        'fogg-encoding-done' => 'Encodatge acabat',
@@ -7061,11 +7061,11 @@ $messages['pl'] = array(
        'fogg-select_new_file' => 'Wybierz nowy plik',
        'fogg-select_url' => 'Wybierz adres URL',
        'fogg-save_local_file' => 'Zapisz w formacie Ogg',
-       'fogg-check_for_fogg' => 'Sprawdzanie czy używasz Firefogg ...',
+       'fogg-check_for_firefogg' => 'Sprawdzanie czy używasz Firefogg ...',
        'fogg-installed' => 'Firefogg jest zainstalowany',
-       'fogg-for_improved_uplods' => 'Dla poprawy przesyłania:',
+       'fogg-for_improved_uploads' => 'Dla poprawy przesyłania:',
        'fogg-please_install' => '<a href="$1">Zainstaluj Firefogg</a>. Więcej <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">o Firefogg</a>',
-       'fogg-use_latest_fox' => 'Należy najpierw zainstalować <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (lub nowszy). <i>Następnie wejść ponownie na tę stronę, aby zainstalować rozszerzenie <b>Firefogg.</b></i>',
+       'fogg-use_latest_firefox' => 'Należy najpierw zainstalować <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (lub nowszy). <i>Następnie wejść ponownie na tę stronę, aby zainstalować rozszerzenie <b>Firefogg.</b></i>',
        'fogg-passthrough_mode' => 'Wybrany przez Ciebie plik jest już w formacie Ogg lub nie jest plikiem wideo',
        'fogg-transcoding' => 'Kodowanie wideo do formatu Ogg',
        'fogg-encoding-done' => 'Kodowanie zakończone',
@@ -7266,9 +7266,9 @@ $messages['pt'] = array(
        'fogg-save_local_file' => 'Gravar Ogg',
        'fogg-check_for_fogg' => 'A procurar o Firefogg...',
        'fogg-installed' => 'Firefogg está instalado',
-       'fogg-for_improved_uplods' => 'Para optimizar os carregamentos:',
+       'fogg-for_improved_uploads' => 'Para optimizar os carregamentos:',
        'fogg-please_install' => '<a href="$1">Instalar o Firefogg</a>. Mais <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">informações sobre o Firefogg</a>.',
-       'fogg-use_latest_fox' => 'Por favor, instale primeiro o <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (ou versão mais recente). <i>Depois volte a esta página para instalar a extensão <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Por favor, instale primeiro o <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (ou versão mais recente). <i>Depois volte a esta página para instalar a extensão <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => 'O ficheiro seleccionado já é de formato Ogg ou não é um ficheiro de vídeo',
        'fogg-transcoding' => 'Codificar vídeo para Ogg',
        'fogg-encoding-done' => 'Codificação finalizada',
@@ -7498,11 +7498,11 @@ $messages['ru'] = array(
        'fogg-select_new_file' => 'Выберите новый файл',
        'fogg-select_url' => 'Выберите URL',
        'fogg-save_local_file' => 'Сохранить Ogg',
-       'fogg-check_for_fogg' => 'Проверка Firefogg …',
+       'fogg-check_for_firefogg' => 'Проверка Firefogg …',
        'fogg-installed' => 'Firefogg установлен',
-       'fogg-for_improved_uplods' => 'Для улучшенных загрузок:',
+       'fogg-for_improved_uploads' => 'Для улучшенных загрузок:',
        'fogg-please_install' => '<a href="$1">Установить Firefogg</a>. Подробнее <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">о Firefogg</a>',
-       'fogg-use_latest_fox' => 'Пожалуйста, сначала установите <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (или выше). <i>Затем повторно обратитесь к этой странице, чтобы установить расширение <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Пожалуйста, сначала установите <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (или выше). <i>Затем повторно обратитесь к этой странице, чтобы установить расширение <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => 'Выбранный файл уже Ogg или не является видео-файлом',
        'fogg-transcoding' => 'Перекодирование видео в Ogg',
        'fogg-encoding-done' => 'Перекодирование завершено',
@@ -7812,11 +7812,11 @@ $messages['sk'] = array(
        'fogg-select_new_file' => 'Vybrať nový súbor',
        'fogg-select_url' => 'Vybrať URL',
        'fogg-save_local_file' => 'Uložiť Ogg',
-       'fogg-check_for_fogg' => 'Kontroluje sa Firefogg ...',
+       'fogg-check_for_firefogg' => 'Kontroluje sa Firefogg ...',
        'fogg-installed' => 'Firefogg je nainštalovaný',
-       'fogg-for_improved_uplods' => 'Na vylepšenie nahrávania:',
+       'fogg-for_improved_uploads' => 'Na vylepšenie nahrávania:',
        'fogg-please_install' => '<a href="$1">si nainštalujte Firefogg</a>. Ďalšie informácie o <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">Firefogg</a>',
-       'fogg-use_latest_fox' => 'Najprv si prosím nainštalujte <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (alebo novší). <i>Po opätovnom navštívení tejto stránky si nainštalujte rozšírenie <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Najprv si prosím nainštalujte <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (alebo novší). <i>Po opätovnom navštívení tejto stránky si nainštalujte rozšírenie <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => 'Váš vybraný súbor je už Ogg alebo to nie je videosúbor',
        'fogg-transcoding' => 'Prebieha prekódovanie videosúboru do Ogg',
        'fogg-encoding-done' => 'Prekódovanie dokončené',
@@ -7937,11 +7937,11 @@ $messages['sv'] = array(
        'fogg-select_new_file' => 'Välj ny fil',
        'fogg-select_url' => 'Välj URL',
        'fogg-save_local_file' => 'Spara Ogg',
-       'fogg-check_for_fogg' => 'Kollar om Firefogg är installerat...',
+       'fogg-check_for_firefogg' => 'Kollar om Firefogg är installerat...',
        'fogg-installed' => 'Firefogg är installerat',
-       'fogg-for_improved_uplods' => 'För förbättrade uppladdningar:',
+       'fogg-for_improved_uploads' => 'För förbättrade uppladdningar:',
        'fogg-please_install' => '<a href="$1">Installera Firefogg</a>. Mer <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">om Firefogg</a> (på engelska).',
-       'fogg-use_latest_fox' => 'Vänligen installera först <a href="http://www.mozilla.com/sv-SE/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (eller senare). <i>Gå sedan tillbaka till den här sidan för att installera tillägget <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Vänligen installera först <a href="http://www.mozilla.com/sv-SE/firefox/upgrade.html?from=firefogg">Firefox 3.5</a> (eller senare). <i>Gå sedan tillbaka till den här sidan för att installera tillägget <b>Firefogg</b>.</i>',
        'fogg-passthrough_mode' => 'Den valda filen är redan i formatet Ogg eller också är den inte en videofil över huvud taget',
        'fogg-transcoding' => 'Kodar om videon till Ogg...',
        'fogg-encoding-done' => 'Kodningen har avslutats',
@@ -8164,11 +8164,11 @@ $messages['tr'] = array(
        'fogg-select_new_file' => 'Yeni dosyayı seç',
        'fogg-select_url' => 'URLyi seç',
        'fogg-save_local_file' => "Ogg'u kaydet",
-       'fogg-check_for_fogg' => 'Firefogg kontrol ediliyor ...',
+       'fogg-check_for_firefogg' => 'Firefogg kontrol ediliyor ...',
        'fogg-installed' => 'Firefogg yüklendi',
-       'fogg-for_improved_uplods' => 'Gelişmiş yüklemeler için:',
+       'fogg-for_improved_uploads' => 'Gelişmiş yüklemeler için:',
        'fogg-please_install' => '<a href="$1">Firefogg\'u yükle</a>. <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg">Firefogg hakkında</a> daha fazla',
-       'fogg-use_latest_fox' => 'Lütfen önce <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a>\'i (ya da sonrası) yükleyin. <i>Daha sonra <b>Firefogg</b> eklentisini yüklemek için bu sayfayı tekrar ziyaret edin.</i>',
+       'fogg-use_latest_firefox' => 'Lütfen önce <a href="http://www.mozilla.com/en-US/firefox/upgrade.html?from=firefogg">Firefox 3.5</a>\'i (ya da sonrası) yükleyin. <i>Daha sonra <b>Firefogg</b> eklentisini yüklemek için bu sayfayı tekrar ziyaret edin.</i>',
        'fogg-passthrough_mode' => 'Seçtiğiniz dosya zaten Ogg ya da bir video dosyası değil',
        'fogg-transcoding' => "Video Ogg'a kodlanıyor",
        'fogg-encoding-done' => 'Kodlama tamamlandı',
@@ -8429,7 +8429,7 @@ $messages['vec'] = array(
        'fogg-select_new_file' => 'Selessiona file novo',
        'fogg-select_url' => 'Selessiona indirisso (URL)',
        'fogg-save_local_file' => 'Salva come Ogg',
-       'fogg-check_for_fogg' => "So' drio sercar el Firefogg...",
+       'fogg-check_for_firefogg' => "So' drio sercar el Firefogg...",
        'fogg-installed' => 'El Firefogg el xe instalà',
        'fogg-transcoding' => "So' drio codificar el video in formato Ogg",
        'fogg-encoding-done' => 'Codifica conpletà',
@@ -8667,11 +8667,11 @@ $messages['vi'] = array(
        'fogg-select_new_file' => 'Chọn tập tin mới',
        'fogg-select_url' => 'Chọn URL',
        'fogg-save_local_file' => 'Lưu thành Ogg',
-       'fogg-check_for_fogg' => 'Đang tìm cho Firefogg …',
+       'fogg-check_for_firefogg' => 'Đang tìm cho Firefogg …',
        'fogg-installed' => 'Firefogg đã được cài đặt',
-       'fogg-for_improved_uplods' => 'Để tải lên tiện hơn:',
+       'fogg-for_improved_uploads' => 'Để tải lên tiện hơn:',
        'fogg-please_install' => '<a href="$1">Cài Firefogg</a>. Thêm <a href="http://commons.wikimedia.org/wiki/Commons:Firefogg?uselang=vi">chi tiết về Firefogg</a>',
-       'fogg-use_latest_fox' => 'Xin hãy cài đặt <a href="http://vi.www.mozilla.com/vi/?from=firefogg">Firefox 3.5</a> (trở lên) trước tiên. <i>Sau đó, hãy trở lại trang này để cài đặt phần mở rộng <b>Firefogg</b>.</i>',
+       'fogg-use_latest_firefox' => 'Xin hãy cài đặt <a href="http://vi.www.mozilla.com/vi/?from=firefogg">Firefox 3.5</a> (trở lên) trước tiên. <i>Sau đó, hãy trở lại trang này để cài đặt phần mở rộng <b>Firefogg</b>.</i>',
        'fogg-preview' => 'Xem trước video',
        'fogg-hidepreview' => 'Ẩn phần xem trước',
        'fogg-help-sticky' => 'Trợ giúp (nhấn chuột để giữ)',
index c009f31..94386ad 100644 (file)
@@ -3,7 +3,7 @@
  * It controls the invocation of the mvUploader class based on local config.
  */
 
-var mwUploadFormTarget = '#mw-upload-form';
+var mwUploadFormSelector = '#mw-upload-form';
 // Set up the upload form bindings once all DOM manipulation is done
 var mwUploadHelper = {
        init: function() {
@@ -18,7 +18,7 @@ var mwUploadHelper = {
                                // An API URL (we won't submit directly to action of the form)
                                'api_url': wgServer + wgScriptPath + '/api.php',
                                'form_rewrite': true,
-                               'target_edit_from': mwUploadFormTarget,
+                               'edit_form_selector': mwUploadFormSelector,
                                'new_source_cb': function( orgFilename, oggName ) {
                                        $j( '#wpDestFile' ).val( oggName );
                                        $j( '#wpDestFile' ).doDestCheck( {
@@ -32,7 +32,7 @@ var mwUploadHelper = {
                        if ( $j( '#wpUploadFileURL' ).length != 0 ) {
                                $j( '#wpUploadFileURL' ).baseUploadInterface( {
                                        'api_url': wgServer + wgScriptPath + '/api.php',
-                                       'target_edit_from': mwUploadFormTarget
+                                       'edit_form_selector': mwUploadFormSelector
                                } );
                        }
                }