/* * 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 . */ ( function ( mw, $, oo, MLBInterface ) { var LIP; /** * @class mw.LightboxInterface * @extends mlb.LightboxInterface * Represents the main interface of the lightbox * @constructor */ function LightboxInterface( viewer ) { MLBInterface.call( this ); this.viewer = viewer; this.eventsRegistered = {}; this.initializeInterface(); } oo.inheritClass( LightboxInterface, MLBInterface ); LIP = LightboxInterface.prototype; LIP.empty = function () { this.clearEvents(); this.$license.empty().addClass( 'empty' ); this.description.empty(); this.$title.empty(); this.$credit.empty().addClass( 'empty' ); this.$username.empty(); this.$usernameLi.addClass( 'empty' ); this.$repo.empty(); this.$repoLi.addClass( 'empty' ); this.$datetime.empty(); this.$datetimeLi.addClass( 'empty' ); this.$location.empty(); this.$locationLi.addClass( 'empty' ); this.fileUsage.empty(); this.$useFile.data( 'title', null ); this.$useFile.data( 'link', null ); this.$useFile.data( 'src', null ); this.$useFile.data( 'isLocal', null ); this.$useFileLi.addClass( 'empty' ); this.$imageDiv.addClass( 'empty' ); this.$dragIcon.removeClass( 'pointing-down' ); MLBInterface.prototype.empty.call( this ); }; /** * Add event handler in a way that will be auto-cleared on lightbox close * @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() ); } } }; LIP.attach = function ( parentId ) { // Advanced description needs to be below the fold when the lightbox opens // regardless of what the scroll value was prior to opening the lightbox // 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 this.scrollTopBeforeAttach = $.scrollTo().scrollTop(); $.scrollTo( 0, 0 ); } // 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' ); MLBInterface.prototype.attach.call( this, parentId ); }; LIP.unattach = function () { MLBInterface.prototype.unattach.call( this ); // Restore the scrollTop as it was before opening the lightbox if ( this.scrollTopBeforeAttach !== undefined ) { $.scrollTo( this.scrollTopBeforeAttach, 0 ); this.scrollTopBeforeAttach = undefined; } }; LIP.load = function ( image ) { var hashFragment = '#mediaviewer/' + this.viewer.currentImageFilename + '/' + this.viewer.lightbox.currentIndex, ui = this; this.viewer.ui = this; this.viewer.registerLogging(); if ( !this.comingFromPopstate ) { history.pushState( {}, '', hashFragment ); } this.handleEvent( 'keydown', function( e ) { ui.keydown( e ); } ); MLBInterface.prototype.load.call( this, image ); }; LIP.initializeInterface = function () { var ui = this; this.initializeHeader(); this.initializeNavigation(); this.initializeButtons(); this.initializeImage(); this.initializeImageMetadata(); this.initializeAboutLinks(); this.$imageDiv.click( function ( e ) { if ( e.target.nodeName !== 'IMG' ) { ui.unattach(); } } ); }; LIP.initializeHeader = function () { var ui = this; this.$dragBar = $( '
' ) .addClass( 'mw-mlb-drag-affordance' ) .appendTo( this.$controlBar ) .click( function () { ui.toggleMetadata(); } ); this.$dragIcon = $( '
' ) .addClass( 'mw-mlb-drag-icon' ) .appendTo( this.$dragBar ); this.$titleDiv = $( '
' ) .addClass( 'mw-mlb-title-contain' ) .appendTo( this.$controlBar ); this.$postDiv.append( this.$controlBar ); this.initializeTitleAndCredit(); this.initializeLicense(); }; LIP.initializeTitleAndCredit = function () { this.$titleAndCredit = $( '
' ) .addClass( 'mw-mlb-title-credit' ) .appendTo( this.$titleDiv ); this.initializeTitle(); this.initializeCredit(); }; LIP.initializeTitle = function () { this.$titlePara = $( '

' ) .addClass( 'mw-mlb-title-para' ) .appendTo( this.$titleAndCredit ); this.$title = $( '' ) .addClass( 'mw-mlb-title' ) .appendTo( this.$titlePara ); }; LIP.initializeCredit = function () { this.$source = $( '' ) .addClass( 'mw-mlb-source' ); this.$author = $( '' ) .addClass( 'mw-mlb-author' ); this.$credit = $( '

' ) .addClass( 'mw-mlb-credit empty' ) .html( mw.message( 'multimediaviewer-credit', this.$author.get( 0 ).outerHTML, this.$source.get( 0 ).outerHTML ).plain() ) .appendTo( this.$titleAndCredit ); }; LIP.initializeLicense = function () { this.$license = $( '' ) .addClass( 'mw-mlb-license empty' ) .prop( 'href', '#' ) .appendTo( this.$titlePara ); }; LIP.initializeButtons = function () { // Note we aren't adding the fullscreen button here. // Fullscreen causes some funky issues with UI redraws, // and we aren't sure why, but it's not really necessary // with the new interface anyway - it's basically fullscreen // already! this.$closeButton .add( this.$fullscreenButton ) .add( this.$nextButton ) .add( this.$prevButton ) .appendTo( this.$imageWrapper ); }; LIP.initializeImage = function () { this.$imageDiv .addClass( 'empty' ); }; LIP.initializeImageMetadata = function () { this.$imageMetadata = $( '

' ) .addClass( 'mw-mlb-image-metadata' ) .appendTo( this.$postDiv ); this.initializeImageDesc(); this.initializeImageLinks(); }; LIP.initializeImageDesc = function () { this.description = new mw.mmv.ui.Description( this.$imageMetadata ); }; LIP.initializeImageLinks = function () { this.$imageLinkDiv = $( '
' ) .addClass( 'mw-mlb-image-links-div' ) .appendTo( this.$imageMetadata ); this.$imageLinks = $( '