Jdlrobson has uploaded a new change for review.
https://gerrit.wikimedia.org/r/53769
Change subject: Story 347: Provide nicer filenames
......................................................................
Story 347: Provide nicer filenames
Filenames are descriptions with date appended accurate to minutes
Change-Id: I8b5f2a78b9f73a23abc505ac424ab3926b81bf6d
---
M MobileFrontend.i18n.php
M MobileFrontend.php
M javascripts/modules/mf-photo.js
M tests/js/test_mf-photo.js
4 files changed, 122 insertions(+), 13 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend
refs/changes/69/53769/1
diff --git a/MobileFrontend.i18n.php b/MobileFrontend.i18n.php
index 0b3be89..792e2fc 100644
--- a/MobileFrontend.i18n.php
+++ b/MobileFrontend.i18n.php
@@ -233,6 +233,7 @@
'mobile-frontend-image-uploading-long' => 'Image still uploading!
Thanks for your patience.',
'mobile-frontend-image-uploading-cancel' => '<a href="#">Cancel</a> if
this is taking too long.',
'mobile-frontend-photo-upload-error' => 'Error, try again.',
+ 'mobile-frontend-photo-upload-error-filename' => 'Error, please provide
a more descriptive summary.',
'mobile-frontend-photo-upload-success-article' => 'Success! Your image
is now live on this page.',
'mobile-frontend-photo-license' => 'By clicking "Submit", you agree to
our [//wikimediafoundation.org/wiki/Terms_of_use Terms of Use] and agree to
release your photo under the [//creativecommons.org/licenses/by-sa/3.0/
Creative Commons Attribution-ShareAlike 3.0 License].',
'mobile-frontend-photo-submit' => 'Submit',
@@ -577,6 +578,7 @@
'mobile-frontend-image-uploading-long' => 'Text that displays whilst an
image is taking long to upload',
'mobile-frontend-image-uploading-cancel' => 'Text saying that user can
cancel the image upload. Word "cancel" should be a link.',
'mobile-frontend-photo-upload-error' => 'Text that displays when a
photo fails to upload',
+ 'mobile-frontend-photo-upload-error-filename' => 'Text that displays
when a photo fails to upload due to filename',
'mobile-frontend-photo-upload-success-article' => 'Text that displays
when a photo has been successfully added to a page.',
'mobile-frontend-photo-license' => 'Text notifying user of license that
image will be published under. You can change the URL to a "local" Wikipedia
URL, but you cannot make it point to the country specific CC BY-SA 3.0
license.',
'mobile-frontend-photo-submit' => 'Caption for the submit button on the
photo uplaod form.
diff --git a/MobileFrontend.php b/MobileFrontend.php
index 573a344..7bef703 100644
--- a/MobileFrontend.php
+++ b/MobileFrontend.php
@@ -378,6 +378,7 @@
'mobile-frontend-photo-article-edit-comment',
'mobile-frontend-photo-article-donate-comment',
'mobile-frontend-photo-upload-error',
+ 'mobile-frontend-photo-upload-error-filename',
'mobile-frontend-photo-upload-success-article',
'mobile-frontend-photo-caption-placeholder',
'mobile-frontend-image-loading',
diff --git a/javascripts/modules/mf-photo.js b/javascripts/modules/mf-photo.js
index 1c4071e..1c91dbd 100644
--- a/javascripts/modules/mf-photo.js
+++ b/javascripts/modules/mf-photo.js
@@ -52,15 +52,75 @@
};
}
- function generateFileName( file, pageTitle ) {
- // FIXME: deal with long and invalid names
- var name = 'Lead_Photo_For_' + pageTitle.replace( / /g, '_' ) +
Math.random(),
- extension;
+ // Originally written by Brion for WikiLovesMonuments app
+ function trimUtf8String( str, allowedLength ) {
+ // Count UTF-8 bytes to see where we need to crop long names.
+ var bytes = 0, chars = 0, codeUnit, len, i;
- name = name.replace( String.fromCharCode( 27 ), '-' );
- name = name.replace( /[\x7f\.\[#<>\[\]\|\{\}\/:]/g, '-' );
- extension = file.name.slice( file.name.lastIndexOf( '.' ) + 1 );
- return name + '.' + extension;
+ for ( i = 0; i < str.length; i++ ) {
+ // JavaScript strings are UTF-16.
+ codeUnit = str.charCodeAt( i );
+
+ // http://en.wikipedia.org/wiki/UTF-8#Description
+ if ( codeUnit < 0x80 ) {
+ len = 1;
+ } else if ( codeUnit < 0x800 ) {
+ len = 2;
+ } else if ( codeUnit >= 0xd800 && codeUnit < 0xe000 ) {
+ //
http://en.wikipedia.org/wiki/UTF-16#Description
+ // Code point is one half of a surrogate pair.
+ // This and its partner combine to form a
single 4 byte character in UTF-8.
+ len = 4;
+ } else {
+ len = 3;
+ }
+
+ if ( bytes + len <= allowedLength ) {
+ bytes += len;
+ chars++;
+ if ( len === 4 ) {
+ // Skip over second half of surrogate
pair as a unit.
+ chars++;
+ i++;
+ }
+ } else {
+ // Ran out of bytes.
+ return str.substr( 0, chars );
+ }
+ }
+
+ // We fit!
+ return str;
+ }
+
+ /**
+ * Generates a file name from a description and a date
+ * Removes illegal characters
+ * Respects maximum file name length (240 bytes)
+ *
+ * @param {String} description Data to be preprocessed and added to
options
+ * @param {Date} date An optional date (defaults to current date)
+ * @return {String} a legal filename
+ */
+ function generateFileName( description, date ) {
+ var allowedLength = 240, // 240 bytes maximum enforced by
MediaWiki
+ delimiter = ' ', name, suffix;
+
+ date = date || new Date();
+ name = description.replace( String.fromCharCode( 27 ),
delimiter );
+ name = name.replace( /[\x7f\.\[#<>\[\]\|\{\}\/:]/g, delimiter );
+
+ function pad( number ) {
+ return number < 9 ? '0' + number : number;
+ }
+
+ // FIXME: should we really assume jpg?
+ suffix = delimiter + date.getFullYear() + delimiter +
+ pad( date.getMonth() + 1 ) + delimiter + pad(
date.getDate() ) + delimiter +
+ pad( date.getHours() ) + delimiter + pad(
date.getMinutes() ) + '.jpg';
+
+ allowedLength = allowedLength - suffix.length;
+ return trimUtf8String( name, allowedLength ) + suffix;
}
PhotoApi = Api.extend( {
@@ -86,9 +146,9 @@
function doUpload( token ) {
var formData = new FormData(), descTextToAppend;
- options.fileName = generateFileName(
options.file, options.pageTitle );
descTextToAppend = mw.config.get(
'wgPhotoUploadAppendToDesc' );
descTextToAppend = descTextToAppend ? '\n\n' +
descTextToAppend : '';
+ options.fileName = generateFileName(
options.description );
formData.append( 'action', 'upload' );
formData.append( 'format', 'json' );
@@ -119,13 +179,22 @@
self.emit( 'progress',
ev.loaded / ev.total );
}
} ).done( function( data ) {
- var descriptionUrl = '';
+ var descriptionUrl = '',
+ warnings = data.upload ?
data.upload.warnings : false;
if ( !data || !data.upload ) {
// error uploading image
result.reject( data.error ?
data.error.info : '' );
return;
}
- options.fileName = data.upload.filename
|| data.upload.warnings.duplicate['0'];
+ options.fileName = data.upload.filename;
+ if ( warnings ) {
+ if ( warnings.duplicate ) {
+ options.fileName =
warnings.duplicate[ '0' ];
+ } else if ( warnings.exists ) {
+ return result.reject(
'Filename exists',
+ mw.msg(
'mobile-frontend-photo-upload-error-filename' ) );
+ }
+ }
// FIXME: API doesn't return this
information on duplicate images...
if ( data.upload.imageinfo ) {
descriptionUrl =
data.upload.imageinfo.descriptionurl;
@@ -396,8 +465,8 @@
descriptionUrl: descriptionUrl,
url: self.preview.imageUrl
} );
- } ).fail( function( err ) {
- popup.show( mw.msg(
'mobile-frontend-photo-upload-error' ), 'toast error' );
+ } ).fail( function( err, msg ) {
+ popup.show( msg || mw.msg(
'mobile-frontend-photo-upload-error' ), 'toast error' );
self.log( { action: 'error', errorText: err } );
self.emit( 'error' );
} );
@@ -454,8 +523,10 @@
}
M.define( 'photo', {
+ generateFileName: generateFileName,
isSupported: isSupported,
PhotoUploader: PhotoUploader,
+ trimUtf8String: trimUtf8String,
// just for testing
_needsPhoto: needsPhoto,
_PhotoUploadProgress: PhotoUploadProgress
diff --git a/tests/js/test_mf-photo.js b/tests/js/test_mf-photo.js
index 05aec3a..df8d348 100644
--- a/tests/js/test_mf-photo.js
+++ b/tests/js/test_mf-photo.js
@@ -63,4 +63,39 @@
);
} );
+test( 'generateFileName', function() {
+ var date = new Date( 2010, 9, 15, 12, 51 ),
+ name = photo.generateFileName( 'Jon eating bacon next to an
armadillo', date );
+ strictEqual( name, 'Jon eating bacon next to an armadillo 2010 10 15 12
51.jpg',
+ 'Check file name is description with appended date' );
+} );
+
+test( 'generateFileName test padding', function() {
+ var date = new Date( 2013, 2, 1, 12, 51 ), // note 0 = january
+ name = photo.generateFileName( 'Tomasz eating bacon next to a
dinosaur', date );
+ strictEqual( name, 'Tomasz eating bacon next to a dinosaur 2013 03 01
12 51.jpg',
+ 'Check file name is description with appended date and numbers
were padded' );
+} );
+
+test( 'generateFileName long line', function() {
+ var i,
+ longDescription = '',
+ date = new Date( 2013, 2, 1, 12, 51 ), name;
+
+ for ( i=0; i < 240; i++ ) {
+ longDescription += 'a';
+ }
+ name = photo.generateFileName( longDescription, date );
+ strictEqual( name.length, 240, 'Check file name was shortened to the
minimum length' );
+ strictEqual( name.substr( 233, 7 ), ' 51.jpg', 'ends with date' );
+} );
+
+
+test( 'trimUtf8String', function() {
+ strictEqual( photo.trimUtf8String( 'Just a string', 20 ), 'Just a
string', 'ascii string fits' );
+ strictEqual( photo.trimUtf8String( 'Just a string', 10 ), 'Just a str',
'ascii string truncated' );
+ strictEqual( photo.trimUtf8String( 'Júst á stríng', 10 ), 'Júst á s',
'latin1 string truncated' );
+ strictEqual( photo.trimUtf8String( 'こんにちは', 10 ), 'こんに', 'CJK string
truncated' );
+} );
+
}( jQuery, mw.mobileFrontend ) );
--
To view, visit https://gerrit.wikimedia.org/r/53769
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8b5f2a78b9f73a23abc505ac424ab3926b81bf6d
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Jdlrobson <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits