diff --git a/MultimediaViewer.php b/MultimediaViewer.php index 704a28fc4..1319a5976 100644 --- a/MultimediaViewer.php +++ b/MultimediaViewer.php @@ -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', diff --git a/MultimediaViewerHooks.php b/MultimediaViewerHooks.php index 4ac1a7a19..085d2c6fa 100644 --- a/MultimediaViewerHooks.php +++ b/MultimediaViewerHooks.php @@ -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', diff --git a/docs/external.js b/docs/external.js index f09d69b23..dd786b398 100644 --- a/docs/external.js +++ b/docs/external.js @@ -14,27 +14,6 @@ * */ -/** - * @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. diff --git a/resources/mmv/mmv.js b/resources/mmv/mmv.js index 3878625dc..880a2a8eb 100755 --- a/resources/mmv/mmv.js +++ b/resources/mmv/mmv.js @@ -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; diff --git a/resources/mmv/mmv.lightboximage.js b/resources/mmv/mmv.lightboximage.js index 4aacef6bf..374206816 100644 --- a/resources/mmv/mmv.lightboximage.js +++ b/resources/mmv/mmv.lightboximage.js @@ -15,11 +15,11 @@ * along with MultimediaViewer. If not, see . */ -( 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.} + * @protected + */ + LIP.initialSrc = null; + + /** + * Loads the image. + * FIXME we probably don't use this. + * @return {jQuery.Promise.} + */ + 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 ) ); diff --git a/resources/mmv/mmv.lightboxinterface.js b/resources/mmv/mmv.lightboxinterface.js index cfc7e1a10..78bd3adca 100644 --- a/resources/mmv/mmv.lightboxinterface.js +++ b/resources/mmv/mmv.lightboxinterface.js @@ -15,18 +15,15 @@ * along with MultimediaViewer. If not, see . */ -( 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 = $( '
' ) + .addClass( 'mlb-staging-area' ); + $( document.body ).append( this.$staging ); + + this.$overlay = $( '
' ) + .addClass( 'mlb-overlay' ); + + this.$wrapper = $( '
' ) + .addClass( 'mlb-wrapper' ); + + this.$main = $( '
' ) + .addClass( 'mlb-main' ); + + this.$imageDiv = $( '
' ) + .addClass( 'mlb-image' ); + + // I blame CSS for this + this.$innerWrapper = $( '
' ) + .addClass( 'mlb-image-inner-wrapper' ) + .append( this.$imageDiv ); + + this.$imageWrapper = $( '
' ) + .addClass( 'mlb-image-wrapper' ) + .append( this.$innerWrapper ); + + this.$preDiv = $( '
' ) + .addClass( 'mlb-pre-image' ); + this.setupPreDiv( addToPre ); + + this.$postDiv = $( '
' ) + .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.} toAdd + */ + LIP.setupPreDiv = function ( toAdd ) { + var lbinterface = this; + + this.$controlBar = $( '
' ) + .addClass( 'mlb-controls' ); + + this.$closeButton = $( '
' ) + .text( ' ' ) + .addClass( 'mlb-close' ) + .click( function () { + lbinterface.unattach(); + } ); + + this.$fullscreenButton = $( '
' ) + .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.} 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 ) ); diff --git a/resources/mmv/mmv.multilightbox.js b/resources/mmv/mmv.multilightbox.js index 740f09434..4f9fc87e7 100644 --- a/resources/mmv/mmv.multilightbox.js +++ b/resources/mmv/mmv.multilightbox.js @@ -15,26 +15,61 @@ * along with MultimediaViewer. If not, see . */ -( 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 ) ); diff --git a/resources/multilightbox/multilightbox.less b/resources/mmv/mmv.multilightbox.less similarity index 97% rename from resources/multilightbox/multilightbox.less rename to resources/mmv/mmv.multilightbox.less index 30f6e5046..c18017539 100644 --- a/resources/multilightbox/multilightbox.less +++ b/resources/mmv/mmv.multilightbox.less @@ -1,4 +1,4 @@ -@import "../mmv/ui/mmv.mixins"; +@import "ui/mmv.mixins"; .mlb-staging-area { position: absolute; diff --git a/resources/multilightbox/img/close.svg b/resources/multilightbox/img/close.svg deleted file mode 100644 index c9cbff6c7..000000000 --- a/resources/multilightbox/img/close.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/multilightbox/img/defullscreen.svg b/resources/multilightbox/img/defullscreen.svg deleted file mode 100644 index 5c8664298..000000000 --- a/resources/multilightbox/img/defullscreen.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/multilightbox/img/fullscreen.svg b/resources/multilightbox/img/fullscreen.svg deleted file mode 100644 index d8ec7fcbb..000000000 --- a/resources/multilightbox/img/fullscreen.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/resources/multilightbox/lightboximage.js b/resources/multilightbox/lightboximage.js deleted file mode 100644 index 34b0caa3b..000000000 --- a/resources/multilightbox/lightboximage.js +++ /dev/null @@ -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.} - * @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 ) ); diff --git a/resources/multilightbox/lightboxinterface.js b/resources/multilightbox/lightboxinterface.js deleted file mode 100644 index ecb7a47e9..000000000 --- a/resources/multilightbox/lightboxinterface.js +++ /dev/null @@ -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 = $( '
' ) - .addClass( 'mlb-staging-area' ); - $( document.body ).append( this.$staging ); - - this.$overlay = $( '
' ) - .addClass( 'mlb-overlay' ); - - this.$wrapper = $( '
' ) - .addClass( 'mlb-wrapper' ); - - this.$main = $( '
' ) - .addClass( 'mlb-main' ); - - this.$imageDiv = $( '
' ) - .addClass( 'mlb-image' ); - - // I blame CSS for this - this.$innerWrapper = $( '
' ) - .addClass( 'mlb-image-inner-wrapper' ) - .append( this.$imageDiv ); - - this.$imageWrapper = $( '
' ) - .addClass( 'mlb-image-wrapper' ) - .append( this.$innerWrapper ); - - this.$preDiv = $( '
' ) - .addClass( 'mlb-pre-image' ); - this.setupPreDiv( addToPre ); - - this.$postDiv = $( '
' ) - .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 = $( '
' ) - .addClass( 'mlb-controls' ); - - this.$closeButton = $( '
' ) - .text( ' ' ) - .addClass( 'mlb-close' ) - .click( function () { - lbinterface.unattach(); - } ); - - this.$fullscreenButton = $( '
' ) - .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 ) ); diff --git a/resources/multilightbox/multilightbox.js b/resources/multilightbox/multilightbox.js deleted file mode 100644 index eeebbe742..000000000 --- a/resources/multilightbox/multilightbox.js +++ /dev/null @@ -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; -}() ); diff --git a/tests/qunit/lightboxinterface.test.js b/tests/qunit/lightboxinterface.test.js deleted file mode 100644 index 4ece563fd..000000000 --- a/tests/qunit/lightboxinterface.test.js +++ /dev/null @@ -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 ) ); diff --git a/tests/qunit/mmv.ThumbnailWidthCalculator.test.js b/tests/qunit/mmv/mmv.ThumbnailWidthCalculator.test.js similarity index 100% rename from tests/qunit/mmv.ThumbnailWidthCalculator.test.js rename to tests/qunit/mmv/mmv.ThumbnailWidthCalculator.test.js diff --git a/tests/qunit/mmv.bootstrap.test.js b/tests/qunit/mmv/mmv.bootstrap.test.js similarity index 100% rename from tests/qunit/mmv.bootstrap.test.js rename to tests/qunit/mmv/mmv.bootstrap.test.js diff --git a/tests/qunit/lightboximage.test.js b/tests/qunit/mmv/mmv.lightboximage.test.js similarity index 63% rename from tests/qunit/lightboximage.test.js rename to tests/qunit/mmv/mmv.lightboximage.test.js index 5d264e544..da12e8336 100644 --- a/tests/qunit/lightboximage.test.js +++ b/tests/qunit/mmv/mmv.lightboximage.test.js @@ -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 !' ); diff --git a/tests/qunit/mmv.lightboxinterface.test.js b/tests/qunit/mmv/mmv.lightboxinterface.test.js similarity index 77% rename from tests/qunit/mmv.lightboxinterface.test.js rename to tests/qunit/mmv/mmv.lightboxinterface.test.js index ddd20ddd7..ebbf63332 100644 --- a/tests/qunit/mmv.lightboxinterface.test.js +++ b/tests/qunit/mmv/mmv.lightboxinterface.test.js @@ -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, diff --git a/tests/qunit/mmv.logger.test.js b/tests/qunit/mmv/mmv.logger.test.js similarity index 100% rename from tests/qunit/mmv.logger.test.js rename to tests/qunit/mmv/mmv.logger.test.js diff --git a/tests/qunit/mmv/mmv.multilightbox.test.js b/tests/qunit/mmv/mmv.multilightbox.test.js new file mode 100644 index 000000000..04f917424 --- /dev/null +++ b/tests/qunit/mmv/mmv.multilightbox.test.js @@ -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 ) ); diff --git a/tests/qunit/mmv.performance.test.js b/tests/qunit/mmv/mmv.performance.test.js similarity index 100% rename from tests/qunit/mmv.performance.test.js rename to tests/qunit/mmv/mmv.performance.test.js diff --git a/tests/qunit/mmv.test.js b/tests/qunit/mmv/mmv.test.js similarity index 98% rename from tests/qunit/mmv.test.js rename to tests/qunit/mmv/mmv.test.js index c404a0774..44bd7019c 100644 --- a/tests/qunit/mmv.test.js +++ b/tests/qunit/mmv/mmv.test.js @@ -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, diff --git a/tests/qunit/mmv.testhelpers.js b/tests/qunit/mmv/mmv.testhelpers.js similarity index 100% rename from tests/qunit/mmv.testhelpers.js rename to tests/qunit/mmv/mmv.testhelpers.js diff --git a/tests/qunit/mmv.model.test.js b/tests/qunit/mmv/model/mmv.model.test.js similarity index 100% rename from tests/qunit/mmv.model.test.js rename to tests/qunit/mmv/model/mmv.model.test.js diff --git a/tests/qunit/provider/mmv.provider.Api.test.js b/tests/qunit/mmv/provider/mmv.provider.Api.test.js similarity index 100% rename from tests/qunit/provider/mmv.provider.Api.test.js rename to tests/qunit/mmv/provider/mmv.provider.Api.test.js diff --git a/tests/qunit/provider/mmv.provider.FileRepoInfo.test.js b/tests/qunit/mmv/provider/mmv.provider.FileRepoInfo.test.js similarity index 100% rename from tests/qunit/provider/mmv.provider.FileRepoInfo.test.js rename to tests/qunit/mmv/provider/mmv.provider.FileRepoInfo.test.js diff --git a/tests/qunit/provider/mmv.provider.GlobalUsage.test.js b/tests/qunit/mmv/provider/mmv.provider.GlobalUsage.test.js similarity index 100% rename from tests/qunit/provider/mmv.provider.GlobalUsage.test.js rename to tests/qunit/mmv/provider/mmv.provider.GlobalUsage.test.js diff --git a/tests/qunit/provider/mmv.provider.Image.test.js b/tests/qunit/mmv/provider/mmv.provider.Image.test.js similarity index 100% rename from tests/qunit/provider/mmv.provider.Image.test.js rename to tests/qunit/mmv/provider/mmv.provider.Image.test.js diff --git a/tests/qunit/provider/mmv.provider.ImageInfo.test.js b/tests/qunit/mmv/provider/mmv.provider.ImageInfo.test.js similarity index 100% rename from tests/qunit/provider/mmv.provider.ImageInfo.test.js rename to tests/qunit/mmv/provider/mmv.provider.ImageInfo.test.js diff --git a/tests/qunit/provider/mmv.provider.ImageUsage.test.js b/tests/qunit/mmv/provider/mmv.provider.ImageUsage.test.js similarity index 100% rename from tests/qunit/provider/mmv.provider.ImageUsage.test.js rename to tests/qunit/mmv/provider/mmv.provider.ImageUsage.test.js diff --git a/tests/qunit/provider/mmv.provider.ThumbnailInfo.test.js b/tests/qunit/mmv/provider/mmv.provider.ThumbnailInfo.test.js similarity index 100% rename from tests/qunit/provider/mmv.provider.ThumbnailInfo.test.js rename to tests/qunit/mmv/provider/mmv.provider.ThumbnailInfo.test.js diff --git a/tests/qunit/provider/mmv.provider.UserInfo.test.js b/tests/qunit/mmv/provider/mmv.provider.UserInfo.test.js similarity index 100% rename from tests/qunit/provider/mmv.provider.UserInfo.test.js rename to tests/qunit/mmv/provider/mmv.provider.UserInfo.test.js diff --git a/tests/qunit/mmv.ui.categories.test.js b/tests/qunit/mmv/ui/mmv.ui.categories.test.js similarity index 100% rename from tests/qunit/mmv.ui.categories.test.js rename to tests/qunit/mmv/ui/mmv.ui.categories.test.js diff --git a/tests/qunit/mmv.ui.description.test.js b/tests/qunit/mmv/ui/mmv.ui.description.test.js similarity index 100% rename from tests/qunit/mmv.ui.description.test.js rename to tests/qunit/mmv/ui/mmv.ui.description.test.js diff --git a/tests/qunit/mmv.ui.fileUsage.test.js b/tests/qunit/mmv/ui/mmv.ui.fileUsage.test.js similarity index 100% rename from tests/qunit/mmv.ui.fileUsage.test.js rename to tests/qunit/mmv/ui/mmv.ui.fileUsage.test.js diff --git a/tests/qunit/mmv.ui.metadataPanel.test.js b/tests/qunit/mmv/ui/mmv.ui.metadataPanel.test.js similarity index 100% rename from tests/qunit/mmv.ui.metadataPanel.test.js rename to tests/qunit/mmv/ui/mmv.ui.metadataPanel.test.js diff --git a/tests/qunit/mmv.ui.permission.test.js b/tests/qunit/mmv/ui/mmv.ui.permission.test.js similarity index 100% rename from tests/qunit/mmv.ui.permission.test.js rename to tests/qunit/mmv/ui/mmv.ui.permission.test.js diff --git a/tests/qunit/mmv.ui.test.js b/tests/qunit/mmv/ui/mmv.ui.test.js similarity index 100% rename from tests/qunit/mmv.ui.test.js rename to tests/qunit/mmv/ui/mmv.ui.test.js diff --git a/tests/qunit/multilightbox.test.js b/tests/qunit/multilightbox.test.js deleted file mode 100644 index 35ab7d3f6..000000000 --- a/tests/qunit/multilightbox.test.js +++ /dev/null @@ -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 ) );