* Note that additional code still lives in skins/common/upload.js
*/
+/**
+ * Add a preview to the upload form
+ */
jQuery( function( $ ) {
/**
* Is the FileAPI available with sufficient functionality?
* Also excludes files over 10M to avoid going insane on memory usage.
*
* @todo is there a way we can ask the browser what's supported in <img>s?
+ * @todo put SVG back after working around Firefox 7 bug <https://bugzilla.wikimedia.org/show_bug.cgi?id=31643>
*
* @param {File} file
* @return boolean
var previewSize = 180,
thumb = $( '<div id="mw-upload-thumbnail" class="thumb tright">' +
'<div class="thumbinner">' +
- '<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>' +
+ '<div class="mw-small-spinner" style="width: 180px; height: 180px"></div>' +
'<div class="thumbcaption"><div class="filename"></div><div class="fileinfo"></div></div>' +
'</div>' +
'</div>' );
thumb.find( '.filename' ).text( file.name ).end()
.find( '.fileinfo' ).text( prettySize( file.size ) ).end();
-
- var ctx = thumb.find( 'canvas' )[0].getContext( '2d' ),
- spinner = new Image();
- spinner.onload = function() {
- ctx.drawImage( spinner, (previewSize - spinner.width) / 2,
- (previewSize - spinner.height) / 2 );
- };
- spinner.src = mw.config.get( 'wgScriptPath' ) + '/skins/common/images/spinner.gif';
+
+ var $canvas = $('<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>'),
+ ctx = $canvas[0].getContext( '2d' );
$( '#mw-htmlform-source' ).parent().prepend( thumb );
var meta;
fetchPreview( file, function( dataURL ) {
var img = new Image(),
rotation = 0;
-
+
if ( meta && meta.tiff && meta.tiff.Orientation ) {
rotation = (360 - function () {
// See includes/media/Bitmap.php
}
}() ) % 360;
}
-
+
img.onload = function() {
+ var width, height, x, y, dx, dy, logicalWidth, logicalHeight;
// Fit the image within the previewSizexpreviewSize box
if ( img.width > img.height ) {
width = previewSize;
dy = (180 - height) / 2;
switch ( rotation ) {
// If a rotation is applied, the direction of the axis
- // changes as well. You can derive the values below by
+ // changes as well. You can derive the values below by
// drawing on paper an axis system, rotate it and see
// where the positive axis direction is
case 0:
x = dx;
y = dy;
+ logicalWidth = img.width;
+ logicalHeight = img.height;
break;
case 90:
-
+
x = dx;
y = dy - previewSize;
+ logicalWidth = img.height;
+ logicalHeight = img.width;
break;
case 180:
x = dx - previewSize;
y = dy - previewSize;
+ logicalWidth = img.width;
+ logicalHeight = img.height;
break;
case 270:
x = dx - previewSize;
y = dy;
+ logicalWidth = img.height;
+ logicalHeight = img.width;
break;
}
-
+
ctx.clearRect( 0, 0, 180, 180 );
ctx.rotate( rotation / 180 * Math.PI );
ctx.drawImage( img, x, y, width, height );
-
+ thumb.find('.mw-small-spinner').replaceWith($canvas);
+
// Image size
- var info = mw.msg( 'widthheight', img.width, img.height ) +
+ var info = mw.msg( 'widthheight', logicalWidth, logicalHeight ) +
', ' + prettySize( file.size );
$( '#mw-upload-thumbnail .fileinfo' ).text( info );
};
img.src = dataURL;
- }, mediaWiki.config.get( 'wgFileCanRotate' ) ? function ( data ) {
+ }, mw.config.get( 'wgFileCanRotate' ) ? function ( data ) {
try {
- meta = mediaWiki.util.jpegmeta( data, file.fileName );
+ meta = mw.libs.jpegmeta( data, file.fileName );
meta._binary_data = null;
} catch ( e ) {
meta = null;
*/
function fetchPreview( file, callback, callbackBinary ) {
var reader = new FileReader();
- reader.onload = function() {
- if ( callbackBinary ) {
+ if ( callbackBinary && 'readAsBinaryString' in reader ) {
+ // To fetch JPEG metadata we need a binary string; start there.
+ // todo:
+ reader.onload = function() {
callbackBinary( reader.result );
- reader.onload = function() {
- callback( reader.result );
- }
- reader.readAsDataURL( file );
- } else {
- callback( reader.result );
- }
- };
- if ( callbackBinary ) {
+
+ // Now run back through the regular code path.
+ fetchPreview( file, callback );
+ };
reader.readAsBinaryString( file );
+ } else if ( callbackBinary && 'readAsArrayBuffer' in reader ) {
+ // readAsArrayBuffer replaces readAsBinaryString
+ // However, our JPEG metadata library wants a string.
+ // So, this is going to be an ugly conversion.
+ reader.onload = function() {
+ var buffer = new Uint8Array( reader.result ),
+ string = '';
+ for ( var i = 0; i < buffer.byteLength; i++ ) {
+ string += String.fromCharCode( buffer[i] );
+ }
+ callbackBinary( string );
+
+ // Now run back through the regular code path.
+ fetchPreview( file, callback );
+ };
+ reader.readAsArrayBuffer( file );
+ } else if ( 'URL' in window && 'createObjectURL' in window.URL ) {
+ // Supported in Firefox 4.0 and above <https://developer.mozilla.org/en/DOM/window.URL.createObjectURL>
+ // WebKit has it in a namespace for now but that's ok. ;)
+ //
+ // Lifetime of this URL is until document close, which is fine
+ // for Special:Upload -- if this code gets used on longer-running
+ // pages, add a revokeObjectURL() when it's no longer needed.
+ //
+ // Prefer this over readAsDataURL for Firefox 7 due to bug reading
+ // some SVG files from data URIs <https://bugzilla.mozilla.org/show_bug.cgi?id=694165>
+ callback( window.URL.createObjectURL( file ) );
} else {
+ // This ends up decoding the file to base-64 and back again, which
+ // feels horribly inefficient.
+ reader.onload = function() {
+ callback( reader.result );
+ };
reader.readAsDataURL( file );
}
}
function clearPreview() {
$( '#mw-upload-thumbnail' ).remove();
}
-
+ /**
+ * Check if the file does not exceed the maximum size
+ */
+ function checkMaxUploadSize( file ) {
+ function getMaxUploadSize( type ) {
+ var sizes = mw.config.get( 'wgMaxUploadSize' );
+ if ( sizes[type] !== undefined ) {
+ return sizes[type];
+ }
+ return sizes['*'];
+ }
+ $( '.mw-upload-source-error' ).remove();
+
+ var maxSize = getMaxUploadSize( 'file' );
+ if ( file.size > maxSize ) {
+ var error = $( '<p class="error mw-upload-source-error" id="wpSourceTypeFile-error">' +
+ mw.message( 'largefileserver', file.size, maxSize ).escaped() + '</p>' );
+ $( '#wpUploadFile' ).after( error );
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Initialization
+ */
if ( hasFileAPI() ) {
// Update thumbnail when the file selection control is updated.
$( '#wpUploadFile' ).change( function() {
if ( this.files && this.files.length ) {
// Note: would need to be updated to handle multiple files.
var file = this.files[0];
+
+ if ( !checkMaxUploadSize( file ) ) {
+ return;
+ }
+
if ( fileIsPreviewable( file ) ) {
showPreview( file );
}
} );
}
} );
+
+/**
+ * Disable all upload source fields except the selected one
+ */
+jQuery( function ( $ ) {
+ var rows = $( '.mw-htmlform-field-UploadSourceField' );
+ for ( var i = rows.length; i; i-- ) {
+ var row = rows[i - 1];
+ $( 'input[name="wpSourceType"]', row ).change( function () {
+ var currentRow = row; // Store current row in our own scope
+ return function () {
+ $( '.mw-upload-source-error' ).remove();
+ if ( this.checked ) {
+ // Disable all inputs
+ $( 'input[name!="wpSourceType"]', rows ).prop( 'disabled', 'disabled' );
+ // Re-enable the current one
+ $( 'input', currentRow ).prop( 'disabled', false );
+ }
+ };
+ }() );
+ }
+} );
+