Index: branches/uploadwizard-firefogg/UploadWizard.config.php |
— | — | @@ -0,0 +1,126 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Upload Wizard Configuration |
| 5 | + * Do not modify this file, instead use localsettings.php and set: |
| 6 | + * $wgUploadWizardConfig[ 'name'] = 'value'; |
| 7 | + */ |
| 8 | +global $wgFileExtensions, $wgServer, $wgScriptPath, $wgAPIModules, |
| 9 | +$wgTimedMediaHandlerFileExtensions, $wgAutoloadClasses; |
| 10 | +return array( |
| 11 | + // Upload wizard has an internal debug flag |
| 12 | + 'debug' => false, |
| 13 | + |
| 14 | + // If the uploaded file should be auto categorized |
| 15 | + 'autoCategory' => true, |
| 16 | + |
| 17 | + // File extensions acceptable in this wiki |
| 18 | + 'fileExtensions' => $wgFileExtensions, |
| 19 | + |
| 20 | + // Check if we want to enable firefogg ( for transcoding ) |
| 21 | + 'enableFirefogg' => true, |
| 22 | + |
| 23 | + // Check if we have the firefogg upload api module enabled: |
| 24 | + 'enableFirefoggChunkUpload' => isset( $wgAPIModules['firefoggupload'] )? true : false, |
| 25 | + |
| 26 | + // Firefogg encode settings ( if timed media handler extension is installed use HD webm, else mid-rage ogg ) |
| 27 | + 'firefoggEncodeSettings' => ( class_exists( 'WebVideoTranscode' ) )? |
| 28 | + WebVideoTranscode::$derivativeSettings[ WebVideoTranscode::ENC_WEBM_HQ_VBR ] : |
| 29 | + array( |
| 30 | + 'maxSize' => '480', |
| 31 | + 'videoBitrate' => '512', |
| 32 | + 'audioBitrate' => '96', |
| 33 | + 'noUpscaling' => 'true', |
| 34 | + 'twopass' => 'true', |
| 35 | + 'keyframeInterval' => '128', |
| 36 | + 'bufDelay' => '256', |
| 37 | + 'videoCodec' => 'theora', |
| 38 | + ), |
| 39 | + |
| 40 | + // The default api url is for the current wiki ( can override at run time ) |
| 41 | + 'apiUrl' => $wgServer . $wgScriptPath . '/api.php', |
| 42 | + |
| 43 | + // The progress update interval for uploads |
| 44 | + 'uploadProgressInterval' => 250, |
| 45 | + |
| 46 | + // Default thumbnail width |
| 47 | + 'thumbnailWidth' => 120, |
| 48 | + |
| 49 | + // Max thumbnail height: |
| 50 | + 'thumbnailMaxHeight' => 200, |
| 51 | + |
| 52 | + // Min thumbnail width |
| 53 | + 'smallThumbnailWidth' => 60, |
| 54 | + |
| 55 | + // Small thumbnail max height |
| 56 | + 'smallThumbnailMaxHeight' => 100, |
| 57 | + |
| 58 | + // Icon thumbnail width: |
| 59 | + 'iconThumbnailWidth' => 32, |
| 60 | + |
| 61 | + // Icon thumbnail height: |
| 62 | + 'iconThumbnailMaxHeight' => 32, |
| 63 | + |
| 64 | + // Max author string length |
| 65 | + 'maxAuthorLength' => 50, |
| 66 | + |
| 67 | + // Min author string length |
| 68 | + 'minAuthorLength' => 2, |
| 69 | + |
| 70 | + // Max source string length |
| 71 | + 'maxSourceLength' => 200, |
| 72 | + |
| 73 | + // Min source string length |
| 74 | + 'minSourceLength' => 5, |
| 75 | + |
| 76 | + // Max file title string length |
| 77 | + 'maxTitleLength' => 200, |
| 78 | + |
| 79 | + // Min file title string length |
| 80 | + 'minTitleLength' => 5, |
| 81 | + |
| 82 | + // Max file description length |
| 83 | + 'maxDescriptionLength' => 4096, |
| 84 | + |
| 85 | + // Min file description length |
| 86 | + 'minDescriptionLength' => 5, |
| 87 | + |
| 88 | + // Max length for other file information: |
| 89 | + 'maxOtherInformationLength' => 4096, |
| 90 | + |
| 91 | + // Max number of simultaneous upload requests |
| 92 | + 'maxSimultaneousConnections' => 1, |
| 93 | + |
| 94 | + // Max number of uploads for a given form |
| 95 | + 'maxUploads' => 10, |
| 96 | + |
| 97 | + // not for use with all wikis. |
| 98 | + // The ISO 639 code for the language tagalog is "tl". |
| 99 | + // Normally we name templates for languages by the ISO 639 code. |
| 100 | + // Commons already had a template called 'tl: though. |
| 101 | + // so, this workaround will cause tagalog descriptions to be saved with this template instead. |
| 102 | + 'languageTemplateFixups' => array( 'tl' => 'tgl' ), |
| 103 | + |
| 104 | + // names of all license templates, in order. Case sensitive! |
| 105 | + // n.b. in the future, the licenses for a wiki will probably be defined in PHP or even LocalSettings. |
| 106 | + 'licenses' => array( |
| 107 | + array( 'template' => 'Cc-by-sa-3.0','messageKey' => 'mwe-upwiz-license-cc-by-sa-3.0', 'default' => true ), |
| 108 | + array( 'template' => 'Cc-by-3.0', 'messageKey' => 'mwe-upwiz-license-cc-by-3.0', 'default' => false ), |
| 109 | + array( 'template' => 'Cc-zero', 'messageKey' => 'mwe-upwiz-license-cc-zero', 'default' => false ), |
| 110 | + // n.b. the PD-US is only for testing purposes, obviously we need some geographical discrimination here... |
| 111 | + array( 'template' => 'PD-US', 'messageKey' => 'mwe-upwiz-license-pd-us', 'default' => false ), |
| 112 | + array( 'template' => 'GFDL', 'messageKey' => 'mwe-upwiz-license-gfdl', 'default' => false ) |
| 113 | + ) |
| 114 | + |
| 115 | + // XXX this is horribly confusing -- some file restrictions are client side, others are server side |
| 116 | + // the filename prefix blacklist is at least server side -- all this should be replaced with PHP regex config |
| 117 | + // or actually, in an ideal world, we'd have some way to reliably detect gibberish, rather than trying to |
| 118 | + // figure out what is bad via individual regexes, we'd detect badness. Might not be too hard. |
| 119 | + // |
| 120 | + // we can export these to JS if we so want. |
| 121 | + // filenamePrefixBlacklist: wgFilenamePrefixBlacklist, |
| 122 | + // |
| 123 | + // filenameRegexBlacklist: [ |
| 124 | + // /^(test|image|img|bild|example?[\s_-]*)$/, // test stuff |
| 125 | + // /^(\d{10}[\s_-][0-9a-f]{10}[\s_-][a-z])$/ // flickr |
| 126 | + // ] |
| 127 | +); |
Index: branches/uploadwizard-firefogg/UploadWizardHooks.php |
— | — | @@ -57,6 +57,11 @@ |
58 | 58 | // workhorse libraries |
59 | 59 | 'resources/mw.IframeTransport.js', |
60 | 60 | 'resources/mw.ApiUploadHandler.js', |
| 61 | + |
| 62 | + // firefogg support |
| 63 | + 'resources/mw.FirefoggHandler.js', |
| 64 | + 'resources/mw.FirefoggTransport.js', |
| 65 | + |
61 | 66 | 'resources/mw.DestinationChecker.js', |
62 | 67 | 'resources/mw.UploadWizardUtil.js', |
63 | 68 | |
— | — | @@ -64,9 +69,8 @@ |
65 | 70 | 'resources/mw.GroupProgressBar.js', |
66 | 71 | |
67 | 72 | // UploadWizard specific abstractions |
68 | | - 'resources/mw.UploadWizardDeed.js', |
69 | 73 | 'resources/mw.UploadWizardLicenseInput.js', |
70 | | - |
| 74 | + |
71 | 75 | // main library |
72 | 76 | 'resources/mw.UploadWizard.js', |
73 | 77 | |
Index: branches/uploadwizard-firefogg/resources/mw.FirefoggHandler.js |
— | — | @@ -0,0 +1,105 @@ |
| 2 | +/** |
| 3 | + * An attempt to refactor out the stuff that does API-via-iframe transport |
| 4 | + * In the hopes that this will eventually work for AddMediaWizard too |
| 5 | + */ |
| 6 | + |
| 7 | +/** |
| 8 | + * Represents an object which configures a form to upload its files via an iframe talking to the MediaWiki API. |
| 9 | + * @param an UploadInterface object, which contains a .form property which points to a real HTML form in the DOM |
| 10 | + */ |
| 11 | +mw.FirefoggHandler = function( upload ) { |
| 12 | + return this.init( upload ); |
| 13 | +}; |
| 14 | + |
| 15 | +mw.FirefoggHandler.prototype = { |
| 16 | + // The transport object |
| 17 | + transport : null, // lazy init |
| 18 | + /** |
| 19 | + * Constructor |
| 20 | + */ |
| 21 | + init: function( upload ){ |
| 22 | + this.upload = upload; |
| 23 | + this.api = upload.api; |
| 24 | + // update the mwe-upwiz-file-input target |
| 25 | + this.upload.ui.$fileInputCtrl = this.getInputControl() |
| 26 | + this.upload.ui.fileCtrlContainer.empty().append( |
| 27 | + this.upload.ui.$fileInputCtrl |
| 28 | + ) |
| 29 | + }, |
| 30 | + // Setup local pointer to firefogg instance |
| 31 | + getFogg: function(){ |
| 32 | + if( ! this.fogg ){ |
| 33 | + this.fogg = new Firefogg(); |
| 34 | + } |
| 35 | + return this.fogg; |
| 36 | + }, |
| 37 | + getTransport: function(){ |
| 38 | + var _this = this; |
| 39 | + if( !this.transport ){ |
| 40 | + this.transport = new mw.FirefoggTransport( |
| 41 | + this.getForm(), |
| 42 | + this.getFogg(), |
| 43 | + function( fraction ) { |
| 44 | + _this.upload.setTransportProgress( fraction ); |
| 45 | + // also update preview video: |
| 46 | + }, |
| 47 | + function( result ) { |
| 48 | + mw.log("FirefoggTransport::getTransport> Transport done " + JSON.stringify( result ) ); |
| 49 | + _this.upload.setTransported( result ); |
| 50 | + } |
| 51 | + ); |
| 52 | + } |
| 53 | + return this.transport; |
| 54 | + }, |
| 55 | + isGoodExtension: function( ext ){ |
| 56 | + // First check if its an oky extension for the wiki: |
| 57 | + if( $j.inArray( ext.toLowerCase(), mw.UploadWizard.config[ 'fileExtensions' ] ) !== -1 ){ |
| 58 | + return true; |
| 59 | + } |
| 60 | + // Check if its a file that can be transcoded: |
| 61 | + if( this.getTransport().isSourceAudio() || this.getTransport().isSourceVideo() ){ |
| 62 | + return true; |
| 63 | + } |
| 64 | + return false; |
| 65 | + }, |
| 66 | + |
| 67 | + getForm: function(){ |
| 68 | + return $j( this.upload.ui.form ); |
| 69 | + }, |
| 70 | + |
| 71 | + /** |
| 72 | + * Get a pointer to the "file" input control |
| 73 | + */ |
| 74 | + getInputControl: function(){ |
| 75 | + var _this = this; |
| 76 | + return $j('<input />').attr({ |
| 77 | + 'size': "1", |
| 78 | + 'name': "file", |
| 79 | + 'type': "text" |
| 80 | + }) |
| 81 | + .addClass( "mwe-upwiz-file-input" ) |
| 82 | + .click( function() { |
| 83 | + if( _this.getFogg().selectVideo() ) { |
| 84 | + // Update the value of the input file: |
| 85 | + $j( this ) |
| 86 | + .val( _this.getFogg().sourceFilename ) |
| 87 | + //.trigger('change'); |
| 88 | + // note the change trigger does not work because we replace the target: |
| 89 | + _this.upload.ui.fileChanged(); |
| 90 | + } |
| 91 | + } ); |
| 92 | + }, |
| 93 | + |
| 94 | + /** |
| 95 | + * If chunks are disabled transcode then upload else |
| 96 | + * upload and transcode at the same time |
| 97 | + */ |
| 98 | + start: function() { |
| 99 | + var _this = this; |
| 100 | + mw.log( "mw.FirefoggHandler::start> upload start!" ); |
| 101 | + _this.beginTime = ( new Date() ).getTime(); |
| 102 | + _this.upload.ui.setStatus( 'mwe-upwiz-transport-started' ); |
| 103 | + _this.upload.ui.showTransportProgress(); |
| 104 | + _this.getTransport().doUpload(); |
| 105 | + } |
| 106 | +}; |
Property changes on: branches/uploadwizard-firefogg/resources/mw.FirefoggHandler.js |
___________________________________________________________________ |
Added: svn:mime-type |
1 | 107 | + text/plain |
Index: branches/uploadwizard-firefogg/resources/mw.UploadWizardUploadInterface.js |
— | — | @@ -0,0 +1,349 @@ |
| 2 | +/** |
| 3 | + * Create an interface fragment corresponding to a file input, suitable for Upload Wizard. |
| 4 | + * @param upload |
| 5 | + * @param div to insert file interface |
| 6 | + * @param addInterface interface to add a new one (assumed that we start out there) |
| 7 | + */ |
| 8 | +mw.UploadWizardUploadInterface = function( upload, filesDiv ) { |
| 9 | + var _this = this; |
| 10 | + |
| 11 | + _this.upload = upload; |
| 12 | + |
| 13 | + // may need to collaborate with the particular upload type sometimes |
| 14 | + // for the interface, as well as the uploadwizard. OY. |
| 15 | + _this.div = $j('<div class="mwe-upwiz-file"></div>').get(0); |
| 16 | + _this.isFilled = false; |
| 17 | + _this.$fileInputCtrl = $j('<input size="1" class="mwe-upwiz-file-input" name="file" type="file"/>') |
| 18 | + .change( function() { |
| 19 | + _this.fileChanged(); |
| 20 | + } ); |
| 21 | + |
| 22 | + _this.$indicator = $j( '<div class="mwe-upwiz-file-indicator"></div>' ); |
| 23 | + |
| 24 | + visibleFilenameDiv = $j('<div class="mwe-upwiz-visible-file"></div>') |
| 25 | + .append( _this.$indicator ) |
| 26 | + .append( '<div class="mwe-upwiz-visible-file-filename">' |
| 27 | + + '<div class="mwe-upwiz-file-preview"/>' |
| 28 | + + '<div class="mwe-upwiz-file-texts">' |
| 29 | + + '<div class="mwe-upwiz-visible-file-filename-text"/>' |
| 30 | + + '<div class="mwe-upwiz-file-status-line">' |
| 31 | + + '<div class="mwe-upwiz-file-status mwe-upwiz-file-status-line-item"></div>' |
| 32 | + + '</div>' |
| 33 | + + '</div>' |
| 34 | + + '</div>' |
| 35 | + ); |
| 36 | + |
| 37 | + _this.$removeCtrl = $j.fn.removeCtrl( |
| 38 | + 'mwe-upwiz-remove', |
| 39 | + 'mwe-upwiz-remove-upload', |
| 40 | + function() { _this.upload.remove(); } |
| 41 | + ).addClass( "mwe-upwiz-file-status-line-item" ); |
| 42 | + |
| 43 | + visibleFilenameDiv.find( '.mwe-upwiz-file-status-line' ) |
| 44 | + .append( _this.$removeCtrl ); |
| 45 | + |
| 46 | + //_this.errorDiv = $j('<div class="mwe-upwiz-upload-error mwe-upwiz-file-indicator" style="display: none;"></div>').get(0); |
| 47 | + |
| 48 | + _this.filenameCtrl = $j('<input type="hidden" name="filename" value=""/>').get(0); |
| 49 | + |
| 50 | + // this file Ctrl container is placed over other interface elements, intercepts clicks and gives them to the file input control. |
| 51 | + // however, we want to pass hover events to interface elements that we are over, hence the bindings. |
| 52 | + // n.b. not using toggleClass because it often gets this event wrong -- relies on previous state to know what to do |
| 53 | + _this.fileCtrlContainer = $j('<div class="mwe-upwiz-file-ctrl-container">'); |
| 54 | +/* |
| 55 | + .bind( 'mouseenter', function(e) { _this.addFileCtrlHover(e); } ) |
| 56 | + .bind( 'mouseleave', function(e) { _this.removeFileCtrlHover(e); } ); |
| 57 | +*/ |
| 58 | + |
| 59 | + |
| 60 | + // the css trickery (along with css) |
| 61 | + // here creates a giant size file input control which is contained within a div and then |
| 62 | + // clipped for overflow. The effect is that we have a div (ctrl-container) we can position anywhere |
| 63 | + // which works as a file input. It will be set to opacity:0 and then we can do whatever we want with |
| 64 | + // interface "below". |
| 65 | + // XXX caution -- if the add file input changes size we won't match, unless we add some sort of event to catch this. |
| 66 | + _this.form = $j( '<form method="POST" encType="multipart/form-data" class="mwe-upwiz-form"></form>' ) |
| 67 | + .attr( { action: _this.upload.api.url } ) |
| 68 | + .append( visibleFilenameDiv ) |
| 69 | + .append( _this.fileCtrlContainer |
| 70 | + .append( _this.$fileInputCtrl ) |
| 71 | + ) |
| 72 | + .append( _this.filenameCtrl ) |
| 73 | + .append( _this.thumbnailParam ) |
| 74 | + .get( 0 ); |
| 75 | + |
| 76 | + |
| 77 | + $j( _this.div ).append( _this.form ); |
| 78 | + |
| 79 | + // XXX evil hardcoded |
| 80 | + // we don't really need filesdiv if we do it this way? |
| 81 | + $j( filesDiv ).append( _this.div ); |
| 82 | + |
| 83 | + // _this.progressBar = ( no progress bar for individual uploads yet ) |
| 84 | + // we bind to the ui div since unbind doesn't work for non-DOM objects |
| 85 | + $j( _this.div ).bind( 'transportProgressEvent', function(e) { _this.showTransportProgress(); } ); |
| 86 | + // $j( _this.div ).bind( 'transportedEvent', function(e) { _this.showStashed(); } ); |
| 87 | + |
| 88 | +}; |
| 89 | + |
| 90 | + |
| 91 | +mw.UploadWizardUploadInterface.prototype = { |
| 92 | + /** |
| 93 | + * Things to do to this interface once we start uploading |
| 94 | + */ |
| 95 | + start: function() { |
| 96 | + var _this = this; |
| 97 | + // remove hovering |
| 98 | + $j( _this.div ) |
| 99 | + .unbind( 'mouseenter mouseover mouseleave mouseout' ); |
| 100 | + |
| 101 | + // remove delete control |
| 102 | + $j( _this.div ) |
| 103 | + .find( '.mwe-upwiz-remove-ctrl' ) |
| 104 | + .unbind( 'mouseenter mouseover mouseleave mouseout' ) |
| 105 | + .remove(); |
| 106 | + }, |
| 107 | + |
| 108 | + /** |
| 109 | + * change the graphic indicator at the far end of the row for this file |
| 110 | + * @param String statusClass: corresponds to a class mwe-upwiz-status which changes style of indicator. |
| 111 | + */ |
| 112 | + showIndicator: function( statusClass ) { |
| 113 | + this.clearIndicator(); |
| 114 | + // add the desired class and make it visible, if it wasn't already. |
| 115 | + this.$indicator.addClass( 'mwe-upwiz-status-' + statusClass ) |
| 116 | + .css( 'visibility', 'visible' ); |
| 117 | + }, |
| 118 | + |
| 119 | + /** |
| 120 | + * Reset the graphic indicator |
| 121 | + */ |
| 122 | + clearIndicator: function() { |
| 123 | + var _this = this; |
| 124 | + $j.each( _this.$indicator.attr( 'class' ).split( /\s+/ ), function( i, className ) { |
| 125 | + if ( className.match( /^mwe-upwiz-status/ ) ) { |
| 126 | + _this.$indicator.removeClass( className ); |
| 127 | + } |
| 128 | + } ); |
| 129 | + }, |
| 130 | + |
| 131 | + /** |
| 132 | + * Set the preview image on the file page for this upload. |
| 133 | + * @param HTMLImageElement |
| 134 | + */ |
| 135 | + setPreview: function( image ) { |
| 136 | + // encoding for url here? |
| 137 | + $j( this.div ).find( '.mwe-upwiz-file-preview' ).css( 'background-image', 'url(' + image.src + ')' ); |
| 138 | + }, |
| 139 | + |
| 140 | + /** |
| 141 | + * Set the status line for this upload with an internationalized message string. |
| 142 | + * @param String msgKey: key for the message |
| 143 | + * @param Array args: array of values, in case any need to be fed to the image. |
| 144 | + */ |
| 145 | + setStatus: function( msgKey, args ) { |
| 146 | + if ( !mw.isDefined( args ) ) { |
| 147 | + args = []; |
| 148 | + } |
| 149 | + this.setStatusStr( gM( msgKey, args ) ); |
| 150 | + }, |
| 151 | + |
| 152 | + /** |
| 153 | + * Set the status line for this upload |
| 154 | + * @param String str: the string to use |
| 155 | + */ |
| 156 | + setStatusStr: function( str ) { |
| 157 | + $j( this.div ).find( '.mwe-upwiz-file-status' ).html( str ).show(); |
| 158 | + }, |
| 159 | + |
| 160 | + /** |
| 161 | + * Clear the status line for this upload (hide it, in case there are paddings and such which offset other things.) |
| 162 | + */ |
| 163 | + clearStatus: function() { |
| 164 | + $j( this.div ).find( '.mwe-upwiz-file-status' ).hide(); |
| 165 | + }, |
| 166 | + |
| 167 | + /** |
| 168 | + * Put the visual state of an individual upload ito "progress" |
| 169 | + * @param fraction The fraction of progress. Float between 0 and 1 |
| 170 | + */ |
| 171 | + showTransportProgress: function( fraction ) { |
| 172 | + // if fraction available, update individual progress bar / estimates, etc. |
| 173 | + this.showIndicator( 'progress' ); |
| 174 | + this.setStatus( 'mwe-upwiz-uploading' ); |
| 175 | + }, |
| 176 | + |
| 177 | + /** |
| 178 | + * Show that upload is transported |
| 179 | + */ |
| 180 | + showStashed: function() { |
| 181 | + this.$removeCtrl.detach(); |
| 182 | + this.$fileInputCtrl.detach(); |
| 183 | + this.showIndicator( 'stashed' ); |
| 184 | + this.setStatus( 'mwe-upwiz-stashed-upload' ); // this is just "OK", say something more. |
| 185 | + }, |
| 186 | + |
| 187 | + /** |
| 188 | + * Show that transport has failed |
| 189 | + * @param String code: error code from API |
| 190 | + * @param {String|Object} info: extra info |
| 191 | + */ |
| 192 | + showError: function( code, info ) { |
| 193 | + this.showIndicator( 'error' ); |
| 194 | + // is this an error that we expect to have a message for? |
| 195 | + var msgKey = 'mwe-upwiz-api-error-unknown-code'; |
| 196 | + var args = [ code ]; |
| 197 | + if ( $j.inArray( code, mw.Api.errors ) !== -1 ) { |
| 198 | + msgKey = 'mwe-upwiz-api-error-' + code; |
| 199 | + // args may change base on particular error messages. |
| 200 | + // for instance, we are throwing away the extra info right now. Might be nice to surface that in a debug mode |
| 201 | + args = []; |
| 202 | + } |
| 203 | + this.setStatus( msgKey, args ); |
| 204 | + }, |
| 205 | + |
| 206 | + /** |
| 207 | + * Run this when the value of the file input has changed. Check the file for various forms of goodness. |
| 208 | + * If okay, then update the visible filename (due to CSS trickery the real file input is invisible) |
| 209 | + */ |
| 210 | + fileChanged: function() { |
| 211 | + var _this = this; |
| 212 | + _this.clearErrors(); |
| 213 | + _this.upload.extractLocalFileInfo( _this.$fileInputCtrl.val() ); |
| 214 | + if ( _this.isGoodExtension( _this.upload.title.getExtension() ) ) { |
| 215 | + _this.updateFilename(); |
| 216 | + } else { |
| 217 | + //_this.error( 'bad-filename-extension', ext ); |
| 218 | + alert("bad extension"); |
| 219 | + } |
| 220 | + this.clearStatus(); |
| 221 | + }, |
| 222 | + |
| 223 | + /** |
| 224 | + * Move the file input to cover a certain element on the page. |
| 225 | + * We use invisible file inputs because this is the only way to style a file input |
| 226 | + * or otherwise get it to do what you want. |
| 227 | + * It is helpful to sometimes move them to cover certain elements on the page, and |
| 228 | + * even to pass events like hover |
| 229 | + * @param selector jquery-compatible selector, for a single element |
| 230 | + */ |
| 231 | + moveFileInputToCover: function( selector ) { |
| 232 | + var $covered = $j( selector ); |
| 233 | + |
| 234 | + this.fileCtrlContainer |
| 235 | + .css( $covered.position() ) |
| 236 | + .css( 'marginTop', $covered.css( 'marginTop' ) ) |
| 237 | + .css( 'marginRight', $covered.css( 'marginRight' ) ) |
| 238 | + .css( 'marginBottom', $covered.css( 'marginBottom' ) ) |
| 239 | + .css( 'marginLeft', $covered.css( 'marginLeft' ) ) |
| 240 | + .width( $covered.outerWidth() ) |
| 241 | + .height( $covered.outerHeight() ); |
| 242 | + |
| 243 | + this.fileCtrlContainer.css( { 'z-index': 1 } ); |
| 244 | + |
| 245 | + // shift the file input over with negative margins, |
| 246 | + // internal to the overflow-containing div, so the div shows all button |
| 247 | + // and none of the textfield-like input |
| 248 | + this.$fileInputCtrl.css( { |
| 249 | + 'margin-left': '-' + ~~( this.$fileInputCtrl.width() - $covered.outerWidth() - 10 ) + 'px', |
| 250 | + 'margin-top' : '-' + ~~( this.$fileInputCtrl.height() - $covered.outerHeight() - 10 ) + 'px' |
| 251 | + } ); |
| 252 | + |
| 253 | + |
| 254 | + }, |
| 255 | + |
| 256 | + /** |
| 257 | + * this does two things: |
| 258 | + * 1 ) since the file input has been hidden with some clever CSS ( to avoid x-browser styling issues ), |
| 259 | + * update the visible filename |
| 260 | + * |
| 261 | + * 2 ) update the underlying "title" which we are targeting to add to mediawiki. |
| 262 | + * TODO silently fix to have unique filename? unnecessary at this point... |
| 263 | + */ |
| 264 | + updateFilename: function() { |
| 265 | + var _this = this; |
| 266 | + var path = _this.$fileInputCtrl.val(); |
| 267 | + // get basename of file; some browsers do this C:\fakepath\something |
| 268 | + path = path.replace(/\w:.*\\(.*)$/,'$1'); |
| 269 | + |
| 270 | + // visible filename |
| 271 | + $j( _this.form ).find( '.mwe-upwiz-visible-file-filename-text' ).html( path ); |
| 272 | + |
| 273 | + _this.upload.title = new mw.Title( mw.UploadWizardUtil.getBasename( path ), 'file' ); |
| 274 | + $j( _this.filenameCtrl ).val( _this.upload.title.getMain() ); |
| 275 | + |
| 276 | + if ( ! _this.isFilled ) { |
| 277 | + var $div = $j( _this.div ); |
| 278 | + _this.isFilled = true; |
| 279 | + $div.addClass( 'filled' ); |
| 280 | + |
| 281 | + // cover the div with the file input. |
| 282 | + // we use the visible-file div because it has the same offsetParent as the file input |
| 283 | + // the second argument offsets the fileinput to the right so there's room for the close icon to get mouse events |
| 284 | + _this.moveFileInputToCover( |
| 285 | + $div.find( '.mwe-upwiz-visible-file-filename-text' ) |
| 286 | + ); |
| 287 | + |
| 288 | + // Highlight the file on mouseover (and also show controls like the remove control). |
| 289 | + // |
| 290 | + // On Firefox there are bugs related to capturing mouse events on inputs, so we seem to miss the |
| 291 | + // mouseenter or mouseleave events randomly. It's only really bad if we miss mouseleave, |
| 292 | + // and have two highlights visible. so we add another call to REALLY make sure that other highlights |
| 293 | + // are deactivated. |
| 294 | + // http://code.google.com/p/fbug/issues/detail?id=2075 |
| 295 | + // |
| 296 | + // ALSO: When file inputs are adjacent, Firefox misses the "mouseenter" and "mouseleave" events. |
| 297 | + // Consequently we have to bind to "mouseover" and "mouseout" as well even though that's not as efficient. |
| 298 | + $div.bind( 'mouseenter mouseover', function() { |
| 299 | + $div.addClass( 'hover' ); |
| 300 | + $j( '#mwe-upwiz-filelist' ) |
| 301 | + .children() |
| 302 | + .filter( function() { return this !== _this.div; } ) |
| 303 | + .removeClass('hover'); |
| 304 | + }, false ); |
| 305 | + $div.bind( 'mouseleave mouseout', function() { |
| 306 | + $div.removeClass( 'hover' ); |
| 307 | + }, false ); |
| 308 | + $j( _this.div ).trigger( 'filled' ); |
| 309 | + } else { |
| 310 | + $j( _this.div ).trigger( 'filenameAccepted' ); |
| 311 | + } |
| 312 | + }, |
| 313 | + |
| 314 | + /** |
| 315 | + * Remove any complaints we had about errors and such |
| 316 | + * XXX this should be changed to something Theme compatible |
| 317 | + */ |
| 318 | + clearErrors: function() { |
| 319 | + var _this = this; |
| 320 | + $j( _this.div ).removeClass( 'mwe-upwiz-upload-error '); |
| 321 | + $j( _this.errorDiv ).hide().empty(); |
| 322 | + }, |
| 323 | + |
| 324 | + /** |
| 325 | + * Show an error with the upload |
| 326 | + */ |
| 327 | + error: function() { |
| 328 | + var _this = this; |
| 329 | + var args = Array.prototype.slice.call( arguments ); // copies arguments into a real array |
| 330 | + var msg = 'mwe-upwiz-upload-error-' + args[0]; |
| 331 | + $j( _this.errorDiv ).append( $j( '<p class="mwe-upwiz-upload-error">' + gM( msg, args.slice( 1 ) ) + '</p>') ); |
| 332 | + // apply a error style to entire did |
| 333 | + $j( _this.div ).addClass( 'mwe-upwiz-upload-error' ); |
| 334 | + $j( _this.errorDiv ).show(); |
| 335 | + }, |
| 336 | + |
| 337 | + /** |
| 338 | + * This is used when checking for "bad" extensions in a filename. |
| 339 | + * @param ext |
| 340 | + * @return boolean if extension was acceptable |
| 341 | + */ |
| 342 | + isGoodExtension: function( ext ) { |
| 343 | + // ugly but we don't have a base "uploadHandler" class |
| 344 | + if( this.upload.getUploadHandler().isGoodExtension ){ |
| 345 | + return this.upload.getUploadHandler().isGoodExtension( ext ); |
| 346 | + } |
| 347 | + return $j.inArray( ext.toLowerCase(), mw.UploadWizard.config[ 'fileExtensions' ] ) !== -1; |
| 348 | + } |
| 349 | + |
| 350 | +}; |
\ No newline at end of file |
Property changes on: branches/uploadwizard-firefogg/resources/mw.UploadWizardUploadInterface.js |
___________________________________________________________________ |
Added: svn:mime-type |
1 | 351 | + text/plain |
Index: branches/uploadwizard-firefogg/resources/mw.DestinationChecker.js |
— | — | @@ -146,6 +146,7 @@ |
147 | 147 | |
148 | 148 | if ( data.query.pages[-1] ) { |
149 | 149 | // No conflict found; this file name is unique |
| 150 | + mw.log("mw.DestinationChecker::checkUnique> No pages in checkUnique result"); |
150 | 151 | result = { isUnique: true }; |
151 | 152 | |
152 | 153 | } else { |
— | — | @@ -156,6 +157,8 @@ |
157 | 158 | } |
158 | 159 | |
159 | 160 | // Conflict found, this filename is NOT unique |
| 161 | + mw.log( "mw.DestinationChecker::checkUnique> conflict! " ); |
| 162 | + |
160 | 163 | var ntitle; |
161 | 164 | if ( data.query.normalized ) { |
162 | 165 | ntitle = data.query.normalized[0].to; |
Index: branches/uploadwizard-firefogg/resources/mw.UtilitiesTime.js |
— | — | @@ -15,7 +15,8 @@ |
16 | 16 | */ |
17 | 17 | mw.seconds2npt = function( sec, show_ms ) { |
18 | 18 | if ( isNaN( sec ) ) { |
19 | | - sec = 0; |
| 19 | + mw.log("mw.seconds2npt> Warning: trying to get npt time on NaN:" + sec); |
| 20 | + return '0:00:00'; |
20 | 21 | } |
21 | 22 | |
22 | 23 | var tm = mw.seconds2Measurements( sec ); |
— | — | @@ -65,7 +66,8 @@ |
66 | 67 | */ |
67 | 68 | mw.npt2seconds = function ( npt_str ) { |
68 | 69 | if ( !npt_str ) { |
69 | | - return undefined; |
| 70 | + // mw.log('npt2seconds:not valid ntp:'+ntp); |
| 71 | + return false; |
70 | 72 | } |
71 | 73 | // Strip {npt:}01:02:20 or 32{s} from time if present |
72 | 74 | npt_str = npt_str.replace( /npt:|s/g, '' ); |
Index: branches/uploadwizard-firefogg/resources/mw.Api.edit.js |
— | — | @@ -1,5 +1,7 @@ |
2 | 2 | // library to assist with edits |
3 | 3 | |
| 4 | +// dependencies: [ mw.Api, jQuery ] |
| 5 | + |
4 | 6 | ( function( mw, $ ) { |
5 | 7 | |
6 | 8 | // cached token so we don't have to keep fetching new ones for every single post |
— | — | @@ -17,27 +19,36 @@ |
18 | 20 | */ |
19 | 21 | postWithEditToken: function( params, ok, err ) { |
20 | 22 | var api = this; |
| 23 | + var _method = 'mw.api.edit::postWithEditToken> '; |
| 24 | + mw.log( 'post with edit token' ); |
21 | 25 | if ( cachedToken === null ) { |
| 26 | + mw.log( _method + 'no cached token' ); |
22 | 27 | // We don't have a valid cached token, so get a fresh one and try posting. |
23 | 28 | // We do not trap any 'badtoken' or 'notoken' errors, because we don't want |
24 | 29 | // an infinite loop. If this fresh token is bad, something else is very wrong. |
25 | 30 | var useTokenToPost = function( token ) { |
| 31 | + mw.log( _method + 'posting with token = ' + token ); |
26 | 32 | params.token = token; |
27 | 33 | this.post( params, ok, err ); |
28 | 34 | }; |
| 35 | + mw.log( _method + 'getting edit token' ); |
29 | 36 | api.getEditToken( useTokenToPost, err ); |
30 | 37 | } else { |
31 | 38 | // We do have a token, but it might be expired. So if it is 'bad' then |
32 | 39 | // start over with a new token. |
33 | 40 | params.token = cachedToken; |
| 41 | + mw.log( _method + 'we do have a token = ' + params.token ); |
34 | 42 | var getTokenIfBad = function( code, result ) { |
| 43 | + mw.log( _method + "error with posting with token!" ); |
35 | 44 | if ( code === 'badtoken' ) { |
| 45 | + mw.log( _method + "bad token; try again" ); |
36 | 46 | cachedToken = null; // force a new token |
37 | 47 | api.postWidthEditToken( params, ok, err ); |
38 | 48 | } else { |
39 | 49 | err( code, result ); |
40 | 50 | } |
41 | 51 | }; |
| 52 | + mw.log ( _method + "posting with the token that was cached " ); |
42 | 53 | api.post( params, ok, getTokenIfBad ); |
43 | 54 | } |
44 | 55 | }, |
Index: branches/uploadwizard-firefogg/resources/mw.FirefoggTransport.js |
— | — | @@ -0,0 +1,247 @@ |
| 2 | +/** |
| 3 | + * Represents a "transport" for files to upload; in this case an firefogg. |
| 4 | + * XXX dubious whether this is really separated from "ApiUploadHandler", which does a lot of form config. |
| 5 | + * |
| 6 | + * The iframe is made to be the target of a form so that the existing page does not reload, even though it's a POST. |
| 7 | + * @param form jQuery selector for HTML form |
| 8 | + * @param progressCb callback to execute when we've started. (does not do float here because iframes can't |
| 9 | + * monitor fractional progress). |
| 10 | + * @param transportedCb callback to execute when we've finished the upload |
| 11 | + */ |
| 12 | +mw.FirefoggTransport = function( $form, fogg, progressCb, transportedCb ) { |
| 13 | + this.$form = $form; |
| 14 | + this.fogg = fogg; |
| 15 | + this.progressCb = progressCb; |
| 16 | + this.transportedCb = transportedCb; |
| 17 | +}; |
| 18 | + |
| 19 | +mw.FirefoggTransport.prototype = { |
| 20 | + |
| 21 | + passthrough: false, |
| 22 | + /** |
| 23 | + * Do an upload on a given fogg object: |
| 24 | + */ |
| 25 | + doUpload: function(){ |
| 26 | + // check if the server supports chunks: |
| 27 | + if( this.isChunkUpload() ){ |
| 28 | + mw.log("FirefoggTransport::doUpload> Chunks"); |
| 29 | + // encode and upload at the same time: |
| 30 | + this.doChunkUpload(); |
| 31 | + } else { |
| 32 | + mw.log("FirefoggTransport::doUpload> Encode then upload"); |
| 33 | + this.doEncodeThenUpload(); |
| 34 | + } |
| 35 | + }, |
| 36 | + isChunkUpload: function(){ |
| 37 | + return false; |
| 38 | + return ( mw.UploadWizard.config[ 'enableFirefoggChunkUpload' ] ); |
| 39 | + }, |
| 40 | + /** |
| 41 | + * Check if the asset should be uploaded in passthrough mode ( or if it should be encoded ) |
| 42 | + */ |
| 43 | + isPassThrough: function(){ |
| 44 | + // Check if the server supports raw webm uploads: |
| 45 | + var wembExt = ( $j.inArray( mw.UploadWizard.config[ 'fileExtensions'], 'webm') !== -1 ) |
| 46 | + // Determine passthrough mode |
| 47 | + if ( this.isOggFormat() || ( wembExt && isWebMFormat() ) ) { |
| 48 | + // Already Ogg, no need to encode |
| 49 | + return true; |
| 50 | + } else if ( this.isSourceAudio() || this.isSourceVideo() ) { |
| 51 | + // OK to encode |
| 52 | + return false; |
| 53 | + } else { |
| 54 | + // Not audio or video, can't encode |
| 55 | + return true; |
| 56 | + } |
| 57 | + }, |
| 58 | + |
| 59 | + isSourceAudio: function() { |
| 60 | + return ( this.getSourceFileInfo().contentType.indexOf("audio/") != -1 ); |
| 61 | + }, |
| 62 | + |
| 63 | + isSourceVideo: function() { |
| 64 | + return ( this.getSourceFileInfo().contentType.indexOf("video/") != -1 ); |
| 65 | + }, |
| 66 | + |
| 67 | + isOggFormat: function() { |
| 68 | + var contentType = this.getSourceFileInfo().contentType; |
| 69 | + return ( contentType.indexOf("video/ogg") != -1 |
| 70 | + || contentType.indexOf("application/ogg") != -1 |
| 71 | + || contentType.indexOf("audio/ogg") != -1); |
| 72 | + }, |
| 73 | + isWebMFormat: function() { |
| 74 | + return ( this.getSourceFileInfo().contentType.indexOf('webm') != -1 ); |
| 75 | + }, |
| 76 | + |
| 77 | + /** |
| 78 | + * Get the source file info for the current file selected into this.fogg |
| 79 | + */ |
| 80 | + getSourceFileInfo: function() { |
| 81 | + if ( !this.fogg.sourceInfo ) { |
| 82 | + mw.log( 'Error:: No firefogg source info is available' ); |
| 83 | + return false; |
| 84 | + } |
| 85 | + try { |
| 86 | + this.sourceFileInfo = JSON.parse( this.fogg.sourceInfo ); |
| 87 | + } catch ( e ) { |
| 88 | + mw.log( 'Error :: could not parse fogg sourceInfo' ); |
| 89 | + return false; |
| 90 | + } |
| 91 | + return this.sourceFileInfo; |
| 92 | + }, |
| 93 | + |
| 94 | + // Get the filename |
| 95 | + getFileName: function(){ |
| 96 | + // If passthrough don't change it |
| 97 | + if( this.isPassThrough() ){ |
| 98 | + return this.fogg.sourceFilename; |
| 99 | + } else { |
| 100 | + if( this.isSourceAudio() ){ |
| 101 | + return this.fogg.sourceFilename.split('.').slice(0,-1).join('.') + '.oga'; |
| 102 | + } |
| 103 | + if( this.isSourceVideo() ){ |
| 104 | + return this.fogg.sourceFilename.split('.').slice(0,-1).join('.') + '.webm'; |
| 105 | + } |
| 106 | + } |
| 107 | + }, |
| 108 | + getEncodeExt: function(){ |
| 109 | + if( this.getEncodeSettings()['videoCodec'] |
| 110 | + && |
| 111 | + this.getEncodeSettings()['videoCodec'] == 'vp8' ) |
| 112 | + { |
| 113 | + return 'webm'; |
| 114 | + } else { |
| 115 | + return 'ogv'; |
| 116 | + } |
| 117 | + }, |
| 118 | + /** |
| 119 | + * Get the encode settings from configuration and the current selected video type |
| 120 | + */ |
| 121 | + getEncodeSettings: function(){ |
| 122 | + var encodeSettings = $j.extend( {}, mw.UploadWizard.config[ 'firefoggEncodeSettings'] , { |
| 123 | + 'passthrough' : this.isPassThrough() |
| 124 | + }); |
| 125 | + // Update the format: |
| 126 | + this.fogg.setFormat( ( this.getEncodeExt == 'webm' )? 'webm' : 'ogg' ); |
| 127 | + |
| 128 | + mw.log("FirefoggTransport::getEncodeSettings> " + JSON.stringify( encodeSettings ) ); |
| 129 | + return encodeSettings; |
| 130 | + }, |
| 131 | + |
| 132 | + /** |
| 133 | + * Encode then upload |
| 134 | + */ |
| 135 | + doEncodeThenUpload: function(){ |
| 136 | + // If doing passthrough jump direct to upload: |
| 137 | + if( this.isPassThrough() ){ |
| 138 | + this.doFoggPost(); |
| 139 | + return ; |
| 140 | + } |
| 141 | + this.fogg.encode( JSON.stringify( this.getEncodeSettings() ) ); |
| 142 | + |
| 143 | + this.monitorProgress(); |
| 144 | + }, |
| 145 | + |
| 146 | + /** |
| 147 | + * do fogg post |
| 148 | + */ |
| 149 | + doFoggPost: function(){ |
| 150 | + var _this = this; |
| 151 | + // Get the upload request with a callback ( populates the request token ) |
| 152 | + this.getUploadRequest( function( request ){ |
| 153 | + mw.log("FirefoggTransport::doFoggPost> " + _this.getUploadUrl() + ' req:' + |
| 154 | + JSON.stringify( request ) ); |
| 155 | + |
| 156 | + _this.fogg.post( _this.getUploadUrl(), |
| 157 | + 'file', |
| 158 | + JSON.stringify( request ) |
| 159 | + ); |
| 160 | + _this.monitorProgress(); |
| 161 | + } ); |
| 162 | + }, |
| 163 | + /** |
| 164 | + * Encode and upload in chunks |
| 165 | + */ |
| 166 | + doChunkUpload: function(){ |
| 167 | + var _this = this; |
| 168 | + this.getUploadRequest( function( request ){ |
| 169 | + this.fogg.upload( |
| 170 | + JSON.stringify( _this.getEncodeSettings() ), |
| 171 | + _this.getUploadUrl(), |
| 172 | + JSON.stringify( request ) |
| 173 | + ); |
| 174 | + }); |
| 175 | + _this.monitorProgress(); |
| 176 | + }, |
| 177 | + /** |
| 178 | + * Get the upload url |
| 179 | + */ |
| 180 | + getUploadUrl: function(){ |
| 181 | + return mw.UploadWizard.config['apiUrl']; |
| 182 | + }, |
| 183 | + |
| 184 | + /** |
| 185 | + * Get the upload settings |
| 186 | + * @param {function} callback function to send the request object |
| 187 | + */ |
| 188 | + getUploadRequest: function( callback ){ |
| 189 | + var _this = this; |
| 190 | + // ugly probably would be nice to have base refrence to the upload class so we can use the |
| 191 | + new mw.Api( { |
| 192 | + 'url' : _this.getUploadUrl() |
| 193 | + } ) |
| 194 | + .getEditToken( function( token ) { |
| 195 | + callback( { |
| 196 | + 'action' : ( _this.isChunkUpload() )? 'firefoggupload' : 'upload', |
| 197 | + 'stash' :1, |
| 198 | + 'comment' : 'DUMMY TEXT', |
| 199 | + 'format' : 'json', |
| 200 | + 'filename' : _this.getFileName(), |
| 201 | + 'token' : token |
| 202 | + } ); |
| 203 | + }, function( code, info ) { |
| 204 | + _this.upload.setError( code, info ); |
| 205 | + } ); |
| 206 | + }, |
| 207 | + /** |
| 208 | + * Monitor progress on an upload: |
| 209 | + */ |
| 210 | + monitorProgress: function(){ |
| 211 | + var _this = this; |
| 212 | + var fogg = this.fogg; |
| 213 | + var progress = fogg.progress(); |
| 214 | + var state = fogg.state; |
| 215 | + |
| 216 | + mw.log("FirefoggTransport::monitorProgress> " + progress + ' state: ' + state + ' status: ' + this.fogg.status() + ' rt: ' + this.getResponseText() ); |
| 217 | + this.progressCb( progress ); |
| 218 | + |
| 219 | + if( state == 'encoding done' && ! this.isChunkUpload() ){ |
| 220 | + // ( if encoding done, we are in a two step encode then upload process ) |
| 221 | + this.doFoggPost(); |
| 222 | + return ; |
| 223 | + } |
| 224 | + // If state is 'in progress' ... fire monitor progress |
| 225 | + if( state == 'encoding' || state == 'uploading' || state == '' ){ |
| 226 | + setTimeout( function(){ |
| 227 | + _this.monitorProgress(); |
| 228 | + }, mw.UploadWizard.config['uploadProgressInterval'] ); |
| 229 | + } |
| 230 | + // return the api result: |
| 231 | + if( state == 'done' || state == 'upload done' ){ |
| 232 | + this.transportedCb( this.getResponseText() ); |
| 233 | + } |
| 234 | + |
| 235 | + }, |
| 236 | + |
| 237 | + getResponseText: function(){ |
| 238 | + var _this = this; |
| 239 | + try { |
| 240 | + var pstatus = JSON.parse( _this.fogg.uploadstatus() ); |
| 241 | + return pstatus["responseText"]; |
| 242 | + } catch( e ) { |
| 243 | + mw.log( "Error:: Firefogg could not parse uploadstatus / could not get responseText: " + e ); |
| 244 | + } |
| 245 | + } |
| 246 | +}; |
| 247 | + |
| 248 | + |
Property changes on: branches/uploadwizard-firefogg/resources/mw.FirefoggTransport.js |
___________________________________________________________________ |
Added: svn:mime-type |
1 | 249 | + text/plain |
Index: branches/uploadwizard-firefogg/resources/mw.UploadWizard.js |
— | — | @@ -22,17 +22,17 @@ |
23 | 23 | this.transportWeight = 1; // default |
24 | 24 | this.detailsWeight = 1; // default |
25 | 25 | |
26 | | - // details |
| 26 | + // details |
27 | 27 | this.ui = new mw.UploadWizardUploadInterface( this, filesDiv ); |
28 | 28 | |
29 | 29 | // handler -- usually ApiUploadHandler |
30 | | - // this.handler = new ( mw.UploadWizard.config[ 'uploadHandlerClass' ] )( this ); |
31 | | - // this.handler = new mw.MockUploadHandler( this ); |
32 | | - this.handler = new mw.ApiUploadHandler( this, api ); |
| 30 | + this.handler = this.getUploadHandler(); |
33 | 31 | }; |
34 | 32 | |
35 | 33 | mw.UploadWizardUpload.prototype = { |
36 | | - |
| 34 | + // Upload handler for the UploadWizardUpload |
| 35 | + uploadHandler: null, // lazy init |
| 36 | + |
37 | 37 | acceptDeed: function( deed ) { |
38 | 38 | var _this = this; |
39 | 39 | _this.deed.applyDeed( _this ); |
— | — | @@ -49,7 +49,7 @@ |
50 | 50 | }, |
51 | 51 | |
52 | 52 | /** |
53 | | - * remove this upload. n.b. we trigger a removeUpload this is usually triggered from |
| 53 | + * Remove this upload. n.b. we trigger a removeUpload this is usually triggered from |
54 | 54 | */ |
55 | 55 | remove: function() { |
56 | 56 | this.state = 'aborted'; |
— | — | @@ -95,10 +95,11 @@ |
96 | 96 | setTransported: function( result ) { |
97 | 97 | var _this = this; |
98 | 98 | if ( _this.state == 'aborted' ) { |
99 | | - return; |
| 99 | + return ; |
100 | 100 | } |
101 | 101 | |
102 | 102 | if ( result.upload && result.upload.imageinfo ) { |
| 103 | + mw.log( 'UploadWizard::setTransported> process api imageinfo' ); |
103 | 104 | // success |
104 | 105 | _this.state = 'transported'; |
105 | 106 | _this.transportProgress = 1; |
— | — | @@ -106,7 +107,7 @@ |
107 | 108 | _this.extractUploadInfo( result ); |
108 | 109 | |
109 | 110 | // use blocking preload for thumbnail, no loading spinner. |
110 | | - _this.getThumbnail( |
| 111 | + _this.getThumbnail( |
111 | 112 | function( image ) { |
112 | 113 | _this.ui.setPreview( image ); |
113 | 114 | _this.deedPreview.setup(); |
— | — | @@ -199,8 +200,27 @@ |
200 | 201 | */ |
201 | 202 | } |
202 | 203 | }, |
203 | | - |
204 | 204 | /** |
| 205 | + * Set the upload handler per browser capabilities |
| 206 | + */ |
| 207 | + getUploadHandler: function(){ |
| 208 | + if( !this.uploadHandler ){ |
| 209 | + if( typeof( Firefogg ) != 'undefined' |
| 210 | + && |
| 211 | + mw.UploadWizard.config[ 'enableFirefogg' ] |
| 212 | + ) { |
| 213 | + mw.log("mw.UploadWizard::getUploadHandler> FirefoggHandler"); |
| 214 | + this.uploadHandler = new mw.FirefoggHandler( this ); |
| 215 | + } else { |
| 216 | + // By default use the apiUploadHandler |
| 217 | + mw.log("mw.UploadWizard::getUploadHandler> ApiUploadHandler"); |
| 218 | + this.uploadHandler = new mw.ApiUploadHandler( this ); |
| 219 | + } |
| 220 | + } |
| 221 | + return this.uploadHandler; |
| 222 | + }, |
| 223 | + |
| 224 | + /** |
205 | 225 | * Fetch a thumbnail for a stashed upload of the desired width. |
206 | 226 | * It is assumed you don't call this until it's been transported. |
207 | 227 | * |
— | — | @@ -262,7 +282,7 @@ |
263 | 283 | |
264 | 284 | var _this = this; |
265 | 285 | if ( typeof width === 'undefined' || width === null || width <= 0 ) { |
266 | | - width = mw.UploadWizard.config[ 'thumbnailWidth' ]; |
| 286 | + width = mw.UploadWizard.config[ 'thumbnailWidth' ]; |
267 | 287 | } |
268 | 288 | width = parseInt( width, 10 ); |
269 | 289 | height = null; |
— | — | @@ -319,38 +339,6 @@ |
320 | 340 | stepNames: [ 'tutorial', 'file', 'deeds', 'details', 'thanks' ], |
321 | 341 | currentStepName: undefined, |
322 | 342 | |
323 | | - /* |
324 | | - // list possible upload handlers in order of preference |
325 | | - // these should all be in the mw.* namespace |
326 | | - // hardcoded for now. maybe some registry system might work later, like, all |
327 | | - // things which subclass off of UploadHandler |
328 | | - uploadHandlers: [ |
329 | | - 'FirefoggUploadHandler', |
330 | | - 'XhrUploadHandler', |
331 | | - 'ApiIframeUploadHandler', |
332 | | - 'SimpleUploadHandler', |
333 | | - 'NullUploadHandler' |
334 | | - ], |
335 | | - |
336 | | - * We can use various UploadHandlers based on the browser's capabilities. Let's pick one. |
337 | | - * For example, the ApiUploadHandler should work just about everywhere, but XhrUploadHandler |
338 | | - * allows for more fine-grained upload progress |
339 | | - * @return valid JS upload handler class constructor function |
340 | | - getUploadHandlerClass: function() { |
341 | | - // return mw.MockUploadHandler; |
342 | | - return mw.ApiUploadHandler; |
343 | | - var _this = this; |
344 | | - for ( var i = 0; i < uploadHandlers.length; i++ ) { |
345 | | - var klass = mw[uploadHandlers[i]]; |
346 | | - if ( klass != undefined && klass.canRun( this.config )) { |
347 | | - return klass; |
348 | | - } |
349 | | - } |
350 | | - // this should never happen; NullUploadHandler should always work |
351 | | - return null; |
352 | | - }, |
353 | | - */ |
354 | | - |
355 | 343 | /** |
356 | 344 | * Reset the entire interface so we can upload more stuff |
357 | 345 | * Depending on whether we split uploading / detailing, it may actually always be as simple as loading a URL |
— | — | @@ -594,9 +582,13 @@ |
595 | 583 | $j( upload.ui.div ).bind( 'filenameAccepted', function(e) { _this.updateFileCounts(); e.stopPropagation(); } ); |
596 | 584 | $j( upload.ui.div ).bind( 'removeUploadEvent', function(e) { _this.removeUpload( upload ); e.stopPropagation(); } ); |
597 | 585 | $j( upload.ui.div ).bind( 'filled', function(e) { |
| 586 | + mw.log( "mw.UploadWizardUpload::newUpload> filled! received!" ); |
598 | 587 | _this.newUpload(); |
| 588 | + mw.log( "mw.UploadWizardUpload::newUpload> filled! new upload!" ); |
599 | 589 | _this.setUploadFilled(upload); |
| 590 | + mw.log( "mw.UploadWizardUpload::newUpload> filled! set upload filled!" ); |
600 | 591 | e.stopPropagation(); |
| 592 | + mw.log( "mw.UploadWizardUpload::newUpload> filled! stop propagation!" ); |
601 | 593 | } ); |
602 | 594 | // XXX bind to some error state |
603 | 595 | |
Index: branches/uploadwizard-firefogg/resources/mw.UploadWizardDetails.js |
— | — | @@ -463,6 +463,7 @@ |
464 | 464 | */ |
465 | 465 | populate: function() { |
466 | 466 | var _this = this; |
| 467 | + mw.log( "mw.UploadWizardUpload::populate> populating details from upload" ); |
467 | 468 | _this.upload.setThumbnail( _this.thumbnailDiv, mw.UploadWizard.config['thumbnailWidth'], mw.UploadWizard.config['thumbnailMaxHeight'] ); |
468 | 469 | _this.prefillDate(); |
469 | 470 | _this.prefillSource(); |
— | — | @@ -712,6 +713,7 @@ |
713 | 714 | |
714 | 715 | // XXX check state of details for okayness ( license selected, at least one desc, sane filename ) |
715 | 716 | var wikiText = _this.getWikiText(); |
| 717 | + mw.log( "mw.UploadWizardUpload::submit> submiting wikiText:\n" + wikiText ); |
716 | 718 | |
717 | 719 | var params = { |
718 | 720 | action: 'upload', |
— | — | @@ -726,7 +728,10 @@ |
727 | 729 | _this.completeDetailsSubmission(); |
728 | 730 | }; |
729 | 731 | |
| 732 | + mw.log( "mw.UploadWizardUpload::submit> uploading: \n" + params ); |
730 | 733 | var callback = function( result ) { |
| 734 | + mw.log( "mw.UploadWizardUpload::submit> result:\n" + result ); |
| 735 | + mw.log( "mw.UploadWizardUpload::submit> successful upload" ); |
731 | 736 | finalCallback( result ); |
732 | 737 | }; |
733 | 738 | |
— | — | @@ -735,6 +740,41 @@ |
736 | 741 | _this.upload.api.postWithEditToken( params, callback ); |
737 | 742 | }, |
738 | 743 | |
| 744 | + |
| 745 | + /** |
| 746 | + * Get new image info, for instance, after we renamed... or? published? an image |
| 747 | + * XXX deprecated? |
| 748 | + * XXX move to mw.API |
| 749 | + * |
| 750 | + * @param upload an UploadWizardUpload object |
| 751 | + * @param title title to look up remotely |
| 752 | + * @param endCallback execute upon completion |
| 753 | + */ |
| 754 | + getImageInfo: function( upload, callback ) { |
| 755 | + var params = { |
| 756 | + 'titles': upload.title.toString(), |
| 757 | + 'prop': 'imageinfo', |
| 758 | + 'iiprop': 'timestamp|url|user|size|sha1|mime|metadata' |
| 759 | + }; |
| 760 | + // XXX timeout callback? |
| 761 | + this.api.get( params, function( data ) { |
| 762 | + if ( data && data.query && data.query.pages ) { |
| 763 | + if ( ! data.query.pages[-1] ) { |
| 764 | + for ( var page_id in data.query.pages ) { |
| 765 | + var page = data.query.pages[ page_id ]; |
| 766 | + if ( ! page.imageinfo ) { |
| 767 | + alert("unimplemented error check, missing imageinfo"); |
| 768 | + // XXX not found? error |
| 769 | + } else { |
| 770 | + upload.extractImageInfo( page.imageinfo[0] ); |
| 771 | + } |
| 772 | + } |
| 773 | + } |
| 774 | + } |
| 775 | + callback(); |
| 776 | + } ); |
| 777 | + }, |
| 778 | + |
739 | 779 | completeDetailsSubmission: function() { |
740 | 780 | var _this = this; |
741 | 781 | _this.upload.state = 'complete'; |
Index: branches/uploadwizard-firefogg/resources/mw.ApiUploadHandler.js |
— | — | @@ -10,9 +10,9 @@ |
11 | 11 | * Represents an object which configures a form to upload its files via an iframe talking to the MediaWiki API. |
12 | 12 | * @param an UploadInterface object, which contains a .form property which points to a real HTML form in the DOM |
13 | 13 | */ |
14 | | -mw.ApiUploadHandler = function( upload, api ) { |
| 14 | +mw.ApiUploadHandler = function( upload ) { |
15 | 15 | this.upload = upload; |
16 | | - this.api = api; |
| 16 | + this.api = upload.api; |
17 | 17 | this.$form = $j( this.upload.ui.form ); |
18 | 18 | this.configureForm(); |
19 | 19 | |
— | — | @@ -39,6 +39,7 @@ |
40 | 40 | */ |
41 | 41 | configureForm: function() { |
42 | 42 | var _this = this; |
| 43 | + mw.log( "configuring form for Upload API" ); |
43 | 44 | |
44 | 45 | _this.addFormInputIfMissing( 'action', 'upload' ); |
45 | 46 | |
— | — | @@ -50,8 +51,14 @@ |
51 | 52 | |
52 | 53 | // we use JSON in HTML because according to mdale, some browsers cannot handle just JSON |
53 | 54 | _this.addFormInputIfMissing( 'format', 'jsonfm' ); |
54 | | - }, |
55 | | - |
| 55 | + |
| 56 | + // XXX only for testing, so it stops complaining about dupes |
| 57 | + /* |
| 58 | + if ( mw.UploadWizard.DEBUG ) { |
| 59 | + _this.addFormInputIfMissing( 'ignorewarnings', '1' ); |
| 60 | + } |
| 61 | + */ |
| 62 | + }, |
56 | 63 | /** |
57 | 64 | * Modify our form to have a fresh edit token. |
58 | 65 | * If successful, return true to a callback. |
— | — | @@ -85,6 +92,7 @@ |
86 | 93 | start: function() { |
87 | 94 | var _this = this; |
88 | 95 | var ok = function() { |
| 96 | + mw.log( "api: upload start!" ); |
89 | 97 | _this.beginTime = ( new Date() ).getTime(); |
90 | 98 | _this.upload.ui.setStatus( 'mwe-upwiz-transport-started' ); |
91 | 99 | _this.upload.ui.showTransportProgress(); |
Index: branches/uploadwizard-firefogg/resources/mw.IframeTransport.js |
— | — | @@ -42,20 +42,21 @@ |
43 | 43 | * Ensure callback on completion of upload |
44 | 44 | */ |
45 | 45 | configureForm: function() { |
| 46 | + mw.log( "mw.IframeTransport::configureForm> configuring form for iframe transport" ); |
46 | 47 | // Set the form target to the iframe |
47 | 48 | this.$form.attr( 'target', this.iframeId ); |
48 | 49 | |
49 | 50 | // attach an additional handler to the form, so, when submitted, it starts showing the progress |
50 | 51 | // XXX this is lame .. there should be a generic way to indicate busy status... |
51 | 52 | this.$form.submit( function() { |
52 | | - //mw.log( "mw.IframeTransport::configureForm> submitting to iframe..." ); |
| 53 | + mw.log( "mw.IframeTransport::configureForm> submitting to iframe..." ); |
53 | 54 | return true; |
54 | 55 | } ); |
55 | 56 | |
56 | 57 | // Set up the completion callback |
57 | 58 | var _this = this; |
58 | 59 | $j( '#' + this.iframeId ).load( function() { |
59 | | - //mw.log( "mw.IframeTransport::configureForm> received result in iframe" ); |
| 60 | + mw.log( "mw.IframeTransport::configureForm> received result in iframe" ); |
60 | 61 | _this.progressCb( 1.0 ); |
61 | 62 | _this.processIframeResult( $j( this ).get( 0 ) ); |
62 | 63 | } ); |
— | — | @@ -72,13 +73,13 @@ |
73 | 74 | var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document; |
74 | 75 | // Fix for Opera 9.26 |
75 | 76 | if ( doc.readyState && doc.readyState != 'complete' ) { |
76 | | - //mw.log( "mw.IframeTransport::processIframeResult> not complete" ); |
| 77 | + mw.log( "mw.IframeTransport::processIframeResult> not complete" ); |
77 | 78 | return; |
78 | 79 | } |
79 | 80 | |
80 | 81 | // Fix for Opera 9.64 |
81 | 82 | if ( doc.body && doc.body.innerHTML == "false" ) { |
82 | | - //mw.log( "mw.IframeTransport::processIframeResult> innerhtml" ); |
| 83 | + mw.log( "mw.IframeTransport::processIframeResult> innerhtml" ); |
83 | 84 | return; |
84 | 85 | } |
85 | 86 | var response; |
— | — | @@ -91,7 +92,7 @@ |
92 | 93 | // according to mdale we need to do this |
93 | 94 | // because IE does not load JSON properly in an iframe |
94 | 95 | json = $j( doc.body ).find( 'pre' ).text(); |
95 | | - // mw.log( "mw.IframeTransport::processIframeResult> iframe:json::" + json ); |
| 96 | + mw.log( "mw.IframeTransport::processIframeResult> iframe:json::" + json ); |
96 | 97 | // check that the JSON is not an XML error message |
97 | 98 | // (this happens when user aborts upload, we get the API docs in XML wrapped in HTML) |
98 | 99 | if ( json && json.substring(0, 5) !== '<?xml' ) { |
Index: branches/uploadwizard-firefogg/resources/mw.Log.js |
— | — | @@ -2,43 +2,43 @@ |
3 | 3 | |
4 | 4 | ( function( mw, $j ) { |
5 | 5 | |
6 | | - function pad( d, n ) { |
7 | | - var s = d.toString(); return s.length == n ? s : pad( '0' + s, n ); |
8 | | - } |
9 | | - |
10 | 6 | /** |
11 | | - * Log a string msg to the console |
12 | | - * |
13 | | - * @param {String} string String to output to console |
14 | | - */ |
| 7 | + * Log a string msg to the console |
| 8 | + * |
| 9 | + * @param {String} string String to output to console |
| 10 | + */ |
15 | 11 | mw.log = function( s, level ) { |
16 | 12 | |
17 | 13 | if ( typeof level === 'undefined' ) { |
18 | | - level = mw.log.INFO; |
| 14 | + level = 30; |
19 | 15 | } |
20 | 16 | |
21 | 17 | if ( level > mw.log.level ) { |
22 | 18 | return; |
23 | 19 | } |
| 20 | + |
| 21 | + // Add any prepend debug ss if necessary |
| 22 | + if ( mw.log.preAppendLog ) { |
| 23 | + s = mw.log.preAppendLog + s; |
| 24 | + } |
24 | 25 | |
25 | 26 | if ( typeof window.console !== 'undefined' && typeof window.console.log === 'function' ) { |
26 | 27 | window.console.log( s ); |
27 | 28 | } else { |
28 | | - // Set timestamp |
29 | | - var d = new Date(); |
30 | | - var time = ( pad( d.getHours(), 2 ) + ':' + pad( d.getMinutes(), 2 ) + pad( d.getSeconds(), 2 ) + pad( d.getMilliseconds(), 3 ) ); |
| 29 | +/* |
31 | 30 | // Show a log box for console-less browsers |
32 | 31 | var $log = $( '#mw-log-console' ); |
33 | 32 | if ( !$log.length ) { |
34 | 33 | $log = $( '<div id="mw-log-console"></div>' ) |
35 | 34 | .css( { |
36 | | - 'position': 'fixed', |
| 35 | + 'position': 'absolute', |
37 | 36 | 'overflow': 'auto', |
38 | 37 | 'z-index': 500, |
39 | 38 | 'bottom': '0px', |
40 | 39 | 'left': '0px', |
41 | 40 | 'right': '0px', |
42 | | - 'height': '150px', |
| 41 | + 'height': '100px', |
| 42 | + 'width': '100%', |
43 | 43 | 'background-color': 'white', |
44 | 44 | 'border-top': 'solid 2px #ADADAD' |
45 | 45 | } ) |
— | — | @@ -52,22 +52,13 @@ |
53 | 53 | 'font-family': 'monospace', |
54 | 54 | 'padding': '0.125em 0.25em' |
55 | 55 | } ) |
56 | | - .text( string ) |
57 | | - .append( '<span style="float:right">[' + time + ']</span>' ) |
| 56 | + .text( s ) |
58 | 57 | ); |
| 58 | +*/ |
59 | 59 | } |
60 | 60 | }; |
61 | 61 | |
62 | | - /** |
63 | | - * Convenience function for logging cases where you want a prefix, or to log at a particular level. |
64 | | - */ |
65 | | - mw.log.logger = function( prefix, level ) { |
66 | | - return function( s ) { |
67 | | - mw.log( prefix + '> ' + s, level ); |
68 | | - } |
69 | | - }; |
70 | | - |
71 | | - mw.log.SILENT = 0; |
| 62 | + mw.log.level = mw.log.NONE = 0; |
72 | 63 | mw.log.FATAL = 10; |
73 | 64 | mw.log.WARN = 20; |
74 | 65 | mw.log.INFO = 30; |
— | — | @@ -82,7 +73,6 @@ |
83 | 74 | mw.log.info = function( s ) { |
84 | 75 | mw.log( s, mw.log.INFO ); |
85 | 76 | }; |
86 | | - |
87 | 77 | mw.log.level = mw.log.ALL; |
88 | 78 | |
89 | 79 | } )( window.mediaWiki, jQuery ); |