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:
Gergő Tisza 2014-02-25 01:54:05 +00:00
parent a04631c405
commit 53da285b07
40 changed files with 602 additions and 753 deletions

View file

@ -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',

View file

@ -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',

View file

@ -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.

View file

@ -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;

View file

@ -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 ) );

View file

@ -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 ) );

View file

@ -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 ) );

View file

@ -1,4 +1,4 @@
@import "../mmv/ui/mmv.mixins";
@import "ui/mmv.mixins";
.mlb-staging-area {
position: absolute;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 ) );

View file

@ -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 ) );

View file

@ -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;
}() );

View file

@ -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 ) );

View file

@ -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 !' );

View file

@ -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,

View 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 ) );

View file

@ -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,

View file

@ -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 ) );