2013-11-13 23:01:16 +00:00
|
|
|
/*
|
|
|
|
* This file is part of the MediaWiki extension MultimediaViewer.
|
|
|
|
*
|
|
|
|
* MultimediaViewer is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* MultimediaViewer is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with MultimediaViewer. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2014-02-25 01:54:05 +00:00
|
|
|
( function ( mw, $ ) {
|
2013-11-25 23:51:40 +00:00
|
|
|
var LIP;
|
|
|
|
|
2014-01-11 00:05:03 +00:00
|
|
|
/**
|
2014-02-25 01:54:05 +00:00
|
|
|
* Represents the main interface of the lightbox
|
2014-02-25 02:28:49 +00:00
|
|
|
* @class mw.mmv.LightboxInterface
|
2014-01-11 00:05:03 +00:00
|
|
|
* @constructor
|
|
|
|
*/
|
2014-01-06 21:53:42 +00:00
|
|
|
function LightboxInterface( viewer ) {
|
|
|
|
this.viewer = viewer;
|
|
|
|
|
2013-12-12 21:31:14 +00:00
|
|
|
this.eventsRegistered = {};
|
|
|
|
|
2014-02-06 23:18:47 +00:00
|
|
|
/**
|
2014-02-19 02:27:30 +00:00
|
|
|
* @property {mw.mmv.ThumbnailWidthCalculator}
|
2014-02-13 09:52:40 +00:00
|
|
|
* @private
|
2014-02-06 23:18:47 +00:00
|
|
|
*/
|
2014-02-13 09:52:40 +00:00
|
|
|
this.thumbnailWidthCalculator = new mw.mmv.ThumbnailWidthCalculator();
|
|
|
|
|
2014-02-25 01:54:05 +00:00
|
|
|
this.init();
|
2013-11-13 23:01:16 +00:00
|
|
|
}
|
|
|
|
|
2013-11-25 23:51:40 +00:00
|
|
|
LIP = LightboxInterface.prototype;
|
|
|
|
|
2014-02-25 01:54:05 +00:00
|
|
|
/**
|
|
|
|
* The currently selected LightboxImage.
|
2014-02-25 02:28:49 +00:00
|
|
|
* @type {mw.mmv.LightboxImage}
|
2014-02-25 01:54:05 +00:00
|
|
|
* @protected
|
|
|
|
*/
|
|
|
|
LIP.currentImage = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the entire interface - helper method.
|
|
|
|
*/
|
|
|
|
LIP.init = function () {
|
|
|
|
var addToPre = [],
|
|
|
|
addToPost = [],
|
|
|
|
lbinterface = this;
|
|
|
|
|
2014-02-26 13:15:09 +00:00
|
|
|
// SVG filter, needed to achieve blur in Firefox
|
|
|
|
this.$filter = $( '<svg><filter id="gaussian-blur"><fegaussianblur stdDeviation="3"></filter></svg>' );
|
|
|
|
|
2014-02-25 01:54:05 +00:00
|
|
|
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,
|
2014-02-26 13:15:09 +00:00
|
|
|
this.$postDiv,
|
|
|
|
this.$filter
|
2014-02-25 01:54:05 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
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 );
|
|
|
|
};
|
|
|
|
|
2014-02-19 02:27:30 +00:00
|
|
|
/**
|
|
|
|
* Empties the interface.
|
|
|
|
*/
|
2013-12-06 20:10:51 +00:00
|
|
|
LIP.empty = function () {
|
2013-12-12 21:31:14 +00:00
|
|
|
this.clearEvents();
|
2013-12-06 20:10:51 +00:00
|
|
|
|
2014-02-07 14:47:00 +00:00
|
|
|
this.panel.empty();
|
2013-12-06 20:10:51 +00:00
|
|
|
|
2014-02-25 01:54:05 +00:00
|
|
|
this.$imageDiv.empty();
|
2013-12-06 20:10:51 +00:00
|
|
|
|
2014-02-25 01:54:05 +00:00
|
|
|
if ( this.resizeListener ) {
|
|
|
|
window.removeEventListener( 'resize', this.resizeListener );
|
|
|
|
this.resizeListener = null;
|
|
|
|
}
|
2013-12-06 20:10:51 +00:00
|
|
|
};
|
|
|
|
|
2013-12-12 21:31:14 +00:00
|
|
|
/**
|
|
|
|
* Add event handler in a way that will be auto-cleared on lightbox close
|
2014-02-07 14:47:00 +00:00
|
|
|
* NOTE: If you're changing this method you should probably do it in the
|
|
|
|
* mw.mmv.ui.Element version, which is where we'll be handling events
|
|
|
|
* from now on.
|
2013-12-12 21:31:14 +00:00
|
|
|
* @param {string} name Name of event, like 'keydown'
|
|
|
|
* @param {Function} handler Callback for the event
|
|
|
|
*/
|
|
|
|
LIP.handleEvent = function ( name, handler ) {
|
|
|
|
if ( this.eventsRegistered[name] === undefined ) {
|
|
|
|
this.eventsRegistered[name] = [];
|
|
|
|
}
|
|
|
|
this.eventsRegistered[name].push( handler );
|
|
|
|
$( document ).on( name, handler );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove all events that have been registered.
|
|
|
|
*/
|
|
|
|
LIP.clearEvents = function () {
|
|
|
|
var i, handlers, thisevent,
|
|
|
|
events = Object.keys( this.eventsRegistered );
|
|
|
|
|
|
|
|
for ( i = 0; i < events.length; i++ ) {
|
|
|
|
thisevent = events[i];
|
|
|
|
handlers = this.eventsRegistered[thisevent];
|
|
|
|
while ( handlers.length > 0 ) {
|
|
|
|
$( document ).off( thisevent, handlers.pop() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-02-19 02:27:30 +00:00
|
|
|
/**
|
|
|
|
* Attaches the interface to the DOM.
|
2014-02-25 01:54:05 +00:00
|
|
|
* @param {string} [parentId] parent id where we want to attach the UI. Defaults to document
|
|
|
|
* element, override is mainly used for testing.
|
2014-02-19 02:27:30 +00:00
|
|
|
*/
|
2014-01-08 15:14:52 +00:00
|
|
|
LIP.attach = function ( parentId ) {
|
2014-02-25 01:54:05 +00:00
|
|
|
var lbinterface = this,
|
|
|
|
$parent;
|
|
|
|
|
2014-01-08 15:14:52 +00:00
|
|
|
// Advanced description needs to be below the fold when the lightbox opens
|
|
|
|
// regardless of what the scroll value was prior to opening the lightbox
|
|
|
|
|
2014-01-09 16:44:00 +00:00
|
|
|
// Only scroll and save the position if it's the first attach
|
|
|
|
// Otherwise it could be an attach event happening because of prev/next
|
|
|
|
if ( this.scrollTopBeforeAttach === undefined ) {
|
|
|
|
// Save the scrollTop value because we want below to be back to where they were
|
|
|
|
// before opening the lightbox
|
2014-01-23 00:38:01 +00:00
|
|
|
this.scrollTopBeforeAttach = $.scrollTo().scrollTop();
|
|
|
|
$.scrollTo( 0, 0 );
|
2014-01-09 16:44:00 +00:00
|
|
|
}
|
2014-01-08 15:14:52 +00:00
|
|
|
|
2014-01-31 10:35:50 +00:00
|
|
|
// Make sure that the metadata is going to be at the bottom when it appears
|
|
|
|
// 83 is the height of the top metadata area. Which can't be measured by
|
|
|
|
// reading the DOM at this point of the execution, unfortunately
|
|
|
|
this.$postDiv.css( 'top', ( $( window ).height() - 83 ) + 'px' );
|
|
|
|
|
2014-02-25 01:54:05 +00:00
|
|
|
// 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;
|
2014-02-03 11:23:31 +00:00
|
|
|
|
2014-02-13 20:50:05 +00:00
|
|
|
this.panel.attach();
|
|
|
|
|
2014-02-03 11:23:31 +00:00
|
|
|
// Buttons fading might not had been reset properly after a hard fullscreen exit
|
|
|
|
// This needs to happen after the parent attach() because the buttons need to be attached
|
|
|
|
// to the DOM for $.fn.stop() to work
|
2014-02-04 23:44:36 +00:00
|
|
|
this.buttons.stopFade();
|
2014-01-08 15:14:52 +00:00
|
|
|
};
|
|
|
|
|
2014-02-19 02:27:30 +00:00
|
|
|
/**
|
|
|
|
* Detaches the interface from the DOM.
|
|
|
|
*/
|
2014-01-08 15:14:52 +00:00
|
|
|
LIP.unattach = function () {
|
2014-02-25 01:54:05 +00:00
|
|
|
// 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;
|
2014-01-08 15:14:52 +00:00
|
|
|
|
2014-02-13 20:50:05 +00:00
|
|
|
this.panel.unattach();
|
|
|
|
|
2014-01-08 15:14:52 +00:00
|
|
|
// Restore the scrollTop as it was before opening the lightbox
|
|
|
|
if ( this.scrollTopBeforeAttach !== undefined ) {
|
2014-01-23 00:38:01 +00:00
|
|
|
$.scrollTo( this.scrollTopBeforeAttach, 0 );
|
2014-01-09 16:44:00 +00:00
|
|
|
this.scrollTopBeforeAttach = undefined;
|
2014-01-08 15:14:52 +00:00
|
|
|
}
|
2014-02-04 23:44:36 +00:00
|
|
|
|
|
|
|
this.panel.fileReuse.closeDialog();
|
2014-01-08 15:14:52 +00:00
|
|
|
};
|
|
|
|
|
2014-02-25 01:54:05 +00:00
|
|
|
/**
|
|
|
|
* Resize callback
|
|
|
|
* @protected
|
|
|
|
*/
|
2014-02-26 03:14:44 +00:00
|
|
|
LIP.resizeCallback = function () {
|
2014-02-25 01:54:05 +00:00
|
|
|
if ( this.currentlyAttached ) {
|
|
|
|
this.$wrapper.trigger( $.Event( 'mmv-resize') );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
|
|
* Displays an already loaded image.
|
|
|
|
* This is an alternative to load() when we have an image element with the image already loaded.
|
2014-02-25 02:28:49 +00:00
|
|
|
* @param {mw.mmv.LightboxImage} image
|
2014-02-25 13:43:22 +00:00
|
|
|
* @param {jQuery} $imageElement
|
2014-02-25 01:54:05 +00:00
|
|
|
*/
|
2014-02-26 03:14:44 +00:00
|
|
|
LIP.showImage = function ( image, $imageElement ) {
|
2014-02-25 01:54:05 +00:00
|
|
|
var iface = this;
|
|
|
|
|
|
|
|
this.currentImage = image;
|
2014-02-25 13:43:22 +00:00
|
|
|
|
|
|
|
this.$image = $imageElement;
|
2014-02-25 01:54:05 +00:00
|
|
|
|
2014-02-27 00:40:39 +00:00
|
|
|
this.$imageDiv.html( this.$image );
|
2014-02-25 01:54:05 +00:00
|
|
|
|
|
|
|
// 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.
|
2014-02-25 02:28:49 +00:00
|
|
|
* @param {mw.mmv.LightboxImage} image
|
2014-02-25 01:54:05 +00:00
|
|
|
*/
|
|
|
|
LIP.load = function ( image ) {
|
|
|
|
var iface = this;
|
|
|
|
|
|
|
|
this.setupForLoad();
|
|
|
|
|
|
|
|
this.currentImage = image;
|
|
|
|
|
|
|
|
image.getImageElement().done( function( image, ele ) {
|
2014-02-25 13:43:22 +00:00
|
|
|
iface.showImage( image, $( ele ) );
|
2014-02-25 01:54:05 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2014-02-13 09:52:40 +00:00
|
|
|
/**
|
2014-02-19 02:27:30 +00:00
|
|
|
* FIXME A bunch of stuff ripped out of #load, because load tries to actually load the image
|
2014-02-13 09:52:40 +00:00
|
|
|
* and causes the small-thumbnail-for-a-moment bug in the process. Needs severe refactoring.
|
|
|
|
*/
|
2014-02-26 03:14:44 +00:00
|
|
|
LIP.setupForLoad = function () {
|
2014-02-17 15:09:23 +00:00
|
|
|
var hashFragment = '#mediaviewer/' + this.viewer.currentImageFilename,
|
2014-01-23 00:38:01 +00:00
|
|
|
ui = this;
|
2013-11-25 23:51:40 +00:00
|
|
|
|
2014-01-06 21:53:42 +00:00
|
|
|
this.viewer.ui = this;
|
2013-11-25 23:51:40 +00:00
|
|
|
|
2014-02-24 09:29:14 +00:00
|
|
|
if ( !this.comingFromHashChange ) {
|
|
|
|
$( document ).trigger( $.Event( 'mmv.hash', { hash : hashFragment } ) );
|
2013-11-25 23:51:40 +00:00
|
|
|
}
|
|
|
|
|
2014-02-18 08:25:48 +00:00
|
|
|
this.handleEvent( 'keydown', function ( e ) { ui.keydown( e ); } );
|
2013-12-12 21:31:14 +00:00
|
|
|
|
2014-02-03 11:23:31 +00:00
|
|
|
// mousemove generates a ton of events, which is why we throttle it
|
|
|
|
this.handleEvent( 'mousemove.lip', $.throttle( 250, function( e ) {
|
|
|
|
ui.mousemove( e );
|
|
|
|
} ) );
|
2014-02-18 08:25:48 +00:00
|
|
|
|
|
|
|
this.handleEvent( 'mmv-faded-out', function ( e ) { ui.fadedOut( e ); } );
|
|
|
|
this.handleEvent( 'mmv-fade-stopped', function ( e ) { ui.fadeStopped( e ); } );
|
2014-02-13 09:52:40 +00:00
|
|
|
};
|
2014-02-03 11:23:31 +00:00
|
|
|
|
2014-02-19 02:27:30 +00:00
|
|
|
/**
|
2014-02-25 01:54:05 +00:00
|
|
|
* Changes what image is being displayed.
|
2014-02-19 02:27:30 +00:00
|
|
|
* @param {HTMLImageElement} imageEle
|
|
|
|
*/
|
2013-12-10 21:04:45 +00:00
|
|
|
LIP.replaceImageWith = function ( imageEle ) {
|
2014-02-26 03:14:44 +00:00
|
|
|
function makeMaxMatchParent ( $image ) {
|
|
|
|
$image.css( {
|
|
|
|
maxHeight : $image.parent().height(),
|
|
|
|
maxWidth : $image.parent().width()
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2014-02-12 01:50:56 +00:00
|
|
|
if ( this.$image.is( imageEle ) ) { // http://bugs.jquery.com/ticket/4087
|
2014-02-26 03:14:44 +00:00
|
|
|
// Update the max dimensions otherwise the image gets distorted
|
|
|
|
makeMaxMatchParent( this.$image );
|
2014-02-12 01:50:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-10 21:04:45 +00:00
|
|
|
var $image = $( imageEle );
|
|
|
|
|
|
|
|
this.$image.replaceWith( $image );
|
2014-02-25 13:43:22 +00:00
|
|
|
this.currentImage.src = imageEle.src;
|
2013-12-10 21:04:45 +00:00
|
|
|
this.$image = $image;
|
|
|
|
|
2014-02-26 03:14:44 +00:00
|
|
|
makeMaxMatchParent( this.$image );
|
2014-02-25 01:54:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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] );
|
|
|
|
}
|
2013-12-10 21:04:45 +00:00
|
|
|
};
|
|
|
|
|
2014-02-25 13:43:22 +00:00
|
|
|
/**
|
|
|
|
* Animates the image into focus
|
|
|
|
*/
|
|
|
|
LIP.unblur = function () {
|
|
|
|
var self = this,
|
|
|
|
animationLength = 300;
|
|
|
|
|
2014-02-26 13:15:09 +00:00
|
|
|
// The blurred class has an opacity < 1. This animates the image to become fully opaque
|
2014-02-25 13:43:22 +00:00
|
|
|
this.$image
|
|
|
|
.addClass( 'blurred' )
|
2014-02-26 13:15:09 +00:00
|
|
|
// We have to apply the SVG filter here, it doesn't work when defined in the .less file
|
|
|
|
// We can't use an external SVG file because filters can't be accessed cross-domain
|
|
|
|
// We can't embed the SVG file because accessing the filter inside of it doesn't work
|
|
|
|
.css( 'filter', 'url("#gaussian-blur")' )
|
2014-02-25 13:43:22 +00:00
|
|
|
.animate( { opacity: 1.0 }, animationLength );
|
|
|
|
|
|
|
|
// During the same amount of time (animationLength) we animate a blur value from 3.0 to 0.0
|
|
|
|
// We pass that value to an inline CSS Gaussian blur effect
|
|
|
|
$( { blur: 3.0 } ).animate( { blur: 0.0 }, {
|
|
|
|
duration: animationLength,
|
|
|
|
step: function ( step ) {
|
|
|
|
self.$image.css( { '-webkit-filter' : 'blur(' + step + 'px)',
|
|
|
|
'filter' : 'blur(' + step + 'px)' } );
|
|
|
|
},
|
|
|
|
complete: function () {
|
|
|
|
// When the animation is complete, the blur value is 0
|
|
|
|
// We apply empty CSS values to remove the inline styles applied by jQuery
|
|
|
|
// so that they don't get in the way of styles defined in CSS
|
2014-02-26 13:15:09 +00:00
|
|
|
self.$image.css( { '-webkit-filter' : '', 'opacity' : '', 'filter' : '' } )
|
2014-02-25 13:43:22 +00:00
|
|
|
.removeClass( 'blurred' );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2014-02-19 02:27:30 +00:00
|
|
|
/**
|
|
|
|
* Handle a fullscreen change event.
|
|
|
|
* @param {jQuery.Event} e The fullscreen change event.
|
|
|
|
*/
|
2014-02-25 01:54:05 +00:00
|
|
|
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;
|
|
|
|
}
|
2014-02-03 11:23:31 +00:00
|
|
|
|
|
|
|
// Fullscreen change events can happen after unattach(), in which
|
|
|
|
// case we shouldn't do anything UI-related
|
|
|
|
if ( !this.currentlyAttached ) {
|
|
|
|
return;
|
|
|
|
}
|
2014-01-06 21:53:42 +00:00
|
|
|
|
2014-02-03 11:23:31 +00:00
|
|
|
if ( this.isFullscreen ) {
|
|
|
|
// When entering fullscreen without a mousemove, the browser
|
|
|
|
// still thinks that the cursor is where it was prior to entering
|
|
|
|
// fullscreen. I.e. on top of the fullscreen button
|
|
|
|
// Thus, we purposefully reset the saved position, so that
|
|
|
|
// the fade out really takes place (otherwise it's cancelled
|
|
|
|
// by updateControls which is called a few times when fullscreen opens)
|
|
|
|
this.mousePosition = { x: 0, y: 0 };
|
2014-02-04 23:44:36 +00:00
|
|
|
this.buttons.fadeOut();
|
2014-02-03 11:23:31 +00:00
|
|
|
}
|
2014-01-06 21:53:42 +00:00
|
|
|
};
|
|
|
|
|
2014-01-23 00:38:01 +00:00
|
|
|
/**
|
|
|
|
* Handles keydown events on the document
|
|
|
|
* @param {jQuery.Event} e The jQuery keypress event object
|
|
|
|
*/
|
|
|
|
LIP.keydown = function ( e ) {
|
|
|
|
var isRtl = $( document.body ).hasClass( 'rtl' );
|
|
|
|
|
2014-02-26 17:04:29 +00:00
|
|
|
if ( e.altKey || e.shiftKey || e.ctrlKey || e.metaKey ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
2014-01-23 00:38:01 +00:00
|
|
|
switch ( e.which ) {
|
|
|
|
case 37:
|
|
|
|
// Left arrow
|
|
|
|
if ( isRtl ) {
|
|
|
|
this.viewer.nextImage();
|
|
|
|
} else {
|
|
|
|
this.viewer.prevImage();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 39:
|
|
|
|
// Right arrow
|
|
|
|
if ( isRtl ) {
|
|
|
|
this.viewer.prevImage();
|
|
|
|
} else {
|
|
|
|
this.viewer.nextImage();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-02-03 11:23:31 +00:00
|
|
|
/**
|
|
|
|
* Handles mousemove events on the document
|
2014-02-19 02:27:30 +00:00
|
|
|
* @param {jQuery.Event} e The mousemove event object
|
2014-02-03 11:23:31 +00:00
|
|
|
*/
|
|
|
|
LIP.mousemove = function ( e ) {
|
|
|
|
if ( e ) {
|
|
|
|
// Saving the mouse position is useful whenever we need to
|
|
|
|
// run LIP.mousemove manually, such as when going to the next/prev
|
|
|
|
// element
|
2014-02-04 23:44:36 +00:00
|
|
|
this.mousePosition = { x: e.pageX, y: e.pageY };
|
2014-02-03 11:23:31 +00:00
|
|
|
}
|
|
|
|
|
2014-02-04 23:44:36 +00:00
|
|
|
if ( this.isFullscreen ) {
|
|
|
|
this.buttons.revealAndFade( this.mousePosition );
|
2014-02-03 11:23:31 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-02-06 23:18:47 +00:00
|
|
|
/**
|
2014-02-18 08:25:48 +00:00
|
|
|
* @method
|
2014-02-13 09:52:40 +00:00
|
|
|
* Gets the widths for a given lightbox image.
|
2014-02-25 02:28:49 +00:00
|
|
|
* @param {mw.mmv.LightboxImage} image
|
2014-02-13 09:52:40 +00:00
|
|
|
* @returns {mw.mmv.model.ThumbnailWidth}
|
2014-02-06 23:18:47 +00:00
|
|
|
*/
|
2014-02-13 09:52:40 +00:00
|
|
|
LIP.getLightboxImageWidths = function ( image ) {
|
|
|
|
var thumb = image.thumbnail;
|
2014-02-06 23:18:47 +00:00
|
|
|
|
|
|
|
return this.thumbnailWidthCalculator.calculateWidths(
|
|
|
|
this.$imageWrapper.width(), this.$imageWrapper.height(), thumb.width, thumb.height );
|
|
|
|
};
|
|
|
|
|
2014-02-13 09:52:40 +00:00
|
|
|
/**
|
2014-02-20 08:43:10 +00:00
|
|
|
* 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).
|
2014-02-25 02:28:49 +00:00
|
|
|
* @param {mw.mmv.LightboxImage} image
|
2014-02-20 08:43:10 +00:00
|
|
|
* @returns {mw.mmv.model.ThumbnailWidth}
|
|
|
|
*/
|
|
|
|
LIP.getLightboxImageWidthsForFullscreen = function ( image ) {
|
|
|
|
var thumb = image.thumbnail;
|
|
|
|
|
|
|
|
return this.thumbnailWidthCalculator.calculateWidths(
|
|
|
|
screen.width, screen.height, thumb.width, thumb.height );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2014-02-13 09:52:40 +00:00
|
|
|
* Gets the widths for the current lightbox image.
|
|
|
|
* @returns {mw.mmv.model.ThumbnailWidth}
|
|
|
|
*/
|
|
|
|
LIP.getCurrentImageWidths = function () {
|
|
|
|
return this.getLightboxImageWidths( this.currentImage );
|
|
|
|
};
|
2014-02-06 23:18:47 +00:00
|
|
|
|
2014-02-18 08:25:48 +00:00
|
|
|
/**
|
|
|
|
* Called when the buttons have completely faded out and disappeared
|
|
|
|
*/
|
|
|
|
LIP.fadedOut = function () {
|
|
|
|
this.$main.addClass( 'cursor-hidden' );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when the buttons have stopped fading and are back into view
|
|
|
|
*/
|
|
|
|
LIP.fadeStopped = function () {
|
|
|
|
this.$main.removeClass( 'cursor-hidden' );
|
|
|
|
};
|
|
|
|
|
2014-02-25 01:54:05 +00:00
|
|
|
/**
|
|
|
|
* 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 );
|
|
|
|
};
|
|
|
|
|
2014-02-25 02:28:49 +00:00
|
|
|
mw.mmv.LightboxInterface = LightboxInterface;
|
2014-02-25 01:54:05 +00:00
|
|
|
}( mediaWiki, jQuery ) );
|