mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/MultimediaViewer
synced 2024-11-24 08:13:38 +00:00
Merge MultiLightbox into MultimediaViewer
* merges parent classes into child classes * moves some files and tests to have a consistent directory structure Change-Id: I360cc0805d8a561f5105fb063747457f67e1fccd Mingle: https://wikimedia.mingle.thoughtworks.com/projects/multimedia/cards/177
This commit is contained in:
parent
a04631c405
commit
53da285b07
|
@ -43,41 +43,10 @@ call_user_func( function() {
|
|||
);
|
||||
};
|
||||
|
||||
$wgResourceModules['multilightbox.interface'] = array_merge( array(
|
||||
'scripts' => array(
|
||||
'lightboxinterface.js',
|
||||
),
|
||||
|
||||
'styles' => array(
|
||||
'multilightbox.less',
|
||||
),
|
||||
), $moduleInfo( 'multilightbox' ) );
|
||||
|
||||
$wgResourceModules['multilightbox.image'] = array_merge( array(
|
||||
'scripts' => array(
|
||||
'lightboximage.js',
|
||||
),
|
||||
), $moduleInfo( 'multilightbox' ) );
|
||||
|
||||
$wgResourceModules['multilightbox'] = array_merge( array(
|
||||
'scripts' => array(
|
||||
'multilightbox.js',
|
||||
),
|
||||
|
||||
'dependencies' => array(
|
||||
'mmv.lightboxinterface',
|
||||
),
|
||||
), $moduleInfo( 'multilightbox' ) );
|
||||
|
||||
$wgResourceModules['mmv.lightboximage'] = array_merge( array(
|
||||
'scripts' => array(
|
||||
'mmv.lightboximage.js',
|
||||
),
|
||||
|
||||
'dependencies' => array(
|
||||
'oojs',
|
||||
'multilightbox.image',
|
||||
),
|
||||
), $moduleInfo( 'mmv' ) );
|
||||
|
||||
$wgResourceModules['mmv.lightboxinterface'] = array_merge( array(
|
||||
|
@ -86,8 +55,6 @@ call_user_func( function() {
|
|||
),
|
||||
|
||||
'dependencies' => array(
|
||||
'oojs',
|
||||
'multilightbox.interface',
|
||||
'mmv.ui.buttons',
|
||||
'mmv.ui.categories',
|
||||
'mmv.ui.description',
|
||||
|
@ -127,9 +94,12 @@ call_user_func( function() {
|
|||
'mmv.multilightbox.js',
|
||||
),
|
||||
|
||||
'styles' => array(
|
||||
'mmv.multilightbox.less',
|
||||
),
|
||||
|
||||
'dependencies' => array(
|
||||
'oojs',
|
||||
'multilightbox',
|
||||
'mmv.lightboxinterface',
|
||||
),
|
||||
), $moduleInfo( 'mmv' ) );
|
||||
|
||||
|
@ -435,7 +405,6 @@ call_user_func( function() {
|
|||
),
|
||||
|
||||
'dependencies' => array(
|
||||
'multilightbox',
|
||||
'jquery.scrollTo',
|
||||
'mmv.lightboximage',
|
||||
'jquery.fullscreen',
|
||||
|
|
|
@ -120,32 +120,31 @@ class MultimediaViewerHooks {
|
|||
public static function getTestModules( array &$testModules, ResourceLoader &$resourceLoader ) {
|
||||
$testModules['qunit']['mmv.tests'] = array(
|
||||
'scripts' => array(
|
||||
'tests/qunit/mmv.testhelpers.js',
|
||||
'tests/qunit/mmv.bootstrap.test.js',
|
||||
'tests/qunit/mmv.test.js',
|
||||
'tests/qunit/mmv.model.test.js',
|
||||
'tests/qunit/mmv/mmv.bootstrap.test.js',
|
||||
'tests/qunit/mmv/mmv.test.js',
|
||||
'tests/qunit/mmv/mmv.lightboxinterface.test.js',
|
||||
'tests/qunit/mmv/mmv.lightboximage.test.js',
|
||||
'tests/qunit/mmv/mmv.multilightbox.test.js',
|
||||
'tests/qunit/mmv/mmv.ThumbnailWidthCalculator.test.js',
|
||||
'tests/qunit/mmv/mmv.performance.test.js',
|
||||
'tests/qunit/mmv/mmv.logger.test.js',
|
||||
'tests/qunit/mmv/model/mmv.model.test.js',
|
||||
'tests/qunit/mmv/model/mmv.model.TaskQueue.test.js',
|
||||
'tests/qunit/mmv.ThumbnailWidthCalculator.test.js',
|
||||
'tests/qunit/provider/mmv.provider.Api.test.js',
|
||||
'tests/qunit/mmv.performance.test.js',
|
||||
'tests/qunit/provider/mmv.provider.ImageUsage.test.js',
|
||||
'tests/qunit/provider/mmv.provider.GlobalUsage.test.js',
|
||||
'tests/qunit/provider/mmv.provider.ImageInfo.test.js',
|
||||
'tests/qunit/provider/mmv.provider.FileRepoInfo.test.js',
|
||||
'tests/qunit/provider/mmv.provider.ThumbnailInfo.test.js',
|
||||
'tests/qunit/provider/mmv.provider.UserInfo.test.js',
|
||||
'tests/qunit/provider/mmv.provider.Image.test.js',
|
||||
'tests/qunit/mmv.lightboxinterface.test.js',
|
||||
'tests/qunit/mmv.ui.test.js',
|
||||
'tests/qunit/mmv.ui.categories.test.js',
|
||||
'tests/qunit/mmv.ui.description.test.js',
|
||||
'tests/qunit/mmv.ui.fileUsage.test.js',
|
||||
'tests/qunit/mmv.ui.metadataPanel.test.js',
|
||||
'tests/qunit/mmv.ui.permission.test.js',
|
||||
'tests/qunit/lightboximage.test.js',
|
||||
'tests/qunit/lightboxinterface.test.js',
|
||||
'tests/qunit/multilightbox.test.js',
|
||||
'tests/qunit/mmv.logger.test.js',
|
||||
'tests/qunit/mmv/provider/mmv.provider.Api.test.js',
|
||||
'tests/qunit/mmv/provider/mmv.provider.ImageUsage.test.js',
|
||||
'tests/qunit/mmv/provider/mmv.provider.GlobalUsage.test.js',
|
||||
'tests/qunit/mmv/provider/mmv.provider.ImageInfo.test.js',
|
||||
'tests/qunit/mmv/provider/mmv.provider.FileRepoInfo.test.js',
|
||||
'tests/qunit/mmv/provider/mmv.provider.ThumbnailInfo.test.js',
|
||||
'tests/qunit/mmv/provider/mmv.provider.UserInfo.test.js',
|
||||
'tests/qunit/mmv/provider/mmv.provider.Image.test.js',
|
||||
'tests/qunit/mmv/ui/mmv.ui.test.js',
|
||||
'tests/qunit/mmv/ui/mmv.ui.categories.test.js',
|
||||
'tests/qunit/mmv/ui/mmv.ui.description.test.js',
|
||||
'tests/qunit/mmv/ui/mmv.ui.fileUsage.test.js',
|
||||
'tests/qunit/mmv/ui/mmv.ui.metadataPanel.test.js',
|
||||
'tests/qunit/mmv/ui/mmv.ui.permission.test.js',
|
||||
'tests/qunit/mmv/mmv.testhelpers.js',
|
||||
),
|
||||
'dependencies' => array(
|
||||
'mmv',
|
||||
|
|
|
@ -14,27 +14,6 @@
|
|||
* <https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Title>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class mlb
|
||||
* @singleton
|
||||
* Upstream multilightbox object
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class mlb.LightboxImage
|
||||
* Upstream object to represent an image
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class mlb.LightboxInterface
|
||||
* Upstream object that represents the lightbox interface
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class mlb.MultiLightbox
|
||||
* Upstream controller object
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class HTMLElement
|
||||
* An HTML element.
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
function MultimediaViewer() {
|
||||
/**
|
||||
* MultiLightbox object used to display the pictures in the page.
|
||||
* @property {mlb.MultiLightbox}
|
||||
* @property {mw.MultiLightbox}
|
||||
* @private
|
||||
*/
|
||||
this.lightbox = null;
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
* along with MultimediaViewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
( function ( mw, $, oo, MLBImage ) {
|
||||
( function ( mw, $ ) {
|
||||
|
||||
/**
|
||||
* Represents an image on the page.
|
||||
* @class mw.LightboxImage
|
||||
* @extends mlb.LightboxImage
|
||||
* @constructor
|
||||
* @param {string} fileLink Link to the file - generally a thumb URL
|
||||
* @param {string} filePageLink Link to the File: page
|
||||
|
@ -29,7 +29,8 @@
|
|||
* @param {string} [caption] The caption, if any.
|
||||
*/
|
||||
function LightboxImage( fileLink, filePageLink, fileTitle, index, thumb, caption ) {
|
||||
MLBImage.call( this, fileLink );
|
||||
/** @property {string} Link to the file - generally a thumb URL */
|
||||
this.src = fileLink;
|
||||
|
||||
/** @property {string} filePageLink URL to the image's file page */
|
||||
this.filePageLink = filePageLink;
|
||||
|
@ -47,7 +48,115 @@
|
|||
this.caption = caption;
|
||||
}
|
||||
|
||||
oo.inheritClass( LightboxImage, MLBImage );
|
||||
var LIP = LightboxImage.prototype;
|
||||
|
||||
/**
|
||||
* The URL of the image (in the size we intend use to display the it in the lightbox)
|
||||
* @type {String}
|
||||
* @protected
|
||||
*/
|
||||
LIP.src = null;
|
||||
|
||||
/**
|
||||
* The URL of a placeholder while the image loads. Typically a smaller version of the image, which is already
|
||||
* loaded in the browser.
|
||||
* @type {String}
|
||||
* @return {jQuery.Promise.<mw.LightboxImage, HTMLImageElement>}
|
||||
* @protected
|
||||
*/
|
||||
LIP.initialSrc = null;
|
||||
|
||||
/**
|
||||
* Loads the image.
|
||||
* FIXME we probably don't use this.
|
||||
* @return {jQuery.Promise.<HTMLImageElement>}
|
||||
*/
|
||||
LIP.getImageElement = function () {
|
||||
var ele,
|
||||
$deferred = $.Deferred(),
|
||||
image = this;
|
||||
|
||||
ele = new Image();
|
||||
ele.addEventListener( 'error', $deferred.reject );
|
||||
ele.addEventListener( 'load', function() { $deferred.resolve( image, ele ); } );
|
||||
|
||||
if ( this.src !== this.initialSrc ) {
|
||||
ele.src = this.src;
|
||||
} else {
|
||||
// Don't display the thumb, pretend that we did load the image
|
||||
// This is a workaround until we decide whether we want to display a nicer version of the thumb or not
|
||||
$deferred.resolve( image, ele );
|
||||
}
|
||||
|
||||
return $deferred;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resizes the image.
|
||||
* Assumes that the parent element's size is the maximum size.
|
||||
* FIXME refactor and document better
|
||||
*/
|
||||
LIP.autoResize = function ( ele, $parent ) {
|
||||
function updateRatios() {
|
||||
if ( imgHeight ) {
|
||||
imgHeightRatio = parentHeight / imgHeight;
|
||||
}
|
||||
|
||||
if ( imgWidth ) {
|
||||
imgWidthRatio = parentWidth / imgWidth;
|
||||
}
|
||||
}
|
||||
|
||||
var imgWidthRatio, imgHeightRatio, parentWidth, parentHeight,
|
||||
$img = $( ele ),
|
||||
imgWidth = $img.width(),
|
||||
imgHeight = $img.height();
|
||||
|
||||
$parent = $parent || $img.parent();
|
||||
parentWidth = $parent.width();
|
||||
parentHeight = $parent.height();
|
||||
|
||||
if ( this.globalMaxWidth && parentWidth > this.globalMaxWidth ) {
|
||||
parentWidth = this.globalMaxWidth;
|
||||
}
|
||||
|
||||
if ( this.globalMaxHeight && parentHeight > this.globalMaxHeight ) {
|
||||
parentHeight = this.globalMaxHeight;
|
||||
}
|
||||
|
||||
updateRatios();
|
||||
|
||||
if ( imgWidth > parentWidth ) {
|
||||
imgHeight *= imgWidthRatio || 1;
|
||||
imgWidth = parentWidth;
|
||||
updateRatios();
|
||||
}
|
||||
|
||||
if ( imgHeight > parentHeight ) {
|
||||
imgWidth *= imgHeightRatio || 1;
|
||||
imgHeight = parentHeight;
|
||||
updateRatios();
|
||||
}
|
||||
|
||||
if ( imgWidth < parentWidth && imgHeight < parentHeight ) {
|
||||
if ( imgWidth === 0 && imgHeight === 0 ) {
|
||||
// Only set one
|
||||
imgWidth = parentWidth;
|
||||
imgHeight = null;
|
||||
} else {
|
||||
if ( imgHeightRatio > imgWidthRatio ) {
|
||||
imgWidth *= imgHeightRatio;
|
||||
imgHeight = parentHeight;
|
||||
} else {
|
||||
imgHeight *= imgWidthRatio;
|
||||
imgWidth = parentWidth;
|
||||
}
|
||||
updateRatios();
|
||||
}
|
||||
}
|
||||
|
||||
$img.width( imgWidth ).height( imgHeight );
|
||||
};
|
||||
|
||||
mw.LightboxImage = LightboxImage;
|
||||
}( mediaWiki, jQuery, OO, window.LightboxImage ) );
|
||||
}( mediaWiki, jQuery ) );
|
||||
|
|
|
@ -15,18 +15,15 @@
|
|||
* along with MultimediaViewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
( function ( mw, $, oo, MLBInterface ) {
|
||||
( function ( mw, $ ) {
|
||||
var LIP;
|
||||
|
||||
/**
|
||||
* Represents the main interface of the lightbox
|
||||
* Represents the main interface of the lightbox
|
||||
* @class mw.LightboxInterface
|
||||
* @extends mlb.LightboxInterface
|
||||
* @constructor
|
||||
*/
|
||||
function LightboxInterface( viewer ) {
|
||||
MLBInterface.call( this );
|
||||
|
||||
this.viewer = viewer;
|
||||
|
||||
this.eventsRegistered = {};
|
||||
|
@ -37,17 +34,92 @@
|
|||
*/
|
||||
this.thumbnailWidthCalculator = new mw.mmv.ThumbnailWidthCalculator();
|
||||
|
||||
|
||||
this.initializeInterface();
|
||||
this.init();
|
||||
}
|
||||
|
||||
oo.inheritClass( LightboxInterface, MLBInterface );
|
||||
|
||||
LIP = LightboxInterface.prototype;
|
||||
|
||||
/**
|
||||
* The currently selected LightboxImage.
|
||||
* @type {mw.LightboxImage}
|
||||
* @protected
|
||||
*/
|
||||
LIP.currentImage = null;
|
||||
|
||||
/**
|
||||
* Initialize the entire interface - helper method.
|
||||
*/
|
||||
LIP.init = function () {
|
||||
var addToPre = [],
|
||||
addToPost = [],
|
||||
lbinterface = this;
|
||||
|
||||
// Staging area for image resizes
|
||||
this.$staging = $( '<div>' )
|
||||
.addClass( 'mlb-staging-area' );
|
||||
$( document.body ).append( this.$staging );
|
||||
|
||||
this.$overlay = $( '<div>' )
|
||||
.addClass( 'mlb-overlay' );
|
||||
|
||||
this.$wrapper = $( '<div>' )
|
||||
.addClass( 'mlb-wrapper' );
|
||||
|
||||
this.$main = $( '<div>' )
|
||||
.addClass( 'mlb-main' );
|
||||
|
||||
this.$imageDiv = $( '<div>' )
|
||||
.addClass( 'mlb-image' );
|
||||
|
||||
// I blame CSS for this
|
||||
this.$innerWrapper = $( '<div>' )
|
||||
.addClass( 'mlb-image-inner-wrapper' )
|
||||
.append( this.$imageDiv );
|
||||
|
||||
this.$imageWrapper = $( '<div>' )
|
||||
.addClass( 'mlb-image-wrapper' )
|
||||
.append( this.$innerWrapper );
|
||||
|
||||
this.$preDiv = $( '<div>' )
|
||||
.addClass( 'mlb-pre-image' );
|
||||
this.setupPreDiv( addToPre );
|
||||
|
||||
this.$postDiv = $( '<div>' )
|
||||
.addClass( 'mlb-post-image' );
|
||||
this.setupPostDiv( addToPost );
|
||||
|
||||
this.$main.append(
|
||||
this.$preDiv,
|
||||
this.$imageWrapper,
|
||||
this.$postDiv
|
||||
);
|
||||
|
||||
this.$wrapper.append(
|
||||
this.$main
|
||||
);
|
||||
|
||||
window.addEventListener( 'keyup', function ( e ) {
|
||||
if ( e.keyCode === 27 ) {
|
||||
// Escape button pressed
|
||||
lbinterface.unattach();
|
||||
}
|
||||
} );
|
||||
|
||||
this.panel = new mw.mmv.ui.MetadataPanel( this.$postDiv, this.$controlBar );
|
||||
this.buttons = new mw.mmv.ui.Buttons( this.$imageWrapper, this.$closeButton, this.$fullscreenButton );
|
||||
this.initializeImage();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the image element.
|
||||
*/
|
||||
LIP.initializeImage = function () {
|
||||
this.$imageDiv
|
||||
.addClass( 'empty' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Empties the interface.
|
||||
* @override
|
||||
*/
|
||||
LIP.empty = function () {
|
||||
this.clearEvents();
|
||||
|
@ -55,8 +127,12 @@
|
|||
this.panel.empty();
|
||||
|
||||
this.$imageDiv.addClass( 'empty' );
|
||||
this.$imageDiv.empty();
|
||||
|
||||
MLBInterface.prototype.empty.call( this );
|
||||
if ( this.resizeListener ) {
|
||||
window.removeEventListener( 'resize', this.resizeListener );
|
||||
this.resizeListener = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -93,10 +169,13 @@
|
|||
|
||||
/**
|
||||
* Attaches the interface to the DOM.
|
||||
* @override
|
||||
* @param {string} parentId ID of the element that we should attach to.
|
||||
* @param {string} [parentId] parent id where we want to attach the UI. Defaults to document
|
||||
* element, override is mainly used for testing.
|
||||
*/
|
||||
LIP.attach = function ( parentId ) {
|
||||
var lbinterface = this,
|
||||
$parent;
|
||||
|
||||
// Advanced description needs to be below the fold when the lightbox opens
|
||||
// regardless of what the scroll value was prior to opening the lightbox
|
||||
|
||||
|
@ -114,7 +193,30 @@
|
|||
// reading the DOM at this point of the execution, unfortunately
|
||||
this.$postDiv.css( 'top', ( $( window ).height() - 83 ) + 'px' );
|
||||
|
||||
MLBInterface.prototype.attach.call( this, parentId );
|
||||
// Re-appending the same content can have nasty side-effects
|
||||
// Such as the browser leaving fullscreen mode if the fullscreened element is part of it
|
||||
if ( this.currentlyAttached ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$( document ).on( 'jq-fullscreen-change.lip', function( e ) {
|
||||
lbinterface.fullscreenChange( e );
|
||||
} );
|
||||
|
||||
$parent = $( parentId || document.body );
|
||||
|
||||
// Clean up fullscreen data because hard-existing fullscreen might have left
|
||||
// jquery.fullscreen unable to remove the class and attribute, since $main wasn't
|
||||
// attached to the DOM anymore at the time the jq-fullscreen-change event triggered
|
||||
this.$main.data( 'isFullscreened', false ).removeClass( 'jq-fullscreened' );
|
||||
this.isFullscreen = false;
|
||||
|
||||
$parent
|
||||
.append(
|
||||
this.$wrapper,
|
||||
this.$overlay
|
||||
);
|
||||
this.currentlyAttached = true;
|
||||
|
||||
this.panel.attach();
|
||||
|
||||
|
@ -126,10 +228,17 @@
|
|||
|
||||
/**
|
||||
* Detaches the interface from the DOM.
|
||||
* @override
|
||||
*/
|
||||
LIP.unattach = function () {
|
||||
MLBInterface.prototype.unattach.call( this );
|
||||
// We trigger this event on the document because unattach() can run
|
||||
// when the interface is unattached
|
||||
$( document ).trigger( $.Event( 'mmv-close' ) )
|
||||
.off( 'jq-fullscreen-change.lip' );
|
||||
|
||||
this.$wrapper.detach();
|
||||
this.$overlay.detach();
|
||||
|
||||
this.currentlyAttached = false;
|
||||
|
||||
this.panel.unattach();
|
||||
|
||||
|
@ -142,6 +251,58 @@
|
|||
this.panel.fileReuse.closeDialog();
|
||||
};
|
||||
|
||||
/**
|
||||
* Resize callback
|
||||
* @protected
|
||||
*/
|
||||
LIP.resizeCallback = function() {
|
||||
if ( this.currentlyAttached ) {
|
||||
this.$wrapper.trigger( $.Event( 'mmv-resize') );
|
||||
|
||||
this.autoResizeImage();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Displays an already loaded image.
|
||||
* This is an alternative to load() when we have an image element with the image already loaded.
|
||||
* @param {mw.LightboxImage} image
|
||||
* @param {HTMLImageElement } imageElement
|
||||
*/
|
||||
LIP.showImage = function( image, imageElement ) {
|
||||
var iface = this;
|
||||
|
||||
this.currentImage = image;
|
||||
image.globalMaxWidth = imageElement.width;
|
||||
image.globalMaxHeight = imageElement.height;
|
||||
this.$image = $( imageElement );
|
||||
|
||||
this.autoResizeImage();
|
||||
|
||||
// Capture listener so we can remove it later, otherwise
|
||||
// we are going to leak listeners !
|
||||
// FIXME should use clearEvents, probably
|
||||
if ( !this.resizeListener ) {
|
||||
this.resizeListener = function () { iface.resizeCallback(); };
|
||||
window.addEventListener( 'resize', this.resizeListener );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads the image, then calls the load callback of the interface.
|
||||
* @param {mw.LightboxImage} image
|
||||
*/
|
||||
LIP.load = function ( image ) {
|
||||
var iface = this;
|
||||
|
||||
this.setupForLoad();
|
||||
|
||||
this.currentImage = image;
|
||||
|
||||
image.getImageElement().done( function( image, ele ) {
|
||||
iface.showImage( image, ele );
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* FIXME A bunch of stuff ripped out of #load, because load tries to actually load the image
|
||||
* and causes the small-thumbnail-for-a-moment bug in the process. Needs severe refactoring.
|
||||
|
@ -168,34 +329,16 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* Loads an image into the interface.
|
||||
* @override
|
||||
* FIXME refactor and document
|
||||
*/
|
||||
LIP.load = function ( image ) {
|
||||
this.setupForLoad();
|
||||
MLBInterface.prototype.load.call( this, image );
|
||||
LIP.autoResizeImage = function () {
|
||||
this.$staging.append( this.$image );
|
||||
this.currentImage.autoResize( this.$image.get( 0 ), this.$imageDiv );
|
||||
this.$imageDiv.append( this.$image );
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the entire interface - helper method.
|
||||
*/
|
||||
LIP.initializeInterface = function () {
|
||||
this.panel = new mw.mmv.ui.MetadataPanel( this.$postDiv, this.$controlBar );
|
||||
this.buttons = new mw.mmv.ui.Buttons( this.$imageWrapper, this.$closeButton, this.$fullscreenButton );
|
||||
this.initializeImage();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize the image element.
|
||||
*/
|
||||
LIP.initializeImage = function () {
|
||||
this.$imageDiv
|
||||
.addClass( 'empty' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Load a new image element into the interface.
|
||||
* @override
|
||||
* Changes what image is being displayed.
|
||||
* @param {HTMLImageElement} imageEle
|
||||
*/
|
||||
LIP.replaceImageWith = function ( imageEle ) {
|
||||
|
@ -214,15 +357,111 @@
|
|||
maxHeight: $image.parent().height(),
|
||||
maxWidth: $image.parent().width()
|
||||
} );
|
||||
|
||||
/*
|
||||
FIXME MLB has this code but it was overridden and never invoked; kept for reference until resize bugs are fixed
|
||||
this.currentImage.globalMaxWidth = this.$image.width();
|
||||
this.currentImage.globalMaxHeight = this.$image.height();
|
||||
this.currentImage.autoResize( imageEle );
|
||||
*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Exits fullscreen mode.
|
||||
*/
|
||||
LIP.exitFullscreen = function () {
|
||||
this.fullscreenButtonJustPressed = true;
|
||||
this.$main.exitFullscreen();
|
||||
};
|
||||
|
||||
/**
|
||||
* Enters fullscreen mode.
|
||||
*/
|
||||
LIP.enterFullscreen = function () {
|
||||
this.$main.enterFullscreen();
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup for DOM elements which come before the main image
|
||||
* @param {Array.<HTMLElement|jQuery>} toAdd
|
||||
*/
|
||||
LIP.setupPreDiv = function ( toAdd ) {
|
||||
var lbinterface = this;
|
||||
|
||||
this.$controlBar = $( '<div>' )
|
||||
.addClass( 'mlb-controls' );
|
||||
|
||||
this.$closeButton = $( '<div>' )
|
||||
.text( ' ' )
|
||||
.addClass( 'mlb-close' )
|
||||
.click( function () {
|
||||
lbinterface.unattach();
|
||||
} );
|
||||
|
||||
this.$fullscreenButton = $( '<div>' )
|
||||
.text( ' ' )
|
||||
.addClass( 'mlb-fullscreen' )
|
||||
.click( function () {
|
||||
if ( lbinterface.isFullscreen ) {
|
||||
lbinterface.exitFullscreen();
|
||||
} else {
|
||||
lbinterface.enterFullscreen();
|
||||
}
|
||||
} );
|
||||
|
||||
this.setupFullscreenButton();
|
||||
|
||||
this.$controlBar.append(
|
||||
this.$closeButton,
|
||||
this.$fullscreenButton
|
||||
);
|
||||
|
||||
this.$preDiv.append( this.$controlBar );
|
||||
|
||||
this.addElementsToDiv( this.$preDiv, toAdd );
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets up the fullscreen button
|
||||
*/
|
||||
LIP.setupFullscreenButton = function () {
|
||||
// If the browser doesn't support fullscreen mode, hide the fullscreen button
|
||||
if ( $.support.fullscreen ) {
|
||||
this.$fullscreenButton.show();
|
||||
} else {
|
||||
this.$fullscreenButton.hide();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup for DOM elements which come before the main image
|
||||
* @param {Array.<HTMLElement|jQuery>} toAdd
|
||||
*/
|
||||
LIP.setupPostDiv = function ( toAdd ) {
|
||||
this.addElementsToDiv( this.$postDiv, toAdd );
|
||||
};
|
||||
|
||||
LIP.addElementsToDiv = function ( $div, toAdd ) {
|
||||
var i;
|
||||
|
||||
for ( i = 0; i < toAdd.length; i++ ) {
|
||||
$div.append( toAdd[i] );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a fullscreen change event.
|
||||
* @override
|
||||
* @param {jQuery.Event} e The fullscreen change event.
|
||||
*/
|
||||
LIP.fullscreenChange = function( e ) {
|
||||
MLBInterface.prototype.fullscreenChange.call( this, e );
|
||||
LIP.fullscreenChange = function ( e ) {
|
||||
this.isFullscreen = e.fullscreen;
|
||||
|
||||
if ( !this.fullscreenButtonJustPressed && !e.fullscreen ) {
|
||||
// Close the interface all the way if the user pressed 'esc'
|
||||
this.unattach();
|
||||
} else if ( this.fullscreenButtonJustPressed ) {
|
||||
this.fullscreenButtonJustPressed = false;
|
||||
}
|
||||
|
||||
// Fullscreen change events can happen after unattach(), in which
|
||||
// case we shouldn't do anything UI-related
|
||||
|
@ -286,28 +525,10 @@
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the next and prev buttons
|
||||
* @param {boolean} showPrevButton Whether the prev button should be revealed or not
|
||||
* @param {boolean} showNextButton Whether the next button should be revealed or not
|
||||
*/
|
||||
LIP.updateControls = function ( showPrevButton, showNextButton ) {
|
||||
var prevNextTop = ( ( this.$imageWrapper.height() / 2 ) - 60 ) + 'px';
|
||||
|
||||
if ( this.$main.data( 'isFullscreened' ) ) {
|
||||
this.$postDiv.css( 'top', '' );
|
||||
} else {
|
||||
this.$postDiv.css( 'top', this.$imageWrapper.height() );
|
||||
}
|
||||
|
||||
this.buttons.setOffset( prevNextTop );
|
||||
this.buttons.toggle( showPrevButton, showNextButton );
|
||||
};
|
||||
|
||||
/**
|
||||
* @method
|
||||
* Gets the widths for a given lightbox image.
|
||||
* @param {mlb.LightboxImage} image
|
||||
* @param {mw.LightboxImage} image
|
||||
* @returns {mw.mmv.model.ThumbnailWidth}
|
||||
*/
|
||||
LIP.getLightboxImageWidths = function ( image ) {
|
||||
|
@ -321,7 +542,7 @@
|
|||
* Gets the fullscreen widths for a given lightbox image.
|
||||
* Intended for use before the viewer is in fullscreen mode
|
||||
* (in fullscreen mode getLightboxImageWidths() works fine).
|
||||
* @param {mlb.LightboxImage} image
|
||||
* @param {mw.LightboxImage} image
|
||||
* @returns {mw.mmv.model.ThumbnailWidth}
|
||||
*/
|
||||
LIP.getLightboxImageWidthsForFullscreen = function ( image ) {
|
||||
|
@ -340,7 +561,6 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* @method
|
||||
* Called when the buttons have completely faded out and disappeared
|
||||
*/
|
||||
LIP.fadedOut = function () {
|
||||
|
@ -348,12 +568,29 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* @method
|
||||
* Called when the buttons have stopped fading and are back into view
|
||||
*/
|
||||
LIP.fadeStopped = function () {
|
||||
this.$main.removeClass( 'cursor-hidden' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the next and prev buttons
|
||||
* @param {boolean} showPrevButton Whether the prev button should be revealed or not
|
||||
* @param {boolean} showNextButton Whether the next button should be revealed or not
|
||||
*/
|
||||
LIP.updateControls = function ( showPrevButton, showNextButton ) {
|
||||
var prevNextTop = ( ( this.$imageWrapper.height() / 2 ) - 60 ) + 'px';
|
||||
|
||||
if ( this.$main.data( 'isFullscreened' ) ) {
|
||||
this.$postDiv.css( 'top', '' );
|
||||
} else {
|
||||
this.$postDiv.css( 'top', this.$imageWrapper.height() );
|
||||
}
|
||||
|
||||
this.buttons.setOffset( prevNextTop );
|
||||
this.buttons.toggle( showPrevButton, showNextButton );
|
||||
};
|
||||
|
||||
mw.LightboxInterface = LightboxInterface;
|
||||
}( mediaWiki, jQuery, OO, window.LightboxInterface ) );
|
||||
}( mediaWiki, jQuery ) );
|
||||
|
|
|
@ -15,26 +15,61 @@
|
|||
* along with MultimediaViewer. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
( function ( mw, $, oo, MLBLightbox ) {
|
||||
( function ( mw ) {
|
||||
var MLBP;
|
||||
|
||||
/**
|
||||
* Some interface functions for MMV.
|
||||
* FIXME merge with Lightboxinterface, figure out better separation of responsibilities
|
||||
* @class mw.MultiLightbox
|
||||
* @extends mlb.MultiLightbox
|
||||
* @inheritdoc
|
||||
* @constructor
|
||||
* @param {number} initial
|
||||
* @param {Function} InterfaceClass type of interface to use
|
||||
* @param {mw.MultimediaViewer} viewer
|
||||
*/
|
||||
function MultiLightbox( initial, InterfaceClass, viewer ) {
|
||||
this.initializeInterface = function ( InterfaceClass ) {
|
||||
InterfaceClass = InterfaceClass || window.LightboxInterface;
|
||||
this.iface = new InterfaceClass( viewer );
|
||||
};
|
||||
|
||||
MLBLightbox.call( this, initial, InterfaceClass );
|
||||
this.currentIndex = initial || 0;
|
||||
this.onInterfaceReady = [];
|
||||
this.iface = new InterfaceClass( viewer );
|
||||
this.interfaceReady();
|
||||
}
|
||||
|
||||
oo.inheritClass( MultiLightbox, MLBLightbox );
|
||||
MLBP = MultiLightbox.prototype;
|
||||
|
||||
/**
|
||||
* Schedules stuff to run when IF is ready (or fires it immediately if it is already).
|
||||
* TODO replace with event or promise
|
||||
* @param {function()} func
|
||||
*/
|
||||
MLBP.onInterface = function ( func ) {
|
||||
if ( this.onInterfaceReady !== undefined ) {
|
||||
this.onInterfaceReady.push( func );
|
||||
} else {
|
||||
func();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface ready "event"
|
||||
* TODO replace with real event or promise
|
||||
*/
|
||||
MLBP.interfaceReady = function () {
|
||||
var i;
|
||||
|
||||
for ( i = 0; i < this.onInterfaceReady.length; i++ ) {
|
||||
this.onInterfaceReady[i]();
|
||||
}
|
||||
|
||||
this.onInterfaceReady = undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens the lightbox.
|
||||
*/
|
||||
MLBP.open = function () {
|
||||
this.iface.empty();
|
||||
this.iface.attach();
|
||||
};
|
||||
|
||||
mw.MultiLightbox = MultiLightbox;
|
||||
}( mediaWiki, jQuery, OO, window.MultiLightbox ) );
|
||||
}( mediaWiki ) );
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import "../mmv/ui/mmv.mixins";
|
||||
@import "ui/mmv.mixins";
|
||||
|
||||
.mlb-staging-area {
|
||||
position: absolute;
|
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="32px" height="32px"><path style="fill:none;stroke:#FFFFFF;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 8,24 24,8" /><path style="fill:none;stroke:#FFFFFF;stroke-width:4px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 8,8 24,24" /></svg>
|
Before Width: | Height: | Size: 519 B |
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="32px" height="32px"><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 14,18 8,24" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 18,14 24,8" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" d="M 10,18 14,18" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" d="M 14,22 14,18" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" d="M 18,10 18,14" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" d="M 22,14 18,14" /></svg>
|
Before Width: | Height: | Size: 971 B |
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="32px" height="32px"><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 14,18 8,24" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M 18,14 24,8" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" d="M 8,20 8,24" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" d="M 12,24 8,24" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" d="M 20,8 24,8" /><path style="fill:none;stroke:#FFFFFF;stroke-width:3px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" d="M 24,12 24,8" /></svg>
|
Before Width: | Height: | Size: 965 B |
|
@ -1,113 +0,0 @@
|
|||
( function ( $ ) {
|
||||
/**
|
||||
* @class mlb.LightboxImage
|
||||
* @constructor
|
||||
* @param {string} src The URL (possibly relative) to the image
|
||||
*/
|
||||
function LightboxImage( src ) {
|
||||
this.src = src;
|
||||
}
|
||||
|
||||
var LIP = LightboxImage.prototype;
|
||||
|
||||
/**
|
||||
* The URL of the image (in the size we intend use to display the it in the lightbox)
|
||||
* @type {String}
|
||||
* @protected
|
||||
*/
|
||||
LIP.src = null;
|
||||
|
||||
/**
|
||||
* The URL of a placeholder while the image loads. Typically a smaller version of the image, which is already
|
||||
* loaded in the browser.
|
||||
* @type {String}
|
||||
* @return {jQuery.Promise.<mlb.LightboxImage, HTMLImageElement>}
|
||||
* @protected
|
||||
*/
|
||||
LIP.initialSrc = null;
|
||||
|
||||
LIP.getImageElement = function () {
|
||||
var ele,
|
||||
$deferred = $.Deferred(),
|
||||
image = this;
|
||||
|
||||
ele = new Image();
|
||||
ele.addEventListener( 'error', $deferred.reject );
|
||||
ele.addEventListener( 'load', function() { $deferred.resolve( image, ele ); } );
|
||||
|
||||
if ( this.src !== this.initialSrc ) {
|
||||
ele.src = this.src;
|
||||
} else {
|
||||
// Don't display the thumb, pretend that we did load the image
|
||||
// This is a workaround until we decide whether we want to display a nicer version of the thumb or not
|
||||
$deferred.resolve( image, ele );
|
||||
}
|
||||
|
||||
return $deferred;
|
||||
};
|
||||
|
||||
// Assumes that the parent element's size is the maximum size.
|
||||
LIP.autoResize = function ( ele, $parent ) {
|
||||
function updateRatios() {
|
||||
if ( imgHeight ) {
|
||||
imgHeightRatio = parentHeight / imgHeight;
|
||||
}
|
||||
|
||||
if ( imgWidth ) {
|
||||
imgWidthRatio = parentWidth / imgWidth;
|
||||
}
|
||||
}
|
||||
|
||||
var imgWidthRatio, imgHeightRatio, parentWidth, parentHeight,
|
||||
$img = $( ele ),
|
||||
imgWidth = $img.width(),
|
||||
imgHeight = $img.height();
|
||||
|
||||
$parent = $parent || $img.parent();
|
||||
parentWidth = $parent.width();
|
||||
parentHeight = $parent.height();
|
||||
|
||||
if ( this.globalMaxWidth && parentWidth > this.globalMaxWidth ) {
|
||||
parentWidth = this.globalMaxWidth;
|
||||
}
|
||||
|
||||
if ( this.globalMaxHeight && parentHeight > this.globalMaxHeight ) {
|
||||
parentHeight = this.globalMaxHeight;
|
||||
}
|
||||
|
||||
updateRatios();
|
||||
|
||||
if ( imgWidth > parentWidth ) {
|
||||
imgHeight *= imgWidthRatio || 1;
|
||||
imgWidth = parentWidth;
|
||||
updateRatios();
|
||||
}
|
||||
|
||||
if ( imgHeight > parentHeight ) {
|
||||
imgWidth *= imgHeightRatio || 1;
|
||||
imgHeight = parentHeight;
|
||||
updateRatios();
|
||||
}
|
||||
|
||||
if ( imgWidth < parentWidth && imgHeight < parentHeight ) {
|
||||
if ( imgWidth === 0 && imgHeight === 0 ) {
|
||||
// Only set one
|
||||
imgWidth = parentWidth;
|
||||
imgHeight = null;
|
||||
} else {
|
||||
if ( imgHeightRatio > imgWidthRatio ) {
|
||||
imgWidth *= imgHeightRatio;
|
||||
imgHeight = parentHeight;
|
||||
} else {
|
||||
imgHeight *= imgWidthRatio;
|
||||
imgWidth = parentWidth;
|
||||
}
|
||||
updateRatios();
|
||||
}
|
||||
}
|
||||
|
||||
$img.width( imgWidth ).height( imgHeight );
|
||||
};
|
||||
|
||||
window.LightboxImage = LightboxImage;
|
||||
}( jQuery ) );
|
|
@ -1,283 +0,0 @@
|
|||
( function ( $ ) {
|
||||
var LIP;
|
||||
|
||||
/**
|
||||
* @class mlb.LightboxInterface
|
||||
* @constructor
|
||||
*/
|
||||
function LightboxInterface() {
|
||||
var addToPre = [],
|
||||
addToPost = [],
|
||||
lbinterface = this;
|
||||
|
||||
// Staging area for image resizes
|
||||
this.$staging = $( '<div>' )
|
||||
.addClass( 'mlb-staging-area' );
|
||||
$( document.body ).append( this.$staging );
|
||||
|
||||
this.$overlay = $( '<div>' )
|
||||
.addClass( 'mlb-overlay' );
|
||||
|
||||
this.$wrapper = $( '<div>' )
|
||||
.addClass( 'mlb-wrapper' );
|
||||
|
||||
this.$main = $( '<div>' )
|
||||
.addClass( 'mlb-main' );
|
||||
|
||||
this.$imageDiv = $( '<div>' )
|
||||
.addClass( 'mlb-image' );
|
||||
|
||||
// I blame CSS for this
|
||||
this.$innerWrapper = $( '<div>' )
|
||||
.addClass( 'mlb-image-inner-wrapper' )
|
||||
.append( this.$imageDiv );
|
||||
|
||||
this.$imageWrapper = $( '<div>' )
|
||||
.addClass( 'mlb-image-wrapper' )
|
||||
.append( this.$innerWrapper );
|
||||
|
||||
this.$preDiv = $( '<div>' )
|
||||
.addClass( 'mlb-pre-image' );
|
||||
this.setupPreDiv( addToPre );
|
||||
|
||||
this.$postDiv = $( '<div>' )
|
||||
.addClass( 'mlb-post-image' );
|
||||
this.setupPostDiv( addToPost );
|
||||
|
||||
this.$main.append(
|
||||
this.$preDiv,
|
||||
this.$imageWrapper,
|
||||
this.$postDiv
|
||||
);
|
||||
|
||||
this.$wrapper.append(
|
||||
this.$main
|
||||
);
|
||||
|
||||
window.addEventListener( 'keyup', function ( e ) {
|
||||
if ( e.keyCode === 27 ) {
|
||||
// Escape button pressed
|
||||
lbinterface.unattach();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
LIP = LightboxInterface.prototype;
|
||||
|
||||
/**
|
||||
* The currently selected LightboxImage.
|
||||
* @type {mlb.LightboxImage}
|
||||
* @protected
|
||||
*/
|
||||
LIP.currentImage = null;
|
||||
|
||||
LIP.empty = function () {
|
||||
this.$imageDiv.empty();
|
||||
|
||||
if ( this.resizeListener ) {
|
||||
window.removeEventListener( 'resize', this.resizeListener );
|
||||
this.resizeListener = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches interface to document or given parent id.
|
||||
*
|
||||
* @param {string} [parentId] parent id where we want to attach the UI. Mainly for testing.
|
||||
*/
|
||||
LIP.attach = function ( parentId ) {
|
||||
var lbinterface = this,
|
||||
$parent;
|
||||
|
||||
// Re-appending the same content can have nasty side-effects
|
||||
// Such as the browser leaving fullscreen mode if the fullscreened element is part of it
|
||||
if ( this.currentlyAttached ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$( document ).on( 'jq-fullscreen-change.lip', function( e ) {
|
||||
lbinterface.fullscreenChange( e );
|
||||
} );
|
||||
|
||||
$parent = $( parentId || document.body );
|
||||
|
||||
// Clean up fullscreen data because hard-existing fullscreen might have left
|
||||
// jquery.fullscreen unable to remove the class and attribute, since $main wasn't
|
||||
// attached to the DOM anymore at the time the jq-fullscreen-change event triggered
|
||||
this.$main.data( 'isFullscreened', false ).removeClass( 'jq-fullscreened' );
|
||||
this.isFullscreen = false;
|
||||
|
||||
$parent
|
||||
.append(
|
||||
this.$wrapper,
|
||||
this.$overlay
|
||||
);
|
||||
this.currentlyAttached = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unattaches interface from parent element.
|
||||
*/
|
||||
LIP.unattach = function () {
|
||||
// We trigger this event on the document because unattach() can run
|
||||
// when the interface is unattached
|
||||
$( document ).trigger( $.Event( 'mmv-close' ) )
|
||||
.off( 'jq-fullscreen-change.lip' );
|
||||
|
||||
this.$wrapper.detach();
|
||||
this.$overlay.detach();
|
||||
|
||||
this.currentlyAttached = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resize callback
|
||||
* @protected
|
||||
*/
|
||||
LIP.resizeCallback = function() {
|
||||
if ( this.currentlyAttached ) {
|
||||
this.$wrapper.trigger( $.Event( 'mmv-resize') );
|
||||
|
||||
this.autoResizeImage();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Displays an already loaded image.
|
||||
* This is an alternative to load() when we have an image element with the image already loaded.
|
||||
* @param {mlb.LightboxImage} image
|
||||
* @param {HTMLImageElement } imageElement
|
||||
*/
|
||||
LIP.showImage = function( image, imageElement ) {
|
||||
var iface = this;
|
||||
|
||||
this.currentImage = image;
|
||||
image.globalMaxWidth = imageElement.width;
|
||||
image.globalMaxHeight = imageElement.height;
|
||||
this.$image = $( imageElement );
|
||||
|
||||
this.autoResizeImage();
|
||||
|
||||
// Capture listener so we can remove it later, otherwise
|
||||
// we are going to leak listeners !
|
||||
if ( !this.resizeListener ) {
|
||||
this.resizeListener = function () { iface.resizeCallback(); };
|
||||
window.addEventListener( 'resize', this.resizeListener );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads the image, then calls the load callback of the interface.
|
||||
* @param {mlb.LightboxImage} image
|
||||
*/
|
||||
LIP.load = function ( image ) {
|
||||
var iface = this;
|
||||
|
||||
this.currentImage = image;
|
||||
|
||||
image.getImageElement().done( function( image, ele ) {
|
||||
iface.showImage( image, ele );
|
||||
} );
|
||||
};
|
||||
|
||||
LIP.autoResizeImage = function () {
|
||||
this.$staging.append( this.$image );
|
||||
this.currentImage.autoResize( this.$image.get( 0 ), this.$imageDiv );
|
||||
this.$imageDiv.append( this.$image );
|
||||
};
|
||||
|
||||
/**
|
||||
* Changes what image is being displayed.
|
||||
* @param {HTMLImageElement} imageEle
|
||||
*/
|
||||
LIP.replaceImageWith = function ( imageEle ) {
|
||||
var $image = $( imageEle );
|
||||
|
||||
this.currentImage.src = imageEle.src;
|
||||
|
||||
this.$image.replaceWith( $image );
|
||||
this.$image = $image;
|
||||
|
||||
this.currentImage.globalMaxWidth = this.$image.width();
|
||||
this.currentImage.globalMaxHeight = this.$image.height();
|
||||
this.currentImage.autoResize( imageEle );
|
||||
};
|
||||
|
||||
LIP.exitFullscreen = function () {
|
||||
this.fullscreenButtonJustPressed = true;
|
||||
this.$main.exitFullscreen();
|
||||
};
|
||||
|
||||
LIP.enterFullscreen = function () {
|
||||
this.$main.enterFullscreen();
|
||||
};
|
||||
|
||||
LIP.setupPreDiv = function ( toAdd ) {
|
||||
var lbinterface = this;
|
||||
|
||||
this.$controlBar = $( '<div>' )
|
||||
.addClass( 'mlb-controls' );
|
||||
|
||||
this.$closeButton = $( '<div>' )
|
||||
.text( ' ' )
|
||||
.addClass( 'mlb-close' )
|
||||
.click( function () {
|
||||
lbinterface.unattach();
|
||||
} );
|
||||
|
||||
this.$fullscreenButton = $( '<div>' )
|
||||
.text( ' ' )
|
||||
.addClass( 'mlb-fullscreen' )
|
||||
.click( function () {
|
||||
if ( lbinterface.isFullscreen ) {
|
||||
lbinterface.exitFullscreen();
|
||||
} else {
|
||||
lbinterface.enterFullscreen();
|
||||
}
|
||||
} );
|
||||
|
||||
this.setupFullscreenButton();
|
||||
|
||||
this.$controlBar.append(
|
||||
this.$closeButton,
|
||||
this.$fullscreenButton
|
||||
);
|
||||
|
||||
this.$preDiv.append( this.$controlBar );
|
||||
|
||||
this.addElementsToDiv( this.$preDiv, toAdd );
|
||||
};
|
||||
|
||||
LIP.setupFullscreenButton = function () {
|
||||
// If the browser doesn't support fullscreen mode, hide the fullscreen button
|
||||
if ( $.support.fullscreen ) {
|
||||
this.$fullscreenButton.show();
|
||||
} else {
|
||||
this.$fullscreenButton.hide();
|
||||
}
|
||||
};
|
||||
|
||||
LIP.setupPostDiv = function ( toAdd ) {
|
||||
this.addElementsToDiv( this.$postDiv, toAdd );
|
||||
};
|
||||
|
||||
LIP.addElementsToDiv = function ( $div, toAdd ) {
|
||||
var i;
|
||||
|
||||
for ( i = 0; i < toAdd.length; i++ ) {
|
||||
$div.append( toAdd[i] );
|
||||
}
|
||||
};
|
||||
|
||||
LIP.fullscreenChange = function ( e ) {
|
||||
this.isFullscreen = e.fullscreen;
|
||||
|
||||
if ( !this.fullscreenButtonJustPressed && !e.fullscreen ) {
|
||||
// Close the interface all the way if the user pressed 'esc'
|
||||
this.unattach();
|
||||
} else if ( this.fullscreenButtonJustPressed ) {
|
||||
this.fullscreenButtonJustPressed = false;
|
||||
}
|
||||
};
|
||||
|
||||
window.LightboxInterface = LightboxInterface;
|
||||
}( jQuery ) );
|
|
@ -1,52 +0,0 @@
|
|||
( function () {
|
||||
var MLBP;
|
||||
|
||||
/**
|
||||
* @class mlb.MultiLightbox
|
||||
* @constructor
|
||||
* @param {number} [start=0]
|
||||
* @param {Function} [InterfaceClass] type of interface to use
|
||||
*/
|
||||
function MultiLightbox( start, InterfaceClass ) {
|
||||
this.currentIndex = start || 0;
|
||||
this.onInterfaceReady = [];
|
||||
this.initializeInterface( InterfaceClass );
|
||||
this.interfaceReady();
|
||||
}
|
||||
|
||||
MLBP = MultiLightbox.prototype;
|
||||
|
||||
/**
|
||||
* Instantiates and initializes the interface object
|
||||
* @param {Function} [InterfaceClass] type of interface to use
|
||||
*/
|
||||
MLBP.initializeInterface = function ( InterfaceClass ) {
|
||||
InterfaceClass = InterfaceClass || window.LightboxInterface;
|
||||
this.iface = new InterfaceClass();
|
||||
};
|
||||
|
||||
MLBP.onInterface = function ( func ) {
|
||||
if ( this.onInterfaceReady !== undefined ) {
|
||||
this.onInterfaceReady.push( func );
|
||||
} else {
|
||||
func();
|
||||
}
|
||||
};
|
||||
|
||||
MLBP.interfaceReady = function () {
|
||||
var i;
|
||||
|
||||
for ( i = 0; i < this.onInterfaceReady.length; i++ ) {
|
||||
this.onInterfaceReady[i]();
|
||||
}
|
||||
|
||||
this.onInterfaceReady = undefined;
|
||||
};
|
||||
|
||||
MLBP.open = function () {
|
||||
this.iface.empty();
|
||||
this.iface.attach();
|
||||
};
|
||||
|
||||
window.MultiLightbox = MultiLightbox;
|
||||
}() );
|
|
@ -1,116 +0,0 @@
|
|||
( function ( mw, $ ) {
|
||||
QUnit.module( 'multilightbox.interface', QUnit.newMwEnvironment() );
|
||||
|
||||
QUnit.test( 'Sanity test, object creation and ui construction', 9, function ( assert ) {
|
||||
var lightbox = new window.LightboxInterface();
|
||||
|
||||
function checkIfUIAreasAttachedToDocument( inDocument ) {
|
||||
var msg = inDocument === 1 ? ' ' : ' not ';
|
||||
assert.strictEqual( $( '.mlb-wrapper' ).length, inDocument, 'Wrapper area' + msg + 'attached.' );
|
||||
assert.strictEqual( $( '.mlb-main' ).length, inDocument, 'Main area' + msg + 'attached.' );
|
||||
assert.strictEqual( $( '.mlb-overlay' ).length, inDocument, 'Overlay area' + msg + 'attached.' );
|
||||
}
|
||||
|
||||
// UI areas not attached to the document yet.
|
||||
checkIfUIAreasAttachedToDocument(0);
|
||||
|
||||
// Attach lightbox to testing fixture to avoid interference with other tests.
|
||||
lightbox.attach( '#qunit-fixture' );
|
||||
|
||||
// UI areas should now be attached to the document.
|
||||
checkIfUIAreasAttachedToDocument(1);
|
||||
|
||||
// Unattach lightbox from document
|
||||
lightbox.unattach();
|
||||
|
||||
checkIfUIAreasAttachedToDocument(0);
|
||||
} );
|
||||
|
||||
QUnit.asyncTest( 'Check we are saving the resize listener', 2, function ( assert ) {
|
||||
var img = new window.LightboxImage('http://en.wikipedia.org/w/skins/vector/images/search-ltr.png'),
|
||||
lightbox = new window.LightboxInterface();
|
||||
|
||||
// resizeListener not saved yet
|
||||
assert.strictEqual( this.resizeListener, undefined, 'Listener is not saved yet' );
|
||||
|
||||
// Save original showImage
|
||||
lightbox.originalShowImage = lightbox.showImage;
|
||||
|
||||
// Mock showImage
|
||||
lightbox.showImage = function ( image, ele ) {
|
||||
// Call original showImage
|
||||
this.originalShowImage( image, ele );
|
||||
|
||||
// resizeListener should have been saved
|
||||
assert.notStrictEqual( this.resizeListener, undefined, 'Saved listener !' );
|
||||
QUnit.start();
|
||||
};
|
||||
|
||||
lightbox.load(img);
|
||||
} );
|
||||
|
||||
QUnit.test( 'Fullscreen mode', 8, function ( assert ) {
|
||||
var lightbox = new window.LightboxInterface(),
|
||||
oldFnEnterFullscreen = $.fn.enterFullscreen,
|
||||
oldFnExitFullscreen = $.fn.exitFullscreen,
|
||||
oldSupportFullscreen = $.support.fullscreen;
|
||||
|
||||
// Since we don't want these tests to really open fullscreen
|
||||
// which is subject to user security confirmation,
|
||||
// we use a mock that pretends regular jquery.fullscreen behavior happened
|
||||
$.fn.enterFullscreen = mw.mmvTestHelpers.enterFullscreenMock;
|
||||
$.fn.exitFullscreen = mw.mmvTestHelpers.exitFullscreenMock;
|
||||
|
||||
// Attach lightbox to testing fixture to avoid interference with other tests.
|
||||
lightbox.attach( '#qunit-fixture' );
|
||||
|
||||
$.support.fullscreen = false;
|
||||
lightbox.setupFullscreenButton();
|
||||
|
||||
assert.ok( !lightbox.$fullscreenButton.is(':visible'),
|
||||
'Fullscreen button is hidden when fullscreen mode is unavailable' );
|
||||
|
||||
$.support.fullscreen = true;
|
||||
lightbox.setupFullscreenButton();
|
||||
|
||||
assert.ok( lightbox.$fullscreenButton.is(':visible'),
|
||||
'Fullscreen button is visible when fullscreen mode is available' );
|
||||
|
||||
// Entering fullscreen
|
||||
lightbox.$fullscreenButton.click();
|
||||
|
||||
assert.strictEqual( lightbox.$main.hasClass( 'jq-fullscreened' ) , true,
|
||||
'Fullscreened area has the fullscreen class');
|
||||
assert.strictEqual( lightbox.isFullscreen , true, 'Lightbox knows it\'s in fullscreen mode');
|
||||
|
||||
// Exiting fullscreen
|
||||
lightbox.$fullscreenButton.click();
|
||||
|
||||
assert.strictEqual( lightbox.$main.hasClass( 'jq-fullscreened' ) , false,
|
||||
'Fullscreened area doesn\'t have the fullscreen class anymore');
|
||||
assert.strictEqual( lightbox.isFullscreen , false, 'Lightbox knows it\'s not in fullscreen mode');
|
||||
|
||||
// Entering fullscreen
|
||||
lightbox.$fullscreenButton.click();
|
||||
|
||||
// Hard-exiting fullscreen
|
||||
lightbox.$closeButton.click();
|
||||
|
||||
// Re-attach after hard-exit
|
||||
lightbox.attach( '#qunit-fixture' );
|
||||
|
||||
assert.strictEqual( lightbox.$main.hasClass( 'jq-fullscreened' ) , false,
|
||||
'Fullscreened area doesn\'t have the fullscreen class anymore');
|
||||
assert.strictEqual( lightbox.isFullscreen , false, 'Lightbox knows it\'s not in fullscreen mode');
|
||||
|
||||
// Unattach lightbox from document
|
||||
lightbox.unattach();
|
||||
|
||||
|
||||
|
||||
$.fn.enterFullscreen = oldFnEnterFullscreen;
|
||||
$.fn.exitFullscreen = oldFnExitFullscreen;
|
||||
$.support.fullscreen = oldSupportFullscreen;
|
||||
} );
|
||||
|
||||
}( mediaWiki, jQuery ) );
|
|
@ -1,8 +1,8 @@
|
|||
( function ( /** mw, $ ** Commentted to keep lint happy, uncomment when needed */) {
|
||||
QUnit.module( 'multilightbox.image', QUnit.newMwEnvironment() );
|
||||
( function ( mw ) {
|
||||
QUnit.module( 'mmv.lightboximage', QUnit.newMwEnvironment() );
|
||||
|
||||
QUnit.asyncTest( 'Sanity test, object creation and image loading', 1, function ( assert ) {
|
||||
var lightboxImage = new window.LightboxImage( 'http://en.wikipedia.org/w/skins/vector/images/search-ltr.png' );
|
||||
var lightboxImage = new mw.LightboxImage( 'http://en.wikipedia.org/w/skins/vector/images/search-ltr.png' );
|
||||
|
||||
// Function to be called if loading is successful
|
||||
function loadCallback() {
|
||||
|
@ -15,7 +15,7 @@
|
|||
} );
|
||||
|
||||
QUnit.asyncTest( 'Image failing', 1, function ( assert ) {
|
||||
var lightboxImage = new window.LightboxImage( 'fail' );
|
||||
var lightboxImage = new mw.LightboxImage( 'fail' );
|
||||
|
||||
function errorCallback() {
|
||||
assert.ok( true, 'Image failed !' );
|
|
@ -1,11 +1,14 @@
|
|||
( function ( mw, $ ) {
|
||||
QUnit.module( 'mmv.lightboxInterface', QUnit.newMwEnvironment() );
|
||||
|
||||
QUnit.test( 'Sanity test, object creation and ui construction', 14, function ( assert ) {
|
||||
QUnit.test( 'Sanity test, object creation and ui construction', 23, function ( assert ) {
|
||||
var lightbox = new mw.LightboxInterface( mw.mediaViewer );
|
||||
|
||||
function checkIfUIAreasAttachedToDocument( inDocument ) {
|
||||
var msg = inDocument === 1 ? ' ' : ' not ';
|
||||
assert.strictEqual( $( '.mlb-wrapper' ).length, inDocument, 'Wrapper area' + msg + 'attached.' );
|
||||
assert.strictEqual( $( '.mlb-main' ).length, inDocument, 'Main area' + msg + 'attached.' );
|
||||
assert.strictEqual( $( '.mlb-overlay' ).length, inDocument, 'Overlay area' + msg + 'attached.' );
|
||||
assert.strictEqual( $( '.mw-mlb-title' ).length, inDocument, 'Title area' + msg + 'attached.' );
|
||||
assert.strictEqual( $( '.mw-mlb-author' ).length, inDocument, 'Author area' + msg + 'attached.' );
|
||||
assert.strictEqual( $( '.mw-mlb-image-desc' ).length, inDocument, 'Description area' + msg + 'attached.' );
|
||||
|
@ -48,6 +51,93 @@
|
|||
assert.strictEqual( handlerCalls, 1, 'The handler was not called after calling lightbox.clearEvents().' );
|
||||
} );
|
||||
|
||||
QUnit.asyncTest( 'Check we are saving the resize listener', 2, function ( assert ) {
|
||||
var img = new mw.LightboxImage('http://en.wikipedia.org/w/skins/vector/images/search-ltr.png'),
|
||||
lightbox = new mw.LightboxInterface( mw.mediaViewer );
|
||||
|
||||
// resizeListener not saved yet
|
||||
assert.strictEqual( this.resizeListener, undefined, 'Listener is not saved yet' );
|
||||
|
||||
// Save original showImage
|
||||
lightbox.originalShowImage = lightbox.showImage;
|
||||
|
||||
// Mock showImage
|
||||
lightbox.showImage = function ( image, ele ) {
|
||||
// Call original showImage
|
||||
this.originalShowImage( image, ele );
|
||||
|
||||
// resizeListener should have been saved
|
||||
assert.notStrictEqual( this.resizeListener, undefined, 'Saved listener !' );
|
||||
QUnit.start();
|
||||
};
|
||||
|
||||
lightbox.load(img);
|
||||
} );
|
||||
|
||||
QUnit.test( 'Fullscreen mode', 8, function ( assert ) {
|
||||
var lightbox = new mw.LightboxInterface( mw.mediaViewer ),
|
||||
oldFnEnterFullscreen = $.fn.enterFullscreen,
|
||||
oldFnExitFullscreen = $.fn.exitFullscreen,
|
||||
oldSupportFullscreen = $.support.fullscreen;
|
||||
|
||||
// Since we don't want these tests to really open fullscreen
|
||||
// which is subject to user security confirmation,
|
||||
// we use a mock that pretends regular jquery.fullscreen behavior happened
|
||||
$.fn.enterFullscreen = mw.mmvTestHelpers.enterFullscreenMock;
|
||||
$.fn.exitFullscreen = mw.mmvTestHelpers.exitFullscreenMock;
|
||||
|
||||
// Attach lightbox to testing fixture to avoid interference with other tests.
|
||||
lightbox.attach( '#qunit-fixture' );
|
||||
|
||||
$.support.fullscreen = false;
|
||||
lightbox.setupFullscreenButton();
|
||||
|
||||
assert.ok( !lightbox.$fullscreenButton.is(':visible'),
|
||||
'Fullscreen button is hidden when fullscreen mode is unavailable' );
|
||||
|
||||
$.support.fullscreen = true;
|
||||
lightbox.setupFullscreenButton();
|
||||
|
||||
assert.ok( lightbox.$fullscreenButton.is(':visible'),
|
||||
'Fullscreen button is visible when fullscreen mode is available' );
|
||||
|
||||
// Entering fullscreen
|
||||
lightbox.$fullscreenButton.click();
|
||||
|
||||
assert.strictEqual( lightbox.$main.hasClass( 'jq-fullscreened' ) , true,
|
||||
'Fullscreened area has the fullscreen class');
|
||||
assert.strictEqual( lightbox.isFullscreen , true, 'Lightbox knows it\'s in fullscreen mode');
|
||||
|
||||
// Exiting fullscreen
|
||||
lightbox.$fullscreenButton.click();
|
||||
|
||||
assert.strictEqual( lightbox.$main.hasClass( 'jq-fullscreened' ) , false,
|
||||
'Fullscreened area doesn\'t have the fullscreen class anymore');
|
||||
assert.strictEqual( lightbox.isFullscreen , false, 'Lightbox knows it\'s not in fullscreen mode');
|
||||
|
||||
// Entering fullscreen
|
||||
lightbox.$fullscreenButton.click();
|
||||
|
||||
// Hard-exiting fullscreen
|
||||
lightbox.$closeButton.click();
|
||||
|
||||
// Re-attach after hard-exit
|
||||
lightbox.attach( '#qunit-fixture' );
|
||||
|
||||
assert.strictEqual( lightbox.$main.hasClass( 'jq-fullscreened' ) , false,
|
||||
'Fullscreened area doesn\'t have the fullscreen class anymore');
|
||||
assert.strictEqual( lightbox.isFullscreen , false, 'Lightbox knows it\'s not in fullscreen mode');
|
||||
|
||||
// Unattach lightbox from document
|
||||
lightbox.unattach();
|
||||
|
||||
|
||||
|
||||
$.fn.enterFullscreen = oldFnEnterFullscreen;
|
||||
$.fn.exitFullscreen = oldFnExitFullscreen;
|
||||
$.support.fullscreen = oldSupportFullscreen;
|
||||
} );
|
||||
|
||||
QUnit.test( 'Fullscreen mode', 8, function ( assert ) {
|
||||
var lightbox = new mw.LightboxInterface( mw.mediaViewer ),
|
||||
oldFnEnterFullscreen = $.fn.enterFullscreen,
|
12
tests/qunit/mmv/mmv.multilightbox.test.js
Normal file
12
tests/qunit/mmv/mmv.multilightbox.test.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
( function ( mw ) {
|
||||
QUnit.module( 'mmv.multilightbox', QUnit.newMwEnvironment() );
|
||||
|
||||
QUnit.test( 'Smoke test', 2, function ( assert ) {
|
||||
function DummyClass() {}
|
||||
var multiLightbox = new mw.MultiLightbox( 0, DummyClass );
|
||||
|
||||
assert.strictEqual( multiLightbox.currentIndex, 0, 'currentIndex initialized correctly.' );
|
||||
assert.ok( multiLightbox.iface instanceof DummyClass, 'interface initialized correctly.' );
|
||||
} );
|
||||
|
||||
}( mediaWiki, jQuery ) );
|
|
@ -80,7 +80,7 @@
|
|||
|
||||
QUnit.test( 'Hash handling', 7, function ( assert ) {
|
||||
var oldUnattach,
|
||||
multiLightbox = new window.MultiLightbox(),
|
||||
multiLightbox = new mw.MultiLightbox( 0, mw.LightboxInterface ),
|
||||
lightbox = new mw.LightboxInterface( mw.mediaViewer ),
|
||||
oldLoadImage = mw.mediaViewer.loadImageByTitle,
|
||||
oldLightbox = mw.mediaViewer.lightbox,
|
|
@ -1,14 +0,0 @@
|
|||
( function () {
|
||||
QUnit.module( 'multilightbox', QUnit.newMwEnvironment() );
|
||||
|
||||
QUnit.test( 'Smoke test', 3, function ( assert ) {
|
||||
function DummyClass() {}
|
||||
var multiLightbox = new window.MultiLightbox(),
|
||||
multilightbox2 = new window.MultiLightbox( 0, DummyClass );
|
||||
|
||||
assert.strictEqual( multiLightbox.currentIndex, 0, 'currentIndex initialized correctly.' );
|
||||
assert.ok( multiLightbox.iface instanceof window.LightboxInterface, 'Using default LightboxInterface class' );
|
||||
assert.ok( multilightbox2.iface instanceof DummyClass, 'Using injected DummyClass' );
|
||||
} );
|
||||
|
||||
}( mediaWiki, jQuery ) );
|
Loading…
Reference in a new issue