From 251c21e84be02aabad13ab30bd56bae69fc7bdde Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Fri, 20 Nov 2009 07:23:08 +0000 Subject: [PATCH] Rework of libAddMedia. The changes are entirely untested and there may be bugs, but at least the code is nicer to look at now. This commit message is probably incomplete. 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 | 2 +- includes/upload/UploadBase.php | 1 - js2/mwEmbed/libAddMedia/mvAdvFirefogg.js | 1225 ++++++++------ .../libAddMedia/mvBaseUploadInterface.js | 1439 +++++++++------- js2/mwEmbed/libAddMedia/mvFirefogg.js | 1489 ++++++++++------- js2/mwEmbed/php/languages/mwEmbed.i18n.php | 180 +- js2/uploadPage.js | 6 +- 7 files changed, 2484 insertions(+), 1858 deletions(-) diff --git a/includes/api/ApiUpload.php b/includes/api/ApiUpload.php index 3b8a7c31e5..faa948a3f9 100644 --- a/includes/api/ApiUpload.php +++ b/includes/api/ApiUpload.php @@ -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: diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php index 147da3dd04..e06ee532e5 100644 --- a/includes/upload/UploadBase.php +++ b/includes/upload/UploadBase.php @@ -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; diff --git a/js2/mwEmbed/libAddMedia/mvAdvFirefogg.js b/js2/mwEmbed/libAddMedia/mvAdvFirefogg.js index 66d2fcfec9..b132954061 100644 --- a/js2/mwEmbed/libAddMedia/mvAdvFirefogg.js +++ b/js2/mwEmbed/libAddMedia/mvAdvFirefogg.js @@ -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 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 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 aspect ratios<\/a>.", + "fogg-aspect-help" : "The video aspect ratio can be 4:3 or 16:9. More about 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 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+= '
'+ - '

' + gM('fogg-cg-'+group_key) + '

'+ - '
'; - //output that group control options: - gdout+=''; - //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 += '
' + + '

' + + gM( 'fogg-cg-' + group_key ) + '

' + + '
'; + // Output this group's control options: + gdout += '
' + + ''; + // 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+='
'; - gdout+= '
' + - '
'; - + gdout += ''; }); - //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( '

' ); + $j( this.selector ).append( '

' ); } - //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 '' + - gM( 'fogg-' + target.substring(11) ) + - ''; - }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 '
' + - '

'+ - gM( 'fogg-' + target.substring(7)) +'

'+ - '
'; - }else if( target == 'target_input_file_name'){ - return '

'; - }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 '' + + linkText + + ''; + 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 + '
' + + '

' + + '' + + text + + '

' + + '
'; + case 'target_input_file_name': + var text = gM( 'fogg-input_file_name' ); + return '

'; + 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+= ''; + $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 += ''; }); - out+=''; - } + out += ''; + } return out; }, - proccessCkControlHTML:function( cK ){ - var cConf = this.default_encoder_config[cK]; - var out =''; - out+=''+ - ''; - //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 += '' + + ''; + // 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+= '' ; - break; + var size = ( type == 'string' || type == 'date' ) ? '14' : '4'; + out += ''; + break; case 'boolean': - var checked_attr = (dv===true)?' checked="true"':''; - out+=''; - break; + var checked_attr = ( defaultValue === true ) ? ' checked="true"' : ''; + out += ''; + break; case 'slider': - var strMax = this.default_encoder_config[ cK ].range.max + ''; - maxdigits = strMax.length +1; - out+= '' + - '
'; - break; + var strMax = this.default_encoder_config[ configKey ].range.max + ''; + maxDigits = strMax.length + 1; + out += '' + + '
'; + break; case 'select': - out+= '' + ''; - for(var i in cConf.selectVal){ - var val = cConf.selectVal[i]; - if(typeof val == 'string'){ - var sel = ( cConf.selectVal[i] == val)?' selected':''; - out+= ''; - }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 += ''; + } 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+= ''; + out += ''; } } - out+=''; - break; + out += ''; + break; } - //output the help row: - out+='
'+ - ''+ - gM('fogg-'+ cK + '-help') + - '
'; - out+=''; + // output the help row: + out += '
' + + '' + + gM( 'fogg-'+ configKey + '-help' ) + + '
'; + out += ''; 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 ) ); } }; diff --git a/js2/mwEmbed/libAddMedia/mvBaseUploadInterface.js b/js2/mwEmbed/libAddMedia/mvBaseUploadInterface.js index 39de0e7d0c..d9c01d7415 100644 --- a/js2/mwEmbed/libAddMedia/mvBaseUploadInterface.js +++ b/js2/mwEmbed/libAddMedia/mvBaseUploadInterface.js @@ -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" : "Your upload 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(''); - - //add json format - if( $j(_this.editForm).find("[name='format']").length == 0) - $j(_this.editForm).append(''); - - //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( '' ); + + // Add JSON format + if ( form.find( "[name='format']" ).length == 0 ) + form.append( '' ); + + // 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(''); - $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( '' ); + + // 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( '
' + _this.getProgressTitle() + '
' + - 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( '
' + _this.getProgressTitle() + '
' + + 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') + '
' + error_msg, bObj ); + _this.updateProgressWin( + gM('mwe-uploaderror'), + gM('mwe-unknown-error') + '
' + 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') + '
', 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' ) + '
', + 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 = '
    '; - for(var wtype in apiRes.upload.warnings){ + for ( var wtype in apiRes.upload.warnings ) { var winfo = apiRes.upload.warnings[wtype] - wmsg+='
  • '; - switch(wtype){ + wmsg += '
  • '; + switch ( wtype ) { case 'duplicate': case 'exists': - if(winfo[1] && winfo[1].title && winfo[1].title.mTextform){ - wmsg += gM('mwe-file-exists-duplicate') +' '+ - '' + winfo[1].title.mTextform + ''; - }else{ + if ( winfo[1] && winfo[1].title && winfo[1].title.mTextform ) { + wmsg += gM( 'mwe-file-exists-duplicate' ) + ' ' + + '' + winfo[1].title.mTextform + ''; + } 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+='
  • '; + wmsg += ''; } - wmsg+='
'; - if( apiRes.upload.sessionkey) - _this.warnings_sessionkey = apiRes.upload.sessionkey; + wmsg += ''; + 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'), '

' + gM('mwe-uploadwarning') + '

' +wmsg + '

',bObj); + // Show warning + _this.updateProgressWin( + gM( 'mwe-uploadwarning' ), + '

' + gM( 'mwe-uploadwarning' ) + '

' + wmsg + '

', + 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('

'); - - $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( - '
' + - '
' + - '
'+ - '0% - ' + - '' + gM('mwe-uploaded-status') + ' ' + - '
'+ - '
' - ) - //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( '
' ); + + $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( + '
' + + '
' + + '
' + + '0% - ' + + '' + gM( 'mwe-uploaded-status' ) + ' ' + + '
'+ + '
' + ); + // 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(''); - - //empty target warn: + + // Add the wpDestFile-warning row + if ( $j( '#wpDestFile-warning' ).length == 0 ) { + $j( '#mw-htmlform-options tr:last' ) + .after( '' ); + } + + // Remove any existing warning $j( opt.warn_target ).empty(); - - //show loading - $j( _this.selector ).append(''); - - //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) + - '
' + - '
' + - '' + - '' + ntitle + '' + - '' + - '
' + - '
' + - '" + - ''+ - '
'+ - gM('mwe-fileexists-thumb') + - '
' + - '
'+ - '
' - ); - } + + // Show the AJAX spinner + $j( _this.selector ) + .append( '' ); + + // 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 ) + + '
' + + '
' + + '' + + '' + + '' + + '
' + + '
' + + '' + + '" + + '' + + '
' + + gM( 'mwe-fileexists-thumb' ) + + '
' + + '
' + + '
' + ); } } - }); + ); } -})(jQuery); +})( jQuery ); diff --git a/js2/mwEmbed/libAddMedia/mvFirefogg.js b/js2/mwEmbed/libAddMedia/mvFirefogg.js index c83d296423..3d532bd601 100644 --- a/js2/mwEmbed/libAddMedia/mvFirefogg.js +++ b/js2/mwEmbed/libAddMedia/mvFirefogg.js @@ -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" : "Install Firefogg<\/a>. More about Firefogg<\/a>.", - "fogg-use_latest_fox" : "Please first install Firefox 3.5<\/a> (or later). Then revisit this page to install the Firefogg<\/b> extension.<\/i>", + "fogg-use_latest_firefox" : "Please first install Firefox 3.5<\/a> (or later). Then revisit this page to install the 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 ' '; - }else if(target.substr(7,5)=='input'){ - return ' '; - }else{ - return '
'+ gM('fogg-'+ target.substring(7)) + '
'; + + /** + * 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 ' '; + } else if ( /^target_input_/.test( target ) ) { + // Text input + var msg = gM( target.replace( /^target_input_/, 'fogg-' ) ); + return ' '; + } else if ( /^target_/.test( target ) ) { + // Message + var msg = gM( target.replace( '/^target_/', 'fogg-' ) ); + return '
' + msg + '
'; + } 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 = ''; + var id = $j( this.selector ).attr( 'name' ) + '_firefogg-control'; + inputTag += '/>'; - 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( - '
'+ - $j.btnHtml(gM('fogg-preview'), 'fogg_preview', 'triangle-1-e') + - '
' + + // Add the preview button and canvas + $j( '#upProgressDialog' ).append( + '
' + + $j.btnHtml( gM( 'fogg-preview' ), 'fogg_preview', 'triangle-1-e' ) + + '
' + '' + '
' ); - // 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(''); - 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( '' ); + 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' ) + '
' + + //show the video at full resolution upto 720px wide + '' + ); + //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') + '
' + - // Show the video at full resolution up-to 720px wide - '' - ); - //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; } }; diff --git a/js2/mwEmbed/php/languages/mwEmbed.i18n.php b/js2/mwEmbed/php/languages/mwEmbed.i18n.php index 9d2a646a13..696361337f 100644 --- a/js2/mwEmbed/php/languages/mwEmbed.i18n.php +++ b/js2/mwEmbed/php/languages/mwEmbed.i18n.php @@ -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' => '
Install Firefogg. More about Firefogg.', - 'fogg-use_latest_fox' => 'Please first install Firefox 3.5 (or later). Then revisit this page to install the Firefogg extension.', + 'fogg-use_latest_firefox' => 'Please first install Firefox 3.5 (or later). Then revisit this page to install the Firefogg extension.', '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' => 'Усталяваць Firefogg. Болей пра Firefogg', - 'fogg-use_latest_fox' => 'Калі ласка, спачатку ўсталюйце Firefox 3.5 (ці больш позьнюю вэрсію). Потым зноў наведайце гэтую старонку і ўсталюйце пашырэньне Firefogg.', + 'fogg-use_latest_firefox' => 'Калі ласка, спачатку ўсталюйце Firefox 3.5 (ці больш позьнюю вэрсію). Потым зноў наведайце гэтую старонку і ўсталюйце пашырэньне Firefogg.', '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' => 'Nainstalujte si Firefogg. Další informace o Firefoggu', - 'fogg-use_latest_fox' => 'Nejprve si nainstalujte Firefox 3.5 (nebo novější). Poté se vraÅ¥te na tuto stránku, abyste si mohli nainstalovat rozšíření Firefogg.', + 'fogg-use_latest_firefox' => 'Nejprve si nainstalujte Firefox 3.5 (nebo novější). Poté se vraÅ¥te na tuto stránku, abyste si mohli nainstalovat rozšíření Firefogg.', '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' => 'Installiere Firefogg. Mehr über Firefogg', - '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). Besuche danach die Seite neu, um die Firefogg-Erweiterung zu installieren.', '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' => 'Firefogg bar ker. derheqê firefoggi de', - 'fogg-use_latest_fox' => 'kerem kerê ewwil Firefox 3.5\'i barkerê. u hema parçeyê Firefogg i bar kerê, qey barkerdışi no pel ziyaret bıkerê', + 'fogg-use_latest_firefox' => 'kerem kerê ewwil Firefox 3.5\'i barkerê. u hema parçeyê Firefogg i bar kerê, qey barkerdışi no pel ziyaret bıkerê', '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' => 'Firefogg instalěrowaś. Wjace wó Firefogg', - 'fogg-use_latest_fox' => 'PÅ¡osym instalěruj njepjerwjej Firefox 3.5 (abo wuÅ¡i). Woglědaj pótom k toś tomu bokoju zasego, aby rozÅ¡yrjenje Firefogg instalěrował.', + 'fogg-use_latest_firefox' => 'PÅ¡osym instalěruj njepjerwjej Firefox 3.5 (abo wuÅ¡i). Woglědaj pótom k toś tomu bokoju zasego, aby rozÅ¡yrjenje Firefogg instalěrował.', '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 Firefox (Fajrvulpo) 3.5 (or later). Poste revenu al ĉi tiu paĝo por instali la kromprogramon Firefogg.', + 'fogg-use_latest_firefox' => 'Bonvolu antaÅ­e instali Firefox (Fajrvulpo) 3.5 (or later). Poste revenu al ĉi tiu paĝo por instali la kromprogramon Firefogg.', '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' => 'Instalar Firefogg. Más acerca de Firefogg', - 'fogg-use_latest_fox' => 'Por favor primero instala Firefox 3.5 (o posterior). Luego vuelve a visitar esta página para instalar la extensión Firefogg.', + 'fogg-use_latest_firefox' => 'Por favor primero instala Firefox 3.5 (o posterior). Luego vuelve a visitar esta página para instalar la extensión Firefogg.', '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' => 'Asenna Firefogg – Tietoja Firefoggista.', - 'fogg-use_latest_fox' => 'Asenna ensin Firefox 3.5 (tai uudempi). Tule sen jälkeen uudelleen tälle sivulle ja asenna Firefogg-laajennus.', + 'fogg-use_latest_firefox' => 'Asenna ensin Firefox 3.5 (tai uudempi). Tule sen jälkeen uudelleen tälle sivulle ja asenna Firefogg-laajennus.', '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' => 'Installer Firefogg. Plus d\'infos sur Firefogg', - 'fogg-use_latest_fox' => 'Veuillez d\'abord installer Firefox 3.5 (ou plus récent). Puis revenez sur cette page pour installer l\'extension Firefogg.', + 'fogg-use_latest_firefox' => 'Veuillez d\'abord installer Firefox 3.5 (ou plus récent). Puis revenez sur cette page pour installer l\'extension Firefogg.', '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' => 'Instalar o Firefogg. Máis información acerca do Firefogg', - 'fogg-use_latest_fox' => 'Por favor, instale primeiro o Firefox 3.5 (ou superior). Logo diso, volte a esta páxina para instalar a extensión Firefogg.', + 'fogg-use_latest_firefox' => 'Por favor, instale primeiro o Firefox 3.5 (ou superior). Logo diso, volte a esta páxina para instalar a extensión Firefogg.', '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' => 'Firefogg inschtalliere. Meh Informatione iber Firefogg', - 'fogg-use_latest_fox' => 'Bitte ischtallier zerscht Firefox 3.5 (oder e nejeri Version). DErno gang wider uf die Syte go d Firefogg-Erwyterig inschtalliere.', + 'fogg-use_latest_firefox' => 'Bitte ischtallier zerscht Firefox 3.5 (oder e nejeri Version). DErno gang wider uf die Syte go d Firefogg-Erwyterig inschtalliere.', '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' => 'להתקנת Firefogg. עוד אודות Firefogg', - 'fogg-use_latest_fox' => 'ראשית יש להתקין את Firefox 3.5 (ומעלה). לאחר מכן יש לבקר בדף זה שוב כדי להתקין את ההרחבה Firefogg.', + 'fogg-use_latest_firefox' => 'ראשית יש להתקין את Firefox 3.5 (ומעלה). לאחר מכן יש לבקר בדף זה שוב כדי להתקין את ההרחבה Firefogg.', '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' => 'Firefogg instalować. Wjace wo Firefoggu', - 'fogg-use_latest_fox' => 'ProÅ¡u instalu najprjedy Firefox 3.5 (abo wyÅ¡e). Potom wopytaj tutu strona znowa, zo by rozšěrjenje Firefogg instalował.', + 'fogg-use_latest_firefox' => 'ProÅ¡u instalu najprjedy Firefox 3.5 (abo wyÅ¡e). Potom wopytaj tutu strona znowa, zo by rozšěrjenje Firefogg instalował.', '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' => 'Firefogg telepítése. További információkat itt találsz róla.', - 'fogg-use_latest_fox' => 'Először telepítsd a Firefox 3.5-ös, vagy újabb verzióját, majd látogass el ide újra a Firefogg-kiterjesztés telepítéséhez.', + 'fogg-use_latest_firefox' => 'Először telepítsd a Firefox 3.5-ös, vagy újabb verzióját, majd látogass el ide újra a Firefogg-kiterjesztés telepítéséhez.', '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' => 'Installar Firefogg. Plus information a proposito de Firefogg', - 'fogg-use_latest_fox' => 'Per favor primo installa Firefox 3.5 (o plus recente). Alora revisita iste pagina pro installar le extension Firefogg.', + 'fogg-use_latest_firefox' => 'Per favor primo installa Firefox 3.5 (o plus recente). Alora revisita iste pagina pro installar le extension Firefogg.', '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' => 'Instal Firefogg. Lebih lanjut tentang Firefogg.', - 'fogg-use_latest_fox' => 'Silakan instal dulu Firefox 3.5 (atau lebih baru). Kemudian kunjungi kembali halaman ini untuk menginstal ekstensi Firefogg.', + 'fogg-use_latest_firefox' => 'Silakan instal dulu Firefox 3.5 (atau lebih baru). Kemudian kunjungi kembali halaman ini untuk menginstal ekstensi Firefogg.', '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' => 'Firefogg をインストール。Firefogg について。', - 'fogg-use_latest_fox' => 'はじめに Firefox 3.5 (以降)をインストールしてください。次にこのページを再読み込みし、 Firefogg 拡張機能をインストールしてください。', + 'fogg-use_latest_firefox' => 'はじめに Firefox 3.5 (以降)をインストールしてください。次にこのページを再読み込みし、 Firefogg 拡張機能をインストールしてください。', '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' => 'URL ußwähle', 'fogg-save_local_file' => 'Ogg afshpeijshere', - 'fogg-check_for_fogg' => 'Op Firefogg aam Prööve â€¦', + 'fogg-check_for_firefogg' => 'Op Firefogg aam Prööve â€¦', 'fogg-installed' => 'Firefogg es ennjeresht', - 'fogg-for_improved_uplods' => 'För e verbäßert Huhlaade: ', + 'fogg-for_improved_uploads' => 'För e verbäßert Huhlaade: ', 'fogg-please_install' => 'Donn Firefogg ennreshte. Kanns mieh övver Firefogg lässe.', - 'fogg-use_latest_fox' => 'Donn eets dä Firefox 3.5 (odder neuer) enshtalleere. Donoh jangk widder op hee di Sigg, öm et Zohsazprojramm Firefogg ze enshtalleere.', + 'fogg-use_latest_firefox' => 'Donn eets dä Firefox 3.5 (odder neuer) enshtalleere. Donoh jangk widder op hee di Sigg, öm et Zohsazprojramm Firefogg ze enshtalleere.', 'fogg-passthrough_mode' => 'Ding ußjesöhk Dattei eß ald em Ogg-Fommaat, udder et eß jaa keine Viddejo drän.', 'fogg-transcoding' => 'Dä Viddejo weedt jraadt noh em Ogg-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' => 'Installéiert Firefogg. Méi iwwer Firefogg', - 'fogg-use_latest_fox' => "Installéiert w.e.g. fir d'éischt Firefox 3.5 (oder méi eng nei Versioun). Kommt duerno zréck op dës Säit fir d'Firefogg-Erweiderung z'installéieren.", + 'fogg-use_latest_firefox' => "Installéiert w.e.g. fir d'éischt Firefox 3.5 (oder méi eng nei Versioun). Kommt duerno zréck op dës Säit fir d'Firefogg-Erweiderung z'installéieren.", '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' => 'ഫയർഫോഗ് ഇൻസ്റ്റോൾ ചെയ്യുക. ഫയർഫോഗിനെ കുറിച്ചു കൂടുതൽ', - 'fogg-use_latest_fox' => 'ദയവായി ഫയർഫോക്സ് 3.5 (അല്ലങ്കിൽ ശേഷമുള്ളത്) ആദ്യം ഇൻസ്റ്റോൾ ചെയ്യുക. പിന്നീട് Firefogg അനുബന്ധത്തിനായി ഈ താൾ ഒന്നുകൂടി സന്ദർശിക്കുക.', + 'fogg-use_latest_firefox' => 'ദയവായി ഫയർഫോക്സ് 3.5 (അല്ലങ്കിൽ ശേഷമുള്ളത്) ആദ്യം ഇൻസ്റ്റോൾ ചെയ്യുക. പിന്നീട് Firefogg അനുബന്ധത്തിനായി ഈ താൾ ഒന്നുകൂടി സന്ദർശിക്കുക.', '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' => 'Installeer Firefogg. Meer over Firefogg', - 'fogg-use_latest_fox' => 'Installeer alstublieft eerst Firefox 3.5 (of een latere versie). + 'fogg-use_latest_firefox' => 'Installeer alstublieft eerst Firefox 3.5 (of een latere versie). Kom daarna terug naar deze pagina om de uitbreiding Firefogg te installeren.', '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' => 'Installer Firefogg. Mai d\'entresenhas sus Firefogg', - 'fogg-use_latest_fox' => 'D\'en primièr, installatz Firefox 3.5 (o mai recent). Puèi tornatz sus aquesta pagina per installar l\'extension Firefogg.', + 'fogg-use_latest_firefox' => 'D\'en primièr, installatz Firefox 3.5 (o mai recent). Puèi tornatz sus aquesta pagina per installar l\'extension Firefogg.', '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' => 'Zainstaluj Firefogg. Więcej o Firefogg', - 'fogg-use_latest_fox' => 'Należy najpierw zainstalować Firefox 3.5 (lub nowszy). Następnie wejść ponownie na tę stronę, aby zainstalować rozszerzenie Firefogg.', + 'fogg-use_latest_firefox' => 'Należy najpierw zainstalować Firefox 3.5 (lub nowszy). Następnie wejść ponownie na tę stronę, aby zainstalować rozszerzenie Firefogg.', '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' => 'Instalar o Firefogg. Mais informações sobre o Firefogg.', - 'fogg-use_latest_fox' => 'Por favor, instale primeiro o Firefox 3.5 (ou versão mais recente). Depois volte a esta página para instalar a extensão Firefogg.', + 'fogg-use_latest_firefox' => 'Por favor, instale primeiro o Firefox 3.5 (ou versão mais recente). Depois volte a esta página para instalar a extensão Firefogg.', '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' => 'Установить Firefogg. Подробнее о Firefogg', - 'fogg-use_latest_fox' => 'Пожалуйста, сначала установите Firefox 3.5 (или выше). Затем повторно обратитесь к этой странице, чтобы установить расширение Firefogg.', + 'fogg-use_latest_firefox' => 'Пожалуйста, сначала установите Firefox 3.5 (или выше). Затем повторно обратитесь к этой странице, чтобы установить расширение Firefogg.', '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' => 'si nainÅ¡talujte Firefogg. ĎalÅ¡ie informácie o Firefogg', - 'fogg-use_latest_fox' => 'Najprv si prosím nainÅ¡talujte Firefox 3.5 (alebo novší). Po opätovnom navÅ¡tívení tejto stránky si nainÅ¡talujte rozšírenie Firefogg.', + 'fogg-use_latest_firefox' => 'Najprv si prosím nainÅ¡talujte Firefox 3.5 (alebo novší). Po opätovnom navÅ¡tívení tejto stránky si nainÅ¡talujte rozšírenie Firefogg.', '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' => 'Installera Firefogg. Mer om Firefogg (pÃ¥ engelska).', - 'fogg-use_latest_fox' => 'Vänligen installera först Firefox 3.5 (eller senare). GÃ¥ sedan tillbaka till den här sidan för att installera tillägget Firefogg.', + 'fogg-use_latest_firefox' => 'Vänligen installera först Firefox 3.5 (eller senare). GÃ¥ sedan tillbaka till den här sidan för att installera tillägget Firefogg.', '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' => 'Firefogg\'u yükle. Firefogg hakkında daha fazla', - 'fogg-use_latest_fox' => 'Lütfen önce Firefox 3.5\'i (ya da sonrası) yükleyin. Daha sonra Firefogg eklentisini yüklemek için bu sayfayı tekrar ziyaret edin.', + 'fogg-use_latest_firefox' => 'Lütfen önce Firefox 3.5\'i (ya da sonrası) yükleyin. Daha sonra Firefogg eklentisini yüklemek için bu sayfayı tekrar ziyaret edin.', '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' => 'Cài Firefogg. Thêm chi tiết về Firefogg', - 'fogg-use_latest_fox' => 'Xin hãy cài đặt Firefox 3.5 (trở lên) trước tiên. Sau đó, hãy trở lại trang này để cài đặt phần mở rộng Firefogg.', + 'fogg-use_latest_firefox' => 'Xin hãy cài đặt Firefox 3.5 (trở lên) trước tiên. Sau đó, hãy trở lại trang này để cài đặt phần mở rộng Firefogg.', '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ữ)', diff --git a/js2/uploadPage.js b/js2/uploadPage.js index c009f31352..94386adfff 100644 --- a/js2/uploadPage.js +++ b/js2/uploadPage.js @@ -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 } ); } } -- 2.20.1