diff --git a/resources/mmv/mmv.js b/resources/mmv/mmv.js index fa0826e9c..8ac0fee8d 100755 --- a/resources/mmv/mmv.js +++ b/resources/mmv/mmv.js @@ -339,29 +339,9 @@ * @param {number} requestedWidth */ MMVP.loadResizedImage = function ( ui, imageData, targetWidth, requestedWidth ) { - var rpid, viewer, image, maybeThumb; - // Replace image only if data was returned. if ( imageData ) { - viewer = this; - image = new Image(); - - image.onload = function () { - viewer.profileEnd( rpid ); - }; - - rpid = this.profileStart( 'image-resize', { - width: imageData.width, - height: imageData.height, - fileSize: imageData.size - }, imageData.mimeType ); - - maybeThumb = imageData.getThumbUrl( requestedWidth ); - image.src = maybeThumb || imageData.url; - if ( maybeThumb && requestedWidth > targetWidth || !maybeThumb && imageData.width > targetWidth ) { - image.width = targetWidth; - } - ui.replaceImageWith( image ); + this.loadAndSetImage( ui, imageData, targetWidth, requestedWidth, 'image-resize' ); } }; @@ -597,6 +577,47 @@ ); }; + /** + * @method + * Loads and sets the image specified in the imageData. It also updates the controls + * and collects profiling information. + * + * @param {mw.LightboxInterface} ui image container + * @param {mw.mmv.model.Image} imageData image information + * @param {number} targetWidth + * @param {number} requestedWidth + * @param {string} profileEvent profile event key + */ + MMVP.loadAndSetImage = function ( ui, imageData, targetWidth, requestedWidth, profileEvent ) { + var rpid, + maybeThumb, + viewer = this, + image = new Image(); + + image.onload = function () { + viewer.profileEnd( rpid ); + }; + + rpid = this.profileStart( profileEvent, { + width: imageData.width, + height: imageData.height, + fileSize: imageData.size + }, imageData.mimeType ); + + // Use cached image if we have it. + maybeThumb = imageData.getThumbUrl( requestedWidth ); + image.src = maybeThumb || imageData.url; + + if ( maybeThumb && requestedWidth > targetWidth || + !maybeThumb && imageData.width > targetWidth ) { + // Image bigger than the current area, resize before loading + image.width = targetWidth; + } + + ui.replaceImageWith( image ); + this.updateControls(); + }; + /** * @method * Loads a specified image. @@ -630,38 +651,19 @@ mdpid = this.profileStart( 'metadata-fetch' ); - this.fetchImageInfo( image.filePageTitle ).done( function ( imageData, repoInfo, size, requestedWidth ) { - var pid, - repoData = mw.mmv.model.Repo.newFromRepoInfo( repoInfo[imageData.repo] ), - imageEle = new Image(), - targetWidth = size; + this.fetchImageInfo( image.filePageTitle ).done( function ( imageData, repoInfo, targetWidth, requestedWidth ) { + var repoData = mw.mmv.model.Repo.newFromRepoInfo( repoInfo[imageData.repo] ); + + viewer.profileEnd( mdpid ); viewer.stopListeningToScroll(); viewer.animateMetadataDivOnce() // We need to wait until the animation is finished before we listen to scroll .then( function() { viewer.startListeningToScroll(); } ); - imageEle.onload = function () { - if ( imageEle.width > targetWidth ) { - imageEle.width = targetWidth; - } - - viewer.profileEnd( pid ); - viewer.updateControls(); - }; - - viewer.profileEnd( mdpid ); - - pid = viewer.profileStart( 'image-load', { - width: imageData.width, - height: imageData.height, - fileSize: imageData.size - }, imageData.mimeType ); - - imageEle.src = imageData.getThumbUrl( requestedWidth ) || imageData.url; + viewer.loadAndSetImage( viewer.lightbox.iface, imageData, targetWidth, requestedWidth, 'image-load' ); viewer.lightbox.iface.$imageDiv.removeClass( 'empty' ); - viewer.lightbox.iface.replaceImageWith( imageEle ); viewer.setImageInfo( image, imageData, repoData ); } ); diff --git a/tests/qunit/mmv.test.js b/tests/qunit/mmv.test.js index e703b6a60..8fb443c11 100644 --- a/tests/qunit/mmv.test.js +++ b/tests/qunit/mmv.test.js @@ -461,25 +461,72 @@ ui.attach( '#qunit-fixture' ); // Fake viewport dimensions, width/height == 2.0, we are limited by height - ui.$imageWrapper.height(200); - ui.$imageWrapper.width(400); + ui.$imageWrapper.height( 200 ); + ui.$imageWrapper.width( 400 ); - widths = viewer.getImageSizeApiArgs(ui); + widths = viewer.getImageSizeApiArgs( ui ); - assert.strictEqual(widths.target, 150/100*200, 'Correct target width was computed.'); - assert.strictEqual(widths.requested, 320 * $.devicePixelRatio(), 'Correct requested width was computed.'); + assert.strictEqual( widths.target, 150/100*200, 'Correct target width was computed.' ); + assert.strictEqual( widths.requested, 320 * $.devicePixelRatio(), 'Correct requested width was computed.' ); // Fake viewport dimensions, width/height == 1.0, we are limited by width - ui.$imageWrapper.height(600); - ui.$imageWrapper.width(600); + ui.$imageWrapper.height( 600 ); + ui.$imageWrapper.width( 600 ); - widths = viewer.getImageSizeApiArgs(ui); + widths = viewer.getImageSizeApiArgs( ui ); - assert.strictEqual(widths.target, 600, 'Correct target width was computed.'); - assert.strictEqual(widths.requested, 640 * $.devicePixelRatio(), 'Correct requested width was computed.'); + assert.strictEqual( widths.target, 600, 'Correct target width was computed.' ); + assert.strictEqual( widths.requested, 640 * $.devicePixelRatio(), 'Correct requested width was computed.' ); ui.unattach(); } ); + QUnit.asyncTest( 'loadAndSetImage(): Basic load', 9, function ( assert ) { + var targetWidth, + requestedWidth, + profileEvent, + pid = 4321, + viewer = new mw.MultimediaViewer(), + ui = new mw.LightboxInterface(), + size = 120, + width = 10, + height = 11, + imageUrl = 'http://en.wikipedia.org/w/skins/vector/images/search-ltr.png', + imageData = new mw.mmv.model.Image( + mw.Title.newFromText( 'File:Foobar.pdf.jpg' ), + size, width, height, 'image/jpeg', + imageUrl, + 'http://example.com', + 'example', 'tester', '2013-11-10', '2013-11-09', 'Blah blah blah', + 'A person', 'Another person', 'CC-BY-SA-3.0', 0, 0 + ); + // Assert funtions are called with correct data + viewer.profileStart = function ( type, imgSize, fileType ) { + assert.strictEqual( type, profileEvent, 'Correct event type for profile start.' ); + assert.strictEqual( imgSize.width, width, 'Correct width for profile start.' ); + assert.strictEqual( imgSize.height, height, 'Correct height for profile start.' ); + assert.strictEqual( imgSize.fileSize, size, 'Correct fileSize for profile start.' ); + assert.strictEqual( fileType, 'image/jpeg', 'Correct fileType for profile start.' ); + + return pid; + }; + viewer.profileEnd = function ( id ) { + assert.strictEqual( id, pid, 'Correct pid to end profiling. Image loaded correctly.' ); + QUnit.start(); + }; + ui.replaceImageWith = function ( image ) { + assert.strictEqual( image.src, imageUrl, 'Image to replace has correct "src" attribute.' ); + assert.strictEqual( image.width, targetWidth, 'Image to replace has correct "width" attribute.' ); + }; + viewer.updateControls = function () { + assert.ok( true, 'Controls updated.' ); + }; + + // Test case when image loaded is bigger than current area + targetWidth = 8; // Current area < imageData.width + requestedWidth = 640; + profileEvent = 'image-load'; + viewer.loadAndSetImage( ui, imageData, targetWidth, requestedWidth, profileEvent ); + } ); }( mediaWiki, jQuery ) );