2013-08-07 08:59:08 +00:00
|
|
|
/*
|
|
|
|
* This file is part of the MediaWiki extension MultimediaViewer.
|
|
|
|
*
|
|
|
|
* MultimediaViewer is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* MultimediaViewer is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with MultimediaViewer. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2014-02-07 14:47:00 +00:00
|
|
|
( function ( mw, $ ) {
|
2014-02-17 15:09:23 +00:00
|
|
|
var MMVP,
|
2014-02-24 09:29:14 +00:00
|
|
|
comingFromHashChange = false;
|
2013-08-07 08:59:08 +00:00
|
|
|
|
2013-11-27 21:57:45 +00:00
|
|
|
/**
|
2014-01-11 00:11:37 +00:00
|
|
|
* Analyses the page, looks for image content and sets up the hooks
|
2013-11-27 21:57:45 +00:00
|
|
|
* to manage the viewing experience of such content.
|
2014-02-25 02:28:49 +00:00
|
|
|
* @class mw.mmv.MultimediaViewer
|
2013-11-27 21:57:45 +00:00
|
|
|
* @constructor
|
|
|
|
*/
|
2013-08-07 08:59:08 +00:00
|
|
|
function MultimediaViewer() {
|
2013-11-27 21:57:45 +00:00
|
|
|
/**
|
2014-02-13 09:52:40 +00:00
|
|
|
* @property {mw.mmv.provider.Image}
|
2013-11-27 21:57:45 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2014-02-13 09:52:40 +00:00
|
|
|
this.imageProvider = new mw.mmv.provider.Image();
|
2013-11-27 21:57:45 +00:00
|
|
|
|
2014-02-03 20:42:17 +00:00
|
|
|
/**
|
|
|
|
* @property {mw.mmv.provider.ImageInfo}
|
|
|
|
* @private
|
|
|
|
*/
|
2014-02-15 02:15:54 +00:00
|
|
|
this.imageInfoProvider = new mw.mmv.provider.ImageInfo( new mw.mmv.Api( 'imageinfo' ),
|
2014-02-03 20:42:17 +00:00
|
|
|
// Short-circuit, don't fallback, to save some tiny amount of time
|
2014-02-15 02:15:54 +00:00
|
|
|
{ language: mw.config.get( 'wgUserLanguage', false ) || mw.config.get( 'wgContentLanguage', 'en' ) }
|
|
|
|
);
|
2014-02-03 20:42:17 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @property {mw.mmv.provider.FileRepoInfo}
|
|
|
|
* @private
|
|
|
|
*/
|
2014-02-15 02:15:54 +00:00
|
|
|
this.fileRepoInfoProvider = new mw.mmv.provider.FileRepoInfo( new mw.mmv.Api( 'filerepoinfo' ) );
|
2014-02-03 20:42:17 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @property {mw.mmv.provider.ThumbnailInfo}
|
|
|
|
* @private
|
|
|
|
*/
|
2014-02-15 02:15:54 +00:00
|
|
|
this.thumbnailInfoProvider = new mw.mmv.provider.ThumbnailInfo( new mw.mmv.Api( 'thumbnailinfo' ) );
|
2014-02-03 20:42:17 +00:00
|
|
|
|
2014-02-06 00:12:50 +00:00
|
|
|
/**
|
|
|
|
* @property {mw.mmv.provider.UserInfo}
|
|
|
|
* @private
|
|
|
|
*/
|
2014-02-15 02:15:54 +00:00
|
|
|
this.userInfoProvider = new mw.mmv.provider.UserInfo( new mw.mmv.Api( 'userinfo' ) );
|
2014-02-06 00:12:50 +00:00
|
|
|
|
2014-01-30 11:28:43 +00:00
|
|
|
/**
|
2014-01-31 00:06:33 +00:00
|
|
|
* @property {mw.mmv.provider.ImageUsage}
|
2014-01-30 11:28:43 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2014-02-15 02:15:54 +00:00
|
|
|
this.imageUsageProvider = new mw.mmv.provider.ImageUsage( new mw.mmv.Api( 'imageusage' ) );
|
2014-01-30 11:28:43 +00:00
|
|
|
|
|
|
|
/**
|
2014-01-31 00:06:33 +00:00
|
|
|
* @property {mw.mmv.provider.GlobalUsage}
|
2014-01-30 11:28:43 +00:00
|
|
|
* @private
|
|
|
|
*/
|
2014-02-19 18:06:11 +00:00
|
|
|
this.globalUsageProvider = new mw.mmv.provider.GlobalUsage( new mw.mmv.Api( 'globalusage' ),
|
2014-02-15 02:15:54 +00:00
|
|
|
{ doNotUseApi: !mw.config.get( 'wgMultimediaViewer' ).globalUsageAvailable }
|
|
|
|
);
|
2014-01-30 11:28:43 +00:00
|
|
|
// replace with this one to test global usage on a local wiki without going through all the
|
|
|
|
// hassle required for installing the extension:
|
2014-02-03 20:42:17 +00:00
|
|
|
//this.globalUsageProvider = new mw.mmv.provider.GlobalUsage(
|
2014-02-19 18:06:11 +00:00
|
|
|
// new mw.mmv.Api( {ajax: { url: 'http://commons.wikimedia.org/w/api.php', dataType: 'jsonp' } } )
|
2014-01-30 11:28:43 +00:00
|
|
|
//);
|
2014-03-05 02:24:18 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Image index on page.
|
2014-04-14 23:22:28 +00:00
|
|
|
* @property {number}
|
2014-03-05 02:24:18 +00:00
|
|
|
*/
|
|
|
|
this.currentIndex = 0;
|
|
|
|
|
2014-04-14 23:22:28 +00:00
|
|
|
/**
|
|
|
|
* @property {mw.mmv.routing.Router} router -
|
|
|
|
*/
|
|
|
|
this.router = new mw.mmv.routing.Router();
|
|
|
|
|
2014-03-05 02:24:18 +00:00
|
|
|
/**
|
|
|
|
* UI object used to display the pictures in the page.
|
|
|
|
* @property {mw.mmv.LightboxInterface}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
this.ui = new mw.mmv.LightboxInterface();
|
2014-02-17 15:09:23 +00:00
|
|
|
}
|
2013-08-07 08:59:08 +00:00
|
|
|
|
2014-02-17 15:09:23 +00:00
|
|
|
MMVP = MultimediaViewer.prototype;
|
2013-08-07 08:59:08 +00:00
|
|
|
|
2014-02-19 02:27:30 +00:00
|
|
|
/**
|
|
|
|
* Initialize the lightbox interface given an array of thumbnail
|
|
|
|
* objects.
|
|
|
|
* @param {Object[]} thumbs Complex structure...TODO, document this better.
|
|
|
|
*/
|
2014-02-17 15:09:23 +00:00
|
|
|
MMVP.initWithThumbs = function ( thumbs ) {
|
|
|
|
var i, thumb;
|
2013-08-07 08:59:08 +00:00
|
|
|
|
2014-02-17 15:09:23 +00:00
|
|
|
this.thumbs = thumbs;
|
2013-10-29 20:26:07 +00:00
|
|
|
|
2014-02-17 15:09:23 +00:00
|
|
|
for ( i = 0; i < this.thumbs.length; i++ ) {
|
|
|
|
thumb = this.thumbs[ i ];
|
|
|
|
// Create a LightboxImage object for each legit image
|
2014-03-04 11:53:53 +00:00
|
|
|
thumb.image = this.createNewImage(
|
|
|
|
thumb.$thumb.prop( 'src' ),
|
2014-02-17 15:09:23 +00:00
|
|
|
thumb.link,
|
|
|
|
thumb.title,
|
|
|
|
i,
|
|
|
|
thumb.thumb,
|
2014-03-04 11:53:53 +00:00
|
|
|
thumb.caption
|
|
|
|
);
|
2014-02-17 15:09:23 +00:00
|
|
|
}
|
|
|
|
};
|
2013-12-10 19:54:07 +00:00
|
|
|
|
2013-12-02 19:46:52 +00:00
|
|
|
/**
|
|
|
|
* Create an image object for the lightbox to use.
|
|
|
|
* @protected
|
|
|
|
* @param {string} fileLink Link to the file - generally a thumb URL
|
|
|
|
* @param {string} filePageLink Link to the File: page
|
|
|
|
* @param {mw.Title} fileTitle Represents the File: page
|
|
|
|
* @param {number} index Which number file this is
|
2013-11-13 21:16:49 +00:00
|
|
|
* @param {HTMLImageElement} thumb The thumbnail that represents this image on the page
|
2013-12-10 19:54:07 +00:00
|
|
|
* @param {string} [caption] The caption, if any.
|
2014-02-25 02:28:49 +00:00
|
|
|
* @returns {mw.mmv.LightboxImage}
|
2013-12-02 19:46:52 +00:00
|
|
|
*/
|
2013-12-10 19:54:07 +00:00
|
|
|
MMVP.createNewImage = function ( fileLink, filePageLink, fileTitle, index, thumb, caption ) {
|
2014-04-09 23:59:49 +00:00
|
|
|
var thisImage = new mw.mmv.LightboxImage( fileLink, filePageLink, fileTitle, index, thumb, caption ),
|
|
|
|
$thumb = $( thumb );
|
|
|
|
|
2013-12-02 19:46:52 +00:00
|
|
|
thisImage.filePageLink = filePageLink;
|
|
|
|
thisImage.filePageTitle = fileTitle;
|
|
|
|
thisImage.index = index;
|
2013-11-13 21:16:49 +00:00
|
|
|
thisImage.thumbnail = thumb;
|
2014-04-09 23:59:49 +00:00
|
|
|
thisImage.originalWidth = parseInt( $thumb.data( 'file-width' ), 10 );
|
|
|
|
thisImage.originalHeight = parseInt( $thumb.data( 'file-height' ), 10 );
|
2013-12-02 19:46:52 +00:00
|
|
|
|
|
|
|
return thisImage;
|
|
|
|
};
|
|
|
|
|
2013-12-03 01:58:09 +00:00
|
|
|
/**
|
|
|
|
* Handles resize events in viewer.
|
|
|
|
* @protected
|
2014-02-25 02:28:49 +00:00
|
|
|
* @param {mw.mmv.LightboxInterface} ui lightbox that got resized
|
2013-12-03 01:58:09 +00:00
|
|
|
*/
|
2013-11-26 03:37:01 +00:00
|
|
|
MMVP.resize = function ( ui ) {
|
2013-12-03 01:58:09 +00:00
|
|
|
var viewer = this,
|
2014-04-09 23:59:49 +00:00
|
|
|
image = this.thumbs[ this.currentIndex].image,
|
2014-02-05 01:06:10 +00:00
|
|
|
imageWidths;
|
2013-11-13 21:16:49 +00:00
|
|
|
|
2014-02-13 09:52:40 +00:00
|
|
|
this.preloadThumbnails();
|
|
|
|
|
2014-04-09 23:59:49 +00:00
|
|
|
if ( image ) {
|
2014-02-26 20:09:37 +00:00
|
|
|
imageWidths = ui.canvas.getCurrentImageWidths();
|
2014-04-09 23:59:49 +00:00
|
|
|
this.fetchThumbnailForLightboxImage(
|
|
|
|
image, imageWidths.real
|
2014-02-13 09:52:40 +00:00
|
|
|
).then( function( thumbnail, image ) {
|
|
|
|
viewer.setImage( ui, thumbnail, image, imageWidths );
|
2014-03-01 01:10:51 +00:00
|
|
|
}, function ( error ) {
|
|
|
|
viewer.ui.canvas.showError( error );
|
2014-01-30 07:22:26 +00:00
|
|
|
} );
|
|
|
|
}
|
2014-01-06 21:53:42 +00:00
|
|
|
|
|
|
|
this.updateControls();
|
2013-12-03 01:58:09 +00:00
|
|
|
};
|
|
|
|
|
2014-02-19 02:27:30 +00:00
|
|
|
/**
|
|
|
|
* Updates positioning of controls, usually after a resize event.
|
|
|
|
*/
|
2013-11-13 00:43:46 +00:00
|
|
|
MMVP.updateControls = function () {
|
2014-02-17 15:09:23 +00:00
|
|
|
var numImages = this.thumbs ? this.thumbs.length : 0,
|
2014-03-05 02:24:18 +00:00
|
|
|
showNextButton = this.currentIndex < (numImages - 1),
|
|
|
|
showPreviousButton = this.currentIndex > 0;
|
2013-11-13 00:43:46 +00:00
|
|
|
|
2014-02-03 11:23:31 +00:00
|
|
|
this.ui.updateControls( showNextButton, showPreviousButton );
|
2013-11-13 00:43:46 +00:00
|
|
|
};
|
2013-11-06 00:36:06 +00:00
|
|
|
|
2014-01-28 23:57:05 +00:00
|
|
|
/**
|
2014-02-13 09:52:40 +00:00
|
|
|
* Loads and sets the specified image. It also updates the controls.
|
2014-02-25 02:28:49 +00:00
|
|
|
* @param {mw.mmv.LightboxInterface} ui image container
|
2014-02-13 09:52:40 +00:00
|
|
|
* @param {mw.mmv.model.Thumbnail} thumbnail thumbnail information
|
|
|
|
* @param {HTMLImageElement} image
|
2014-02-06 23:18:47 +00:00
|
|
|
* @param {mw.mmv.model.ThumbnailWidth} imageWidths
|
2014-01-28 23:57:05 +00:00
|
|
|
*/
|
2014-02-13 09:52:40 +00:00
|
|
|
MMVP.setImage = function ( ui, thumbnail, image, imageWidths ) {
|
2014-03-04 01:58:27 +00:00
|
|
|
ui.canvas.setImageAndMaxDimensions( thumbnail, image, imageWidths );
|
2014-02-13 09:52:40 +00:00
|
|
|
this.updateControls();
|
2014-01-28 23:57:05 +00:00
|
|
|
};
|
|
|
|
|
2013-12-10 19:54:07 +00:00
|
|
|
/**
|
|
|
|
* Loads a specified image.
|
2014-02-25 02:28:49 +00:00
|
|
|
* @param {mw.mmv.LightboxImage} image
|
2014-02-13 09:52:40 +00:00
|
|
|
* @param {HTMLImageElement} initialImage A thumbnail to use as placeholder while the image loads
|
2013-12-10 19:54:07 +00:00
|
|
|
*/
|
2014-02-13 09:52:40 +00:00
|
|
|
MMVP.loadImage = function ( image, initialImage ) {
|
2014-02-06 23:18:47 +00:00
|
|
|
var imageWidths,
|
2014-02-13 09:52:40 +00:00
|
|
|
imagePromise,
|
2014-02-25 13:43:22 +00:00
|
|
|
metadataPromise,
|
|
|
|
start,
|
2014-03-28 10:06:17 +00:00
|
|
|
viewer = this,
|
|
|
|
$initialImage = $( initialImage ),
|
2014-04-09 23:59:49 +00:00
|
|
|
fileWidth = image.originalWidth,
|
|
|
|
fileHeight = image.originalHeight;
|
2014-02-13 09:52:40 +00:00
|
|
|
|
2014-03-05 02:24:18 +00:00
|
|
|
this.currentIndex = image.index;
|
2013-11-25 23:51:40 +00:00
|
|
|
|
|
|
|
this.currentImageFilename = image.filePageTitle.getPrefixedText();
|
2014-01-06 20:02:39 +00:00
|
|
|
this.currentImageFileTitle = image.filePageTitle;
|
2014-01-06 21:53:42 +00:00
|
|
|
|
|
|
|
if ( !this.isOpen ) {
|
2014-03-05 02:24:18 +00:00
|
|
|
this.ui.open();
|
2014-01-06 21:53:42 +00:00
|
|
|
this.isOpen = true;
|
|
|
|
} else {
|
2014-03-05 02:24:18 +00:00
|
|
|
this.ui.empty();
|
2014-01-06 21:53:42 +00:00
|
|
|
}
|
2014-03-04 12:52:08 +00:00
|
|
|
this.setHash();
|
2014-02-25 13:43:22 +00:00
|
|
|
|
|
|
|
// At this point we can't show the thumbnail because we don't
|
|
|
|
// know what size it should be. We still assign it to allow for
|
|
|
|
// size calculations in getCurrentImageWidths, which needs to know
|
|
|
|
// the aspect ratio
|
|
|
|
$initialImage.hide();
|
2014-03-05 02:24:18 +00:00
|
|
|
this.ui.canvas.set( image, $initialImage );
|
2014-02-13 09:52:40 +00:00
|
|
|
|
|
|
|
this.preloadImagesMetadata();
|
|
|
|
this.preloadThumbnails();
|
2014-02-20 09:34:48 +00:00
|
|
|
this.preloadFullscreenThumbnail( image );
|
2014-01-06 21:53:42 +00:00
|
|
|
|
2014-02-26 20:09:37 +00:00
|
|
|
imageWidths = this.ui.canvas.getCurrentImageWidths();
|
2014-02-25 13:43:22 +00:00
|
|
|
|
|
|
|
this.resetBlurredThumbnailStates();
|
|
|
|
|
|
|
|
start = $.now();
|
|
|
|
|
2014-02-27 00:40:39 +00:00
|
|
|
// Reset the progress bar, it could be at any state if we're calling loadImage
|
|
|
|
// while another image is already loading
|
|
|
|
viewer.ui.panel.percent( 0 );
|
|
|
|
|
2014-04-09 23:59:49 +00:00
|
|
|
imagePromise = this.fetchThumbnailForLightboxImage( image, imageWidths.real );
|
2014-02-27 00:40:39 +00:00
|
|
|
|
|
|
|
// Check that the image hasn't already been loaded
|
|
|
|
if ( imagePromise.state() === 'pending' ) {
|
|
|
|
// Animate it to 5 to give a sense to something is happening, even if we're stuck
|
|
|
|
// waiting for server-side processing, such as thumbnail (re)generation
|
|
|
|
viewer.ui.panel.percent( 5 );
|
|
|
|
}
|
|
|
|
|
2014-03-28 10:06:17 +00:00
|
|
|
if ( fileWidth > 0 && fileHeight > 0 ) {
|
|
|
|
viewer.displayPlaceholderThumbnail( { width : fileWidth , height : fileHeight },
|
|
|
|
$initialImage,
|
|
|
|
imageWidths );
|
|
|
|
} else {
|
|
|
|
this.imageInfoProvider.get( image.filePageTitle ).done( function ( imageInfo ) {
|
|
|
|
if ( viewer.currentIndex !== image.index ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
viewer.displayPlaceholderThumbnail( imageInfo, $initialImage, imageWidths );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2014-02-27 00:40:39 +00:00
|
|
|
imagePromise.progress( function ( thumbnailInfoResponse, imageResponse ) {
|
2014-03-05 02:24:18 +00:00
|
|
|
if ( viewer.currentIndex !== image.index ) {
|
2014-02-27 00:40:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( viewer.ui
|
|
|
|
&& viewer.ui.panel
|
|
|
|
&& imageResponse.length === 2
|
|
|
|
&& imageResponse[ 1 ] > 5 ) {
|
2014-02-25 13:43:22 +00:00
|
|
|
viewer.ui.panel.percent( imageResponse[ 1 ] );
|
|
|
|
}
|
2014-02-27 00:40:39 +00:00
|
|
|
} ).done( function ( thumbnail, imageElement ) {
|
2014-04-01 07:56:18 +00:00
|
|
|
// Fallback in case the browser doesn't have fancy progress updates
|
|
|
|
viewer.ui.panel.percent( 100 );
|
|
|
|
|
2014-03-05 02:24:18 +00:00
|
|
|
if ( viewer.currentIndex !== image.index ) {
|
2014-02-27 00:40:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
viewer.displayRealThumbnail( thumbnail, imageElement, imageWidths, $.now() - start );
|
2014-03-01 01:10:51 +00:00
|
|
|
} ).fail( function ( error ) {
|
|
|
|
viewer.ui.canvas.showError( error );
|
2014-02-25 13:43:22 +00:00
|
|
|
} );
|
|
|
|
|
2014-02-13 09:52:40 +00:00
|
|
|
metadataPromise = this.fetchSizeIndependentLightboxInfo(
|
|
|
|
image.filePageTitle
|
|
|
|
).done( function ( imageInfo, repoInfo, localUsage, globalUsage, userInfo ) {
|
2014-03-05 02:24:18 +00:00
|
|
|
if ( viewer.currentIndex !== image.index ) {
|
2014-02-27 00:40:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-01 01:10:51 +00:00
|
|
|
viewer.ui.panel.setImageInfo( image, imageInfo, repoInfo, localUsage, globalUsage, userInfo );
|
|
|
|
} ).fail( function ( error ) {
|
|
|
|
if ( viewer.currentIndex !== image.index ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
viewer.ui.panel.showError( error );
|
2014-02-13 09:52:40 +00:00
|
|
|
} );
|
2014-01-28 23:57:05 +00:00
|
|
|
|
2014-02-13 09:52:40 +00:00
|
|
|
$.when( imagePromise, metadataPromise ).then( function() {
|
2014-03-05 02:24:18 +00:00
|
|
|
if ( viewer.currentIndex !== image.index ) {
|
2014-02-27 00:40:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-25 13:23:08 +00:00
|
|
|
viewer.ui.panel.animateMetadataOnce();
|
2014-04-11 14:05:58 +00:00
|
|
|
viewer.preloadDependencies();
|
2014-02-13 09:52:40 +00:00
|
|
|
} );
|
2013-11-25 23:51:40 +00:00
|
|
|
|
2014-02-24 09:29:14 +00:00
|
|
|
this.comingFromHashChange = false;
|
2014-02-17 15:09:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads an image by its title
|
2014-04-14 23:22:28 +00:00
|
|
|
* @param {mw.Title} title
|
2014-02-17 15:09:23 +00:00
|
|
|
* @param {boolean} updateHash Viewer should update the location hash when true
|
|
|
|
*/
|
|
|
|
MMVP.loadImageByTitle = function ( title, updateHash ) {
|
|
|
|
var viewer = this;
|
|
|
|
|
|
|
|
if ( !this.thumbs || !this.thumbs.length ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-24 09:29:14 +00:00
|
|
|
this.comingFromHashChange = !updateHash;
|
2014-02-17 15:09:23 +00:00
|
|
|
|
|
|
|
$.each( this.thumbs, function ( idx, thumb ) {
|
2014-04-14 23:22:28 +00:00
|
|
|
if ( thumb.title.getPrefixedText() === title.getPrefixedText() ) {
|
2014-02-17 15:09:23 +00:00
|
|
|
viewer.loadImage( thumb.image, thumb.$thumb.clone()[ 0 ], true );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} );
|
2014-02-13 09:52:40 +00:00
|
|
|
};
|
2013-12-10 21:04:45 +00:00
|
|
|
|
2014-02-25 13:43:22 +00:00
|
|
|
/**
|
|
|
|
* Resets the cross-request states needed to handle the blurred thumbnail logic
|
|
|
|
*/
|
|
|
|
MMVP.resetBlurredThumbnailStates = function () {
|
|
|
|
this.realThumbnailShown = false;
|
|
|
|
this.blurredThumbnailShown = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Display the real, full-resolution, thumbnail that was fetched with fetchThumbnail
|
|
|
|
* @param {mw.mmv.model.Thumbnail} thumbnail
|
|
|
|
* @param {HTMLImageElement} image
|
|
|
|
* @param {mw.mmv.model.ThumbnailWidth} imageWidths
|
|
|
|
* @param {number} loadTime Time it took to load the thumbnail
|
|
|
|
*/
|
|
|
|
MMVP.displayRealThumbnail = function ( thumbnail, image, imageWidths, loadTime ) {
|
|
|
|
this.realThumbnailShown = true;
|
|
|
|
|
2014-03-05 02:24:18 +00:00
|
|
|
this.setImage( this.ui, thumbnail, image, imageWidths );
|
2014-02-25 13:43:22 +00:00
|
|
|
|
|
|
|
// We only animate unblur if the image wasn't loaded from the cache
|
|
|
|
// A load in < 10ms is considered to be a browser cache hit
|
|
|
|
// And of course we only unblur if there was a blur to begin with
|
|
|
|
if ( this.blurredThumbnailShown && loadTime > 10 ) {
|
2014-03-05 02:24:18 +00:00
|
|
|
this.ui.canvas.unblur();
|
2014-02-25 13:43:22 +00:00
|
|
|
}
|
2014-02-28 10:44:26 +00:00
|
|
|
|
|
|
|
mw.mmv.logger.log( 'image-view' );
|
2014-02-25 13:43:22 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Display the blurred thumbnail from the page
|
|
|
|
* @param {mw.mmv.model.Image} imageInfo
|
|
|
|
* @param {jQuery} $initialImage The thumbnail from the page
|
|
|
|
* @param {mw.mmv.model.ThumbnailWidth} imageWidths
|
|
|
|
*/
|
2014-03-04 01:58:27 +00:00
|
|
|
MMVP.displayPlaceholderThumbnail = function ( imageInfo, $initialImage, imageWidths ) {
|
2014-02-25 13:43:22 +00:00
|
|
|
// If the actual image has already been displayed, there's no point showing the blurry one
|
|
|
|
if ( this.realThumbnailShown ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-03-05 02:24:18 +00:00
|
|
|
this.blurredThumbnailShown = this.ui.canvas.maybeDisplayPlaceholder(
|
2014-02-26 20:09:37 +00:00
|
|
|
imageInfo, $initialImage, imageWidths );
|
2014-02-25 13:43:22 +00:00
|
|
|
};
|
|
|
|
|
2014-02-13 09:52:40 +00:00
|
|
|
/**
|
|
|
|
* Preload this many prev/next images to speed up navigation.
|
|
|
|
* (E.g. preloadDistance = 3 means that the previous 3 and the next 3 images will be loaded.)
|
|
|
|
* Preloading only happens when the viewer is open.
|
|
|
|
* @property {number}
|
|
|
|
*/
|
|
|
|
MMVP.preloadDistance = 1;
|
2014-02-07 14:47:00 +00:00
|
|
|
|
2014-02-13 09:52:40 +00:00
|
|
|
/**
|
|
|
|
* Stores image metadata preloads, so they can be cancelled.
|
2014-02-19 02:27:30 +00:00
|
|
|
* @property {mw.mmv.model.TaskQueue}
|
2014-02-13 09:52:40 +00:00
|
|
|
*/
|
|
|
|
MMVP.metadataPreloadQueue = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stores image thumbnail preloads, so they can be cancelled.
|
2014-02-19 02:27:30 +00:00
|
|
|
* @property {mw.mmv.model.TaskQueue}
|
2014-02-13 09:52:40 +00:00
|
|
|
*/
|
|
|
|
MMVP.thumbnailPreloadQueue = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Orders lightboximage indexes for preloading. Works similar to $.each, except it only takes
|
|
|
|
* the callback argument. Calls the callback with each lightboximage index in some sequence
|
|
|
|
* that is ideal for preloading.
|
|
|
|
* @private
|
2014-02-25 02:28:49 +00:00
|
|
|
* @param {function(number, mw.mmv.LightboxImage)} callback
|
2014-02-13 09:52:40 +00:00
|
|
|
*/
|
|
|
|
MMVP.eachPrealoadableLightboxIndex = function( callback ) {
|
|
|
|
for ( var i = 0; i <= this.preloadDistance; i++ ) {
|
2014-03-05 02:24:18 +00:00
|
|
|
if ( this.currentIndex + i < this.thumbs.length ) {
|
2014-02-13 09:52:40 +00:00
|
|
|
callback(
|
2014-03-05 02:24:18 +00:00
|
|
|
this.currentIndex + i,
|
|
|
|
this.thumbs[ this.currentIndex + i ].image
|
2014-02-13 09:52:40 +00:00
|
|
|
);
|
2014-02-07 14:47:00 +00:00
|
|
|
}
|
2014-03-05 02:24:18 +00:00
|
|
|
if ( i && this.currentIndex - i >= 0 ) { // skip duplicate for i==0
|
2014-02-13 09:52:40 +00:00
|
|
|
callback(
|
2014-03-05 02:24:18 +00:00
|
|
|
this.currentIndex - i,
|
|
|
|
this.thumbs[ this.currentIndex - i ].image
|
2014-02-13 09:52:40 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A helper function to fill up the preload queues.
|
|
|
|
* taskFactory(lightboxImage) should return a preload task for the given lightboximage.
|
|
|
|
* @private
|
2014-02-25 02:28:49 +00:00
|
|
|
* @param {function(mw.mmv.LightboxImage): function()} taskFactory
|
2014-02-13 09:52:40 +00:00
|
|
|
* @return {mw.mmv.model.TaskQueue}
|
|
|
|
*/
|
|
|
|
MMVP.pushLightboxImagesIntoQueue = function( taskFactory ) {
|
|
|
|
var queue = new mw.mmv.model.TaskQueue();
|
|
|
|
|
|
|
|
this.eachPrealoadableLightboxIndex( function( i, lightboxImage ) {
|
|
|
|
queue.push( taskFactory( lightboxImage ) );
|
2013-11-25 23:51:40 +00:00
|
|
|
} );
|
|
|
|
|
2014-02-13 09:52:40 +00:00
|
|
|
return queue;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cancels in-progress image metadata preloading.
|
|
|
|
*/
|
|
|
|
MMVP.cancelImageMetadataPreloading = function() {
|
|
|
|
if ( this.metadataPreloadQueue ) {
|
|
|
|
this.metadataPreloadQueue.cancel();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cancels in-progress image thumbnail preloading.
|
|
|
|
*/
|
|
|
|
MMVP.cancelThumbnailsPreloading = function() {
|
|
|
|
if ( this.thumbnailPreloadQueue ) {
|
|
|
|
this.thumbnailPreloadQueue.cancel();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Preload metadata for next and prev N image (N = MMVP.preloadDistance).
|
|
|
|
* Two images will be loaded at a time (one forward, one backward), with closer images
|
|
|
|
* being loaded sooner.
|
|
|
|
*/
|
|
|
|
MMVP.preloadImagesMetadata = function() {
|
|
|
|
var viewer = this;
|
|
|
|
|
|
|
|
this.cancelImageMetadataPreloading();
|
|
|
|
|
|
|
|
this.metadataPreloadQueue = this.pushLightboxImagesIntoQueue( function( lightboxImage ) {
|
|
|
|
return function() {
|
|
|
|
return viewer.fetchSizeIndependentLightboxInfo( lightboxImage.filePageTitle );
|
|
|
|
};
|
|
|
|
} );
|
|
|
|
|
|
|
|
this.metadataPreloadQueue.execute();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Preload thumbnails for next and prev N image (N = MMVP.preloadDistance).
|
|
|
|
* Two images will be loaded at a time (one forward, one backward), with closer images
|
|
|
|
* being loaded sooner.
|
|
|
|
*/
|
|
|
|
MMVP.preloadThumbnails = function() {
|
2014-03-05 02:24:18 +00:00
|
|
|
var viewer = this;
|
2014-02-13 09:52:40 +00:00
|
|
|
|
|
|
|
this.cancelThumbnailsPreloading();
|
|
|
|
|
|
|
|
this.thumbnailPreloadQueue = this.pushLightboxImagesIntoQueue( function( lightboxImage ) {
|
|
|
|
return function() {
|
2014-04-09 23:59:49 +00:00
|
|
|
return viewer.fetchThumbnailForLightboxImage(
|
|
|
|
lightboxImage,
|
2014-03-05 02:24:18 +00:00
|
|
|
viewer.ui.canvas.getLightboxImageWidths( lightboxImage ).real
|
2014-02-13 09:52:40 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
} );
|
|
|
|
|
|
|
|
this.thumbnailPreloadQueue.execute();
|
2013-11-25 23:51:40 +00:00
|
|
|
};
|
|
|
|
|
2014-02-20 08:43:10 +00:00
|
|
|
/**
|
|
|
|
* Preload the fullscreen size of the current image.
|
|
|
|
*/
|
2014-02-20 09:34:48 +00:00
|
|
|
MMVP.preloadFullscreenThumbnail = function( image ) {
|
2014-04-09 23:59:49 +00:00
|
|
|
this.fetchThumbnailForLightboxImage(
|
|
|
|
image,
|
2014-03-05 02:24:18 +00:00
|
|
|
this.ui.canvas.getLightboxImageWidthsForFullscreen( image ).real
|
2014-02-20 08:43:10 +00:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2014-01-06 20:02:39 +00:00
|
|
|
/**
|
2014-02-13 09:52:40 +00:00
|
|
|
* Loads all the size-independent information needed by the lightbox (image metadata, repo
|
|
|
|
* information, file usage, uploader data).
|
|
|
|
* @param {mw.Title} fileTitle Title of the file page for the image.
|
|
|
|
* @returns {jQuery.Promise.<mw.mmv.model.Image, mw.mmv.model.Repo, mw.mmv.model.FileUsage,
|
|
|
|
* mw.mmv.model.FileUsage, mw.mmv.model.User>}
|
2014-01-06 20:02:39 +00:00
|
|
|
*/
|
2014-02-13 09:52:40 +00:00
|
|
|
MMVP.fetchSizeIndependentLightboxInfo = function ( fileTitle ) {
|
|
|
|
var viewer = this,
|
|
|
|
imageInfoPromise = this.imageInfoProvider.get( fileTitle ),
|
|
|
|
repoInfoPromise = this.fileRepoInfoProvider.get( fileTitle ),
|
|
|
|
imageUsagePromise = this.imageUsageProvider.get( fileTitle ),
|
|
|
|
globalUsagePromise = this.globalUsageProvider.get( fileTitle ),
|
|
|
|
userInfoPromise;
|
|
|
|
|
|
|
|
userInfoPromise = $.when(
|
|
|
|
imageInfoPromise, repoInfoPromise
|
|
|
|
).then( function( imageInfo, repoInfoHash ) {
|
|
|
|
if ( imageInfo.lastUploader ) {
|
|
|
|
return viewer.userInfoProvider.get( imageInfo.lastUploader, repoInfoHash[imageInfo.repo] );
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
|
2014-02-03 20:42:17 +00:00
|
|
|
return $.when(
|
2014-02-13 09:52:40 +00:00
|
|
|
imageInfoPromise, repoInfoPromise, imageUsagePromise, globalUsagePromise, userInfoPromise
|
|
|
|
).then( function( imageInfo, repoInfoHash, imageUsage, globalUsage, userInfo ) {
|
|
|
|
return $.Deferred().resolve( imageInfo, repoInfoHash[imageInfo.repo], imageUsage, globalUsage, userInfo );
|
2014-02-03 20:42:17 +00:00
|
|
|
} );
|
2013-09-26 01:47:59 +00:00
|
|
|
};
|
|
|
|
|
2014-04-09 23:59:49 +00:00
|
|
|
/**
|
|
|
|
* Loads size-dependent components of a lightbox - the thumbnail model and the image itself.
|
|
|
|
* @param {mw.mmv.LightboxImage} image
|
|
|
|
* @param {number} width the width of the requested thumbnail
|
|
|
|
*/
|
|
|
|
MMVP.fetchThumbnailForLightboxImage = function ( image, width ) {
|
|
|
|
return this.fetchThumbnail(
|
|
|
|
image.filePageTitle,
|
|
|
|
width,
|
|
|
|
image.originalWidth,
|
|
|
|
image.originalHeight
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2014-01-30 11:28:43 +00:00
|
|
|
/**
|
2014-02-13 09:52:40 +00:00
|
|
|
* Loads size-dependent components of a lightbox - the thumbnail model and the image itself.
|
|
|
|
* @param {mw.Title} fileTitle
|
2014-04-09 23:59:49 +00:00
|
|
|
* @param {number} width the width of the requested thumbnail
|
|
|
|
* @param {number} [originalWidth] the width of the original, full-sized file (might be missing)
|
|
|
|
* @param {number} [originalHeight] the height of the original, full-sized file (might be missing)
|
2014-02-13 09:52:40 +00:00
|
|
|
* @returns {jQuery.Promise.<mw.mmv.model.Thumbnail, HTMLImageElement>}
|
2014-01-30 11:28:43 +00:00
|
|
|
*/
|
2014-04-09 23:59:49 +00:00
|
|
|
MMVP.fetchThumbnail = function ( fileTitle, width, originalWidth, originalHeight ) {
|
2014-04-15 00:01:03 +00:00
|
|
|
$.noop( originalHeight ); // keep JSHint happy... will be removed later
|
2014-02-13 09:52:40 +00:00
|
|
|
var viewer = this,
|
|
|
|
thumbnailPromise,
|
|
|
|
imagePromise;
|
|
|
|
|
2014-04-15 00:01:03 +00:00
|
|
|
if ( originalWidth && width > originalWidth ) {
|
|
|
|
// Do not request images larger than the original image
|
|
|
|
width = originalWidth;
|
|
|
|
}
|
|
|
|
|
2014-02-13 09:52:40 +00:00
|
|
|
thumbnailPromise = this.thumbnailInfoProvider.get( fileTitle, width );
|
2014-02-25 13:43:22 +00:00
|
|
|
|
2014-04-15 00:01:03 +00:00
|
|
|
imagePromise = thumbnailPromise.then( function ( thumbnail ) {
|
2014-02-13 09:52:40 +00:00
|
|
|
return viewer.imageProvider.get( thumbnail.url );
|
2014-01-30 11:28:43 +00:00
|
|
|
} );
|
2014-02-13 09:52:40 +00:00
|
|
|
|
|
|
|
return $.when( thumbnailPromise, imagePromise );
|
2014-01-30 11:28:43 +00:00
|
|
|
};
|
|
|
|
|
2014-02-19 02:27:30 +00:00
|
|
|
/**
|
|
|
|
* Loads an image at a specified index in the viewer's thumbnail array.
|
|
|
|
* @param {number} index
|
|
|
|
*/
|
2013-11-26 03:37:01 +00:00
|
|
|
MMVP.loadIndex = function ( index ) {
|
2014-02-17 15:09:23 +00:00
|
|
|
var thumb;
|
|
|
|
|
|
|
|
if ( index < this.thumbs.length && index >= 0 ) {
|
|
|
|
thumb = this.thumbs[ index ];
|
|
|
|
this.loadImage( thumb.image, thumb.$thumb.clone()[0] );
|
2013-11-26 03:37:01 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-02-11 13:25:39 +00:00
|
|
|
/**
|
|
|
|
* Opens the next image
|
|
|
|
*/
|
2013-11-26 03:37:01 +00:00
|
|
|
MMVP.nextImage = function () {
|
2014-03-05 02:24:18 +00:00
|
|
|
this.loadIndex( this.currentIndex + 1 );
|
2013-11-26 03:37:01 +00:00
|
|
|
};
|
|
|
|
|
2014-02-11 13:25:39 +00:00
|
|
|
/**
|
|
|
|
* Opens the previous image
|
|
|
|
*/
|
2013-11-26 03:37:01 +00:00
|
|
|
MMVP.prevImage = function () {
|
2014-03-05 02:24:18 +00:00
|
|
|
this.loadIndex( this.currentIndex - 1 );
|
2013-11-26 03:37:01 +00:00
|
|
|
};
|
|
|
|
|
2014-02-11 13:25:39 +00:00
|
|
|
/**
|
|
|
|
* Handles close event coming from the lightbox
|
|
|
|
*/
|
|
|
|
MMVP.close = function () {
|
2014-02-24 09:29:14 +00:00
|
|
|
if ( comingFromHashChange === false ) {
|
2014-04-11 09:31:38 +00:00
|
|
|
$( document ).trigger( $.Event( 'mmv-hash', { hash : '#' } ) );
|
2014-02-11 13:25:39 +00:00
|
|
|
} else {
|
2014-02-24 09:29:14 +00:00
|
|
|
comingFromHashChange = false;
|
2014-02-11 13:25:39 +00:00
|
|
|
}
|
|
|
|
|
2014-04-11 09:31:38 +00:00
|
|
|
// This has to happen after the hash reset, because setting the hash to # will reset the page scroll
|
|
|
|
$( document ).trigger( $.Event( 'mmv-cleanup-overlay' ) );
|
|
|
|
|
2014-02-11 13:25:39 +00:00
|
|
|
this.isOpen = false;
|
|
|
|
};
|
|
|
|
|
2014-02-17 15:09:23 +00:00
|
|
|
/**
|
2014-02-21 11:16:30 +00:00
|
|
|
* Handles a hash change coming from the browser
|
2014-02-17 15:09:23 +00:00
|
|
|
*/
|
2014-02-21 11:16:30 +00:00
|
|
|
MMVP.hash = function () {
|
2014-04-14 23:22:28 +00:00
|
|
|
var route = this.router.parseLocation( window.location );
|
2014-02-21 11:16:30 +00:00
|
|
|
|
2014-04-14 23:22:28 +00:00
|
|
|
if ( route instanceof mw.mmv.routing.ThumbnailRoute ) {
|
|
|
|
this.loadImageByTitle( route.fileTitle );
|
2014-02-21 11:16:30 +00:00
|
|
|
} else if ( this.isOpen ) {
|
2014-04-11 09:31:38 +00:00
|
|
|
// This allows us to avoid the mmv-hash event that normally happens on close
|
2014-02-24 09:29:14 +00:00
|
|
|
comingFromHashChange = true;
|
2014-02-21 11:16:30 +00:00
|
|
|
|
2014-03-05 02:24:18 +00:00
|
|
|
if ( this.ui ) {
|
|
|
|
// FIXME triggers mmv-close event, which calls viewer.close()
|
|
|
|
this.ui.unattach();
|
2014-02-21 11:16:30 +00:00
|
|
|
} else {
|
|
|
|
this.close();
|
|
|
|
}
|
2014-02-17 15:09:23 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-03-04 12:52:08 +00:00
|
|
|
MMVP.setHash = function() {
|
2014-04-14 23:22:28 +00:00
|
|
|
var route, hashFragment;
|
2014-03-04 12:52:08 +00:00
|
|
|
if ( !this.comingFromHashChange ) {
|
2014-04-14 23:22:28 +00:00
|
|
|
route = new mw.mmv.routing.ThumbnailRoute( this.currentImageFileTitle );
|
|
|
|
hashFragment = '#' + this.router.createHash( route );
|
2014-04-11 09:31:38 +00:00
|
|
|
$( document ).trigger( $.Event( 'mmv-hash', { hash : hashFragment } ) );
|
2014-03-04 12:52:08 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-04-08 09:54:30 +00:00
|
|
|
/**
|
|
|
|
* @event mmv-close
|
2014-04-11 09:31:38 +00:00
|
|
|
* Fired when the viewer is closed. This is used by the ligthbox to notify the main app.
|
2014-04-08 09:54:30 +00:00
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* @event mmv-next
|
|
|
|
* Fired when the user requests the next image.
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* @event mmv-prev
|
|
|
|
* Fired when the user requests the previous image.
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* @event mmv-resize
|
|
|
|
* Fired when the screen size changes.
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* @event mmv-request-thumbnail
|
|
|
|
* Used by components to request a thumbnail URL for the current thumbnail, with a given size.
|
|
|
|
* @param {number} size
|
|
|
|
*/
|
2014-02-19 02:27:30 +00:00
|
|
|
/**
|
2014-02-21 11:16:30 +00:00
|
|
|
* Registers all event handlers
|
2014-02-19 02:27:30 +00:00
|
|
|
*/
|
2014-02-11 13:25:39 +00:00
|
|
|
MMVP.setupEventHandlers = function () {
|
2014-02-11 01:12:31 +00:00
|
|
|
var viewer = this;
|
|
|
|
|
2014-02-21 11:16:30 +00:00
|
|
|
$( document ).on( 'mmv-close.mmvp', function () {
|
2014-02-11 13:25:39 +00:00
|
|
|
viewer.close();
|
2014-02-21 11:16:30 +00:00
|
|
|
} ).on( 'mmv-next.mmvp', function () {
|
2014-02-11 01:12:31 +00:00
|
|
|
viewer.nextImage();
|
2014-02-21 11:16:30 +00:00
|
|
|
} ).on( 'mmv-prev.mmvp', function () {
|
2014-02-11 01:12:31 +00:00
|
|
|
viewer.prevImage();
|
2014-02-21 11:16:30 +00:00
|
|
|
} ).on( 'mmv-resize.mmvp', function () {
|
2014-03-05 02:24:18 +00:00
|
|
|
viewer.resize( viewer.ui );
|
2014-03-19 03:05:36 +00:00
|
|
|
} ).on( 'mmv-request-thumbnail.mmvp', function ( e, size ) {
|
|
|
|
if ( viewer.currentImageFileTitle ) {
|
|
|
|
return viewer.thumbnailInfoProvider.get( viewer.currentImageFileTitle, size );
|
|
|
|
} else {
|
|
|
|
return $.Deferred().reject();
|
|
|
|
}
|
2014-03-17 08:07:53 +00:00
|
|
|
} );
|
2014-02-11 01:12:31 +00:00
|
|
|
};
|
|
|
|
|
2014-03-04 11:53:53 +00:00
|
|
|
/**
|
|
|
|
* Unregisters all event handlers. Currently only used in tests.
|
|
|
|
*/
|
2014-04-11 14:05:58 +00:00
|
|
|
MMVP.cleanupEventHandlers = function () {
|
2014-03-04 11:53:53 +00:00
|
|
|
$( document ).off( 'mmv-close.mmvp mmv-next.mmvp mmv-prev.mmvp mmv-resize.mmvp' );
|
|
|
|
};
|
|
|
|
|
2014-04-11 14:05:58 +00:00
|
|
|
/**
|
|
|
|
* Preloads JS and CSS dependencies that aren't needed to display the first image, but could be needed later
|
|
|
|
*/
|
|
|
|
MMVP.preloadDependencies = function () {
|
|
|
|
mw.loader.load( [ 'mmv.ui.reuse.share', 'mmv.ui.reuse.embed', 'mmv.ui.reuse.download' ] );
|
|
|
|
};
|
|
|
|
|
2014-02-25 02:28:49 +00:00
|
|
|
mw.mmv.MultimediaViewer = MultimediaViewer;
|
2014-02-07 14:47:00 +00:00
|
|
|
}( mediaWiki, jQuery ) );
|