r91656 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r91655‎ | r91656 | r91657 >
Date:17:36, 7 July 2011
Author:neilk
Status:resolved (Comments)
Tags:
Comment:
untangling upload interface & upload logic code -- upload controls filename acceptability, interface controls getting the preview
Modified paths:
  • /trunk/extensions/UploadWizard/UploadWizard.i18n.php (modified) (history)
  • /trunk/extensions/UploadWizard/resources/mw.UploadWizard.js (modified) (history)
  • /trunk/extensions/UploadWizard/resources/mw.UploadWizardUploadInterface.js (modified) (history)

Diff [purge]

Index: trunk/extensions/UploadWizard/UploadWizard.i18n.php
@@ -132,6 +132,7 @@
133133 'mwe-upwiz-help-allowed-filename-extensions' => 'Allowed filename extensions',
134134 'mwe-upwiz-upload-error-duplicate' => 'This file was previously uploaded to this wiki.',
135135 'mwe-upwiz-upload-error-stashed-anyway' => 'Upload anyway?',
 136+ 'mwe-upwiz-upload-error-unknown-filename-error' => 'We could not read or understand the filename "$1" for unknown reasons.',
136137 'mwe-upwiz-ok' => 'OK',
137138 'mwe-upwiz-cancel' => 'Cancel',
138139 'mwe-upwiz-fileexists-replace' => 'A file with the title "$1" exists already. Please change your title to something unique.',
Index: trunk/extensions/UploadWizard/resources/mw.UploadWizardUploadInterface.js
@@ -14,15 +14,10 @@
1515 _this.div = $j('<div class="mwe-upwiz-file"></div>').get(0);
1616 _this.isFilled = false;
1717
18 - _this.$fileInputCtrl = $j('<input size="1" class="mwe-upwiz-file-input" name="file" type="file"/>')
19 - .change( function() {
20 - _this.clearErrors();
21 - _this.upload.extractLocalFileInfo(
22 - this, // the file input
23 - function() { _this.fileChanged(); }
24 - );
25 - } );
 18+ _this.$fileInputCtrl = $j('<input size="1" class="mwe-upwiz-file-input" name="file" type="file"/>');
2619
 20+ _this.initFileInputCtrl();
 21+
2722 _this.$indicator = $j( '<div class="mwe-upwiz-file-indicator"></div>' );
2823
2924 visibleFilenameDiv = $j('<div class="mwe-upwiz-visible-file"></div>')
@@ -225,61 +220,138 @@
226221 this.setStatus( msgKey, args );
227222 },
228223
 224+
 225+ initFileInputCtrl: function() {
 226+ var _this = this;
 227+ this.$fileInputCtrl.change( function() {
 228+ _this.clearErrors();
 229+ _this.upload.checkFile(
 230+ this, // the file input
 231+ function() { _this.fileChangedOk(); },
 232+ function( code, info ) { _this.fileChangedError( code, info ); }
 233+ );
 234+ } );
 235+ },
 236+
 237+
229238 /**
230 - * Run this when the value of the file input has changed. Check the file for various forms of goodness.
231 - * If okay, then update the visible filename (due to CSS trickery the real file input is invisible)
 239+ * Run this when the value of the file input has changed and we know it's acceptable -- this
 240+ * will update interface to show as much info as possible, including preview.
 241+ * n.b. in older browsers we only will know the filename
232242 */
233 - fileChanged: function() {
 243+ fileChangedOk: function() {
234244 var _this = this;
235 - var extension = _this.upload.title.getExtension();
236 - var hasExtension = ! mw.isEmpty( extension );
 245+ _this.updateFilename();
237246
238 - /* this should not be in the interface */
239 - var isGoodExtension = false;
240 - if ( hasExtension ) {
241 - isGoodExtension = $j.inArray( extension.toLowerCase(), mw.UploadWizard.config[ 'fileExtensions' ] ) !== -1;
 247+ // set the status string - e.g. "256 Kb, 100 x 200"
 248+ var statusItems = [];
 249+ if ( this.upload.imageinfo && this.upload.imageinfo.width && this.upload.imageinfo.height ) {
 250+ statusItems.push( this.upload.imageinfo.width + '\u00d7' + this.upload.imageinfo.height );
242251 }
243 - if ( hasExtension && isGoodExtension ) {
244 - _this.updateFilename();
245 - } else {
246 - var $errorMessage;
247 - // Check if firefogg should be recommended to be installed ( user selects an extension that can be converted)
248 - if( mw.UploadWizard.config['enableFirefogg']
249 - &&
250 - $j.inArray( extension.toLowerCase(), mw.UploadWizard.config['transcodeExtensionList'] ) !== -1
251 - ){
252 - $errorMessage = $j( '<p>' ).msg('mwe-upwiz-upload-error-bad-extension-video-firefogg',
253 - mw.Firefogg.getFirefoggInstallUrl(),
254 - 'http://commons.wikimedia.org/wiki/Help:Converting_video'
255 - );
256 -
257 - } else {
258 - var errorKey = hasExtension ? 'mwe-upwiz-upload-error-bad-filename-extension' : 'mwe-upwiz-upload-error-bad-filename-no-extension';
259 - $errorMessage = $j( '<p>' ).msg( errorKey, extension );
260 - }
261 - $( '<div></div>' )
262 - .append(
263 - $errorMessage,
264 - $j( '<p>' ).msg( 'mwe-upwiz-allowed-filename-extensions' ),
265 - $j( '<blockquote>' ).append( $j( '<tt>' ).append(
266 - mw.UploadWizard.config[ 'fileExtensions' ].join( " " )
267 - ) )
268 - )
269 - .dialog({
270 - width: 500,
271 - zIndex: 200000,
272 - autoOpen: true,
273 - title: gM( 'mwe-upwiz-help-popup' ) + ': ' + gM( 'mwe-upwiz-help-allowed-filename-extensions' ),
274 - modal: true
275 - });
 252+ if ( this.upload.file ) {
 253+ statusItems.push( mw.units.bytes( this.upload.file.size ) );
276254 }
 255+
 256+ this.clearStatus();
 257+ this.setStatusString( statusItems.join( ' \u00b7 ' ) );
277258
278 - this.clearStatus();
279 - if ( this.upload.file ) {
280 - this.setStatusString( mw.units.bytes( this.upload.file.size ) );
 259+ // do preview if we can
 260+ if ( mw.fileApi.isAvailable() && _this.upload.file && mw.fileApi.isPreviewableFile( _this.upload.file ) ) {
 261+ var dataUrlReader = new FileReader();
 262+ dataUrlReader.onload = function() {
 263+ var image = document.createElement( 'img' );
 264+ image.onload = function() {
 265+ $.publishReady( 'thumbnails.' + _this.upload.index, image );
 266+ };
 267+ image.src = dataUrlReader.result;
 268+ _this.upload.thumbnails['*'] = image;
 269+ };
 270+ dataUrlReader.readAsDataURL( _this.upload.file );
281271 }
 272+
282273 },
283274
 275+ fileChangedError: function( code, info ) {
 276+ var filename = this.$fileInputCtrl.value;
 277+
 278+ // ok we now have a fileInputCtrl with a "bad" file in it
 279+ // you cannot blank a file input ctrl in all browsers, so we
 280+ // replace existing file input with empty clone
 281+ var $newFileInput = this.$fileInputCtrl.clone();
 282+ this.$fileInputCtrl.replaceWith( $newFileInput );
 283+ this.$fileInputCtrl = $newFileInput;
 284+ this.initFileInputCtrl();
 285+
 286+ if ( code === 'ext' ) {
 287+ this.showBadExtensionError( filename, info );
 288+ } else if ( code === 'noext' ) {
 289+ this.showMissingExtensionError( filename );
 290+ } else if ( code === 'dup' ) {
 291+ this.showDuplicateError( filename );
 292+ } else if ( code === 'unparseable' ) {
 293+ this.showUnparseableFilenameError( filename );
 294+ } else {
 295+ this.showUnknownError( code, filename );
 296+ }
 297+ },
 298+
 299+ showUnparseableFilenameError: function( filename ) {
 300+ this.showFilenameError( gM( 'mwe-upwiz-unparseable-filename', filename ) );
 301+ },
 302+
 303+ showBadExtensionError: function( filename, extension ) {
 304+ var $errorMessage;
 305+ // Check if firefogg should be recommended to be installed ( user selects an extension that can be converted)
 306+ if ( mw.UploadWizard.config['enableFirefogg']
 307+ &&
 308+ $j.inArray( extension.toLowerCase(), mw.UploadWizard.config['transcodeExtensionList'] ) !== -1
 309+ ) {
 310+ $errorMessage = $j( '<p>' ).msg('mwe-upwiz-upload-error-bad-extension-video-firefogg',
 311+ mw.Firefogg.getFirefoggInstallUrl(),
 312+ 'http://commons.wikimedia.org/wiki/Help:Converting_video'
 313+ );
 314+ } else {
 315+ $errorMessage = $j( '<p>' ).msg( 'mwe-upwiz-upload-error-bad-filename-extension', extension );
 316+ }
 317+ this.showFilenameError( $errorMessage );
 318+ },
 319+
 320+ showMissingExtensionError: function( filename ) {
 321+ this.showExtensionError( $j( '<p>' ).msg( 'mwe-upwiz-upload-error-bad-filename-no-extension' ) );
 322+ },
 323+
 324+ showUnknownFilenameError: function( filename ) {
 325+ this.showFilenameError( $j( '<p>' ).msg( 'mwe-upwiz-upload-error-unknown-filename-error', filename ) );
 326+ },
 327+
 328+ showExtensionError: function( $errorMessage ) {
 329+ this.showFilenameError(
 330+ $( '<div></div>' ).append(
 331+ $errorMessage,
 332+ $j( '<p>' ).msg( 'mwe-upwiz-allowed-filename-extensions' ),
 333+ $j( '<blockquote>' ).append( $j( '<tt>' ).append(
 334+ mw.UploadWizard.config[ 'fileExtensions' ].join( " " )
 335+ ) )
 336+ )
 337+ );
 338+ },
 339+
 340+ showDuplicateError: function() {
 341+ // to be implemented
 342+ },
 343+
 344+ showFilenameError: function( $text ) {
 345+ $( '<div>' )
 346+ .append( $text )
 347+ .dialog({
 348+ width: 500,
 349+ zIndex: 200000,
 350+ autoOpen: true,
 351+ modal: true
 352+ });
 353+ },
 354+
 355+
284356 /**
285357 * Move the file input to cover a certain element on the page.
286358 * We use invisible file inputs because this is the only way to style a file input
@@ -330,30 +402,13 @@
331403 // visible filename
332404 $j( _this.form ).find( '.mwe-upwiz-visible-file-filename-text' ).html( path );
333405
334 - var filename = mw.UploadWizardUtil.getBasename( path );
335 - try {
336 - _this.upload.title = new mw.Title( filename, 'file' );
337 - } catch ( e ) {
338 - $( '<div>' )
339 - .msg( 'mwe-upwiz-unparseable-filename', filename )
340 - .dialog({
341 - width: 500,
342 - zIndex: 200000,
343 - autoOpen: true,
344 - modal: true
345 - });
346 - _this.$fileInputCtrl.val();
347 - return;
348 - }
349 -
350406 // Set the filename we tell to the API to be the current timestamp + the filename
351407 // This is because we don't actually care what the filename is at this point, we just want it to be unique for this session and have the
352408 // proper file extension.
353409 // Also, it avoids a problem -- the API only returns one error at a time and it thinks that the same-filename error is more important than same-content.
354410 // But for UploadWizard, at this stage, it's the reverse. We want to stop same-content dead, but for now we ignore same-filename
355 - $j( _this.filenameCtrl ).val( ( new Date() ).getTime().toString() +_this.upload.title.getMain() );
 411+ $j( _this.filenameCtrl ).val( ( new Date() ).getTime().toString() + path );
356412
357 -
358413 // deal with styling the file inputs and making it react to mouse
359414 if ( ! _this.isFilled ) {
360415 var $div = $j( _this.div );
Index: trunk/extensions/UploadWizard/resources/mw.UploadWizard.js
@@ -252,97 +252,99 @@
253253 },
254254
255255 /**
256 - * Called when the file is entered into the file input
257 - * Get as much data as possible with this browser, including thumbnail.
258 - * TODO exif
 256+ * Called when the file is entered into the file input.
 257+ * Error out if filename or its contents are determined to be unacceptable
 258+ * Proceed to thumbnail extraction and image info if acceptable
259259 * @param {HTMLFileInput} file input field
260 - * @param {Function} callback when ready
 260+ * @param {Function()} callback when ok, and upload object is ready
 261+ * @param {Function(String, Mixed)} callback when filename or contents in error. Signature of string code, mixed info
261262 */
262 - extractLocalFileInfo: function( fileInput, callback ) {
 263+ checkFile: function( fileInput, fileNameOk, fileNameErr ) {
 264+ // check if local file is acceptable
 265+
263266 var _this = this;
264 - if ( mw.fileApi.isAvailable() ) {
265 - if ( fileInput.files && fileInput.files.length ) {
266 - // TODO multiple files in an input
267 - this.file = fileInput.files[0];
268 - }
269 - // TODO check max upload size, alert user if too big
270 - this.transportWeight = this.file.size;
 267+
 268+ // TODO check if filename has been used already in this wizard
271269
272 - if ( mw.fileApi.isPreviewableFile( this.file ) ) {
273 - /*
274 - * The following part is a bit tricky, but not easy to untangle in code
275 - * First, we will read the file as binary
276 - * in the binary reader's onload function
277 - * we try to get metadata with jpegmeta library, and add it to the upload object
278 - * we re-read the file as a data URL
279 - * in that file reader's onload function
280 - * assign it to an image
281 - * in that image's onload function
282 - * publish the event, that this upload can now do thumbnails, with the image itself
283 - * (listeners will then use that image to create thumbnails in the DOM,
284 - * with local scaling or canvas)
285 - */
286 -
287 - var image = document.createElement( 'img' );
288 - image.onload = function() {
289 - $.publishReady( 'thumbnails.' + _this.index, image );
290 - };
291 -
292 - var binReader = new FileReader();
293 - binReader.onload = function() {
294 - var meta;
295 - try {
296 - meta = mw.libs.jpegmeta( binReader.result, _this.file.fileName );
297 - meta._binary_data = null;
298 - } catch ( e ) {
299 - meta = null;
300 - }
301 - _this.extractMetadataFromJpegMeta( meta );
302 -
303 - var dataUrlReader = new FileReader();
304 - dataUrlReader.onload = function() {
305 - image.src = dataUrlReader.result;
306 - _this.thumbnails['*'] = image;
307 - };
308 - dataUrlReader.readAsDataURL( _this.file );
309 - };
310 - binReader.readAsBinaryString( _this.file );
311 - }
312 - }
 270+ // Check if filename is acceptable
313271 // TODO sanitize filename
314272 var filename = fileInput.value;
315273 try {
316274 this.title = new mw.Title( mw.UploadWizardUtil.getBasename( filename ).replace( /:/g, '_' ), 'file' );
317275 } catch ( e ) {
318 - this.setError( 'mwe-upwiz-unparseable-filename', filename );
 276+ fileNameErr( 'unparseable' );
319277 }
320 - if ( this.title ) {
321 - callback();
 278+
 279+ // Check if extension is acceptable
 280+ var extension = this.title.getExtension();
 281+ if ( mw.isEmpty( extension ) ) {
 282+ fileNameErr( 'noext' );
 283+ } else {
 284+ if ( $j.inArray( extension.toLowerCase(), mw.UploadWizard.config[ 'fileExtensions' ] ) === -1 ) {
 285+ fileNameErr( 'ext', extension );
 286+ } else {
 287+
 288+ // extract more info via fileAPI
 289+ if ( mw.fileApi.isAvailable() ) {
 290+ if ( fileInput.files && fileInput.files.length ) {
 291+ // TODO multiple files in an input
 292+ this.file = fileInput.files[0];
 293+ }
 294+ // TODO check max upload size, alert user if too big
 295+ this.transportWeight = this.file.size;
 296+ if ( !mw.isDefined( this.imageinfo ) ) {
 297+ this.imageinfo = {};
 298+ }
 299+
 300+ var binReader = new FileReader();
 301+ binReader.onload = function() {
 302+ var meta;
 303+ try {
 304+ meta = mw.libs.jpegmeta( binReader.result, _this.file.fileName );
 305+ meta._binary_data = null;
 306+ } catch ( e ) {
 307+ meta = null;
 308+ }
 309+ _this.extractMetadataFromJpegMeta( meta );
 310+ fileNameOk();
 311+ };
 312+ binReader.readAsBinaryString( _this.file );
 313+ } else {
 314+ fileChangedOk();
 315+ }
 316+
 317+ }
 318+
322319 }
 320+
323321 },
324322
 323+
325324
 325+
326326 /**
327327 * Map fields from jpegmeta's metadata return into our format (which is more like the imageinfo returned from the API
328328 * @param {Object} (as returned by jpegmeta)
329329 */
330330 extractMetadataFromJpegMeta: function( meta ) {
331 - if ( !mw.isDefined( this.imageinfo ) ) {
332 - this.imageinfo = {};
333 - }
334 - if ( !mw.isDefined( this.imageinfo.metadata ) ) {
335 - this.imageinfo.metadata = {};
336 - }
337 - if ( meta.tiff && meta.tiff.Orientation ) {
338 - this.imageinfo.metadata.orientation = meta.tiff.Orientation.value;
339 - }
340 - if ( meta.general ) {
341 - if ( meta.general.pixelHeight ) {
342 - this.imageinfo.height = meta.general.pixelHeight.value;
 331+ if ( mw.isDefined( meta ) && meta !== null && typeof meta === 'object' ) {
 332+ if ( !mw.isDefined( this.imageinfo ) ) {
 333+ this.imageinfo = {};
343334 }
344 - if ( meta.general.pixelWidth ) {
345 - this.imageinfo.width = meta.general.pixelWidth.value;
 335+ if ( !mw.isDefined( this.imageinfo.metadata ) ) {
 336+ this.imageinfo.metadata = {};
346337 }
 338+ if ( meta.tiff && meta.tiff.Orientation ) {
 339+ this.imageinfo.metadata.orientation = meta.tiff.Orientation.value;
 340+ }
 341+ if ( meta.general ) {
 342+ if ( meta.general.pixelHeight ) {
 343+ this.imageinfo.height = meta.general.pixelHeight.value;
 344+ }
 345+ if ( meta.general.pixelWidth ) {
 346+ this.imageinfo.width = meta.general.pixelWidth.value;
 347+ }
 348+ }
347349 }
348350 },
349351
@@ -889,6 +891,7 @@
890892 return fileUrl;
891893 }
892894
 895+
893896 };
894897
895898

Comments

#Comment by Catrope (talk | contribs)   08:04, 20 August 2011
-					title: gM( 'mwe-upwiz-help-popup' ) + ': ' + gM( 'mwe-upwiz-help-allowed-filename-extensions' ),

Dialog title has disappeared, is that intentional?

+					fileChangedOk();

Should be fileNameOk(), already fixed in r91694.

Status & tagging log