Reveal full text when metadata panel is opened

Automatically reveal/hide full text as metadata panel is opened/closed.
Also makes metadata open/close a proper event.
Changes scrollTop calculation for the fully open metadatapanel so it is not
confused by the size of the panel changing.

Also rename MetadataPanel.$controlBar to $aboveFold (that field was missed
when the corresponding CSS class got renamed).

Change-Id: I7e66ca0f45c2188dab4b78508ad7f91154187de4
Mingle: https://wikimedia.mingle.thoughtworks.com/projects/multimedia/cards/396
This commit is contained in:
Gergő Tisza 2014-07-16 23:15:38 +00:00
parent f5ccd12ee5
commit 0423bfbe5a
4 changed files with 90 additions and 39 deletions

View file

@ -72,7 +72,7 @@
this.$postDiv = $( '<div>' )
.addClass( 'mw-mmv-post-image' );
this.$controlBar = $( '<div>' )
this.$aboveFold = $( '<div>' )
.addClass( 'mw-mmv-above-fold' );
this.$main.append(
@ -88,7 +88,7 @@
this.setupCanvasButtons();
this.panel = new mw.mmv.ui.MetadataPanel( this.$postDiv, this.$controlBar, window.localStorage );
this.panel = new mw.mmv.ui.MetadataPanel( this.$postDiv, this.$aboveFold, window.localStorage );
this.buttons = new mw.mmv.ui.CanvasButtons( this.$preDiv, this.$closeButton, this.$fullscreenButton );
this.canvas = new mw.mmv.ui.Canvas( this.$innerWrapper, this.$imageWrapper, this.$wrapper );
};

View file

@ -25,13 +25,13 @@
* @extends mw.mmv.ui.Element
* @constructor
* @param {jQuery} $container The container for the panel (.mw-mmv-post-image).
* @param {jQuery} $controlBar The control bar element (.mw-mmv-above-fold).
* @param {jQuery} $aboveFold The always-visible part of the metadata panel (.mw-mmv-above-fold).
* @param {Object} localStorage the localStorage object, for dependency injection
*/
function MetadataPanel( $container, $controlBar, localStorage ) {
function MetadataPanel( $container, $aboveFold, localStorage ) {
mw.mmv.ui.Element.call( this, $container );
this.$controlBar = $controlBar;
this.$aboveFold = $aboveFold;
/** @property {mw.mmv.Config} config - */
this.config = new mw.mmv.Config(
@ -69,6 +69,16 @@
}
panel.toggleTruncatedText();
} );
$( this.$container ).on( 'mmv-metadata-open', function () {
panel.revealTruncatedText( true );
} ).on( 'mmv-metadata-close', function () {
panel.hideTruncatedText();
} );
this.handleEvent( 'jq-fullscreen-change.lip', function() {
panel.hideTruncatedText();
} );
};
MPP.unattach = function() {
@ -135,16 +145,16 @@
* @param {Object} localStorage the localStorage object, for dependency injection
*/
MPP.initializeHeader = function ( localStorage ) {
this.progressBar = new mw.mmv.ui.ProgressBar( this.$controlBar );
this.progressBar = new mw.mmv.ui.ProgressBar( this.$aboveFold );
this.scroller = new mw.mmv.ui.MetadataPanelScroller( this.$container, this.$controlBar,
this.scroller = new mw.mmv.ui.MetadataPanelScroller( this.$container, this.$aboveFold,
localStorage );
this.$titleDiv = $( '<div>' )
.addClass( 'mw-mmv-title-contain' )
.appendTo( this.$controlBar );
.appendTo( this.$aboveFold );
this.$container.append( this.$controlBar );
this.$container.append( this.$aboveFold );
this.initializeButtons(); // float, needs to be on top
this.initializeTitleAndCredit();
@ -868,12 +878,18 @@
/**
* Shows truncated text in the title and credit (this also rearranges the layout a bit).
* Opens the panel partially to make sure the revealed text is visible.
* @param {boolean} noScroll if set, do not scroll the panel (because the function was triggered from a
* scroll event in the first place)
*/
MPP.revealTruncatedText = function () {
MPP.revealTruncatedText = function ( noScroll ) {
if ( this.$container.hasClass( 'mw-mmv-untruncated' ) ) {
// avoid self-triggering via reveal -> scroll -> reveal
return;
}
this.$container.addClass( 'mw-mmv-untruncated' );
this.title.grow();
this.creditField.grow();
if ( this.aboveFoldIsLargerThanNormal() ) {
if ( this.aboveFoldIsLargerThanNormal() && !noScroll ) {
this.scroller.scrollIntoView( this.$datetimeLi, 500 );
}
};
@ -882,6 +898,10 @@
* Undoes changes made by revealTruncatedText().
*/
MPP.hideTruncatedText = function () {
if ( !this.$container.hasClass( 'mw-mmv-untruncated' ) ) {
// avoid double-triggering
return;
}
this.title.shrink();
this.creditField.shrink();
this.$container.removeClass( 'mw-mmv-untruncated' );
@ -892,7 +912,7 @@
* calling revealTruncatedText().
*/
MPP.aboveFoldIsLargerThanNormal = function () {
return this.$controlBar.height() > parseInt( this.$controlBar.css( 'min-height' ), 10 );
return this.$aboveFold.height() > parseInt( this.$aboveFold.css( 'min-height' ), 10 );
};
mw.mmv.ui.MetadataPanel = MetadataPanel;

View file

@ -23,15 +23,21 @@
* @extends mw.mmv.ui.Element
* Handles scrolling behavior of the metadata panel.
* @constructor
* @param {jQuery} $container The container for the panel (.mw-mmv-post-image).
* @param {jQuery} $aboveFold The control bar element (.mw-mmv-above-fold).
* @param {Object} localStorage the localStorage object, for dependency injection
*/
function MetadataPanelScroller( $container, $controlBar, localStorage ) {
function MetadataPanelScroller( $container, $aboveFold, localStorage ) {
mw.mmv.ui.Element.call( this, $container );
this.$controlBar = $controlBar;
this.$aboveFold = $aboveFold;
/** @property {Object} localStorage the window.localStorage object */
this.localStorage = localStorage;
/** @property {boolean} panelIsOpen state flag which will be used to detect open <-> closed transitions */
this.panelIsOpen = null;
/**
* Whether this user has ever opened the metadata panel.
* Based on a localstorage flag; will be set to true if the client does not support localstorage.
@ -64,6 +70,18 @@
panel.scroll();
} ) );
this.$container.on( 'mmv-metadata-open', function () {
if ( !panel.hasOpenedMetadata && panel.localStorage ) {
panel.hasOpenedMetadata = true;
panel.$dragIcon.removeClass( 'panel-never-opened' );
try {
panel.localStorage.setItem( 'mmv.hasOpenedMetadata', true );
} catch ( e ) {
// localStorage is full or disabled
}
}
} );
// reset animation flag when the viewer is reopened
this.hasAnimatedMetadata = false;
};
@ -71,6 +89,7 @@
MPSP.unattach = function() {
this.clearEvents();
$.scrollTo().off( 'scroll.mmvp' );
this.$container.off( 'mmv-metadata-open' );
};
MPSP.empty = function () {
@ -78,6 +97,8 @@
// need to remove this to avoid animating again when reopening lightbox on same page
this.$container.removeClass( 'invite' );
this.panelIsOpen = !!$.scrollTo().scrollTop();
};
MPSP.initialize = function () {
@ -88,9 +109,18 @@
.toggleClass( 'panel-never-opened', !this.hasOpenedMetadata )
.prop( 'title', mw.message( 'multimediaviewer-panel-open-popup-text' ).text() )
.tipsy( { gravity: 's', delayIn: mw.config.get( 'wgMultimediaViewer').tooltipDelay } )
.appendTo( this.$controlBar )
.appendTo( this.$aboveFold )
.click( function () {
panel.toggle();
// Trigger open event and do related actions that would be normally done by the scroll handler.
// If we left this to the scroll handler, the size of the panel would change mid-animation
// and the end position would be off.
panel.panelIsOpen = true;
panel.$dragIcon.addClass( 'panel-open' );
// use triggerHandler instead of trigger because it is non-async; the untruncate handler
// must run before the toggle() call
panel.$container.triggerHandler( 'mmv-metadata-open' );
panel.toggle( 'up' );
} );
this.$dragIconBottom = $( '<div>' )
@ -99,7 +129,7 @@
.tipsy( { gravity: 's', delayIn: mw.config.get( 'wgMultimediaViewer').tooltipDelay } )
.appendTo( this.$container )
.click( function () {
panel.toggle();
panel.toggle( 'down' );
} );
this.hasOpenedMetadata = !this.localStorage || this.localStorage.getItem( 'mmv.hasOpenedMetadata' );
@ -124,7 +154,7 @@
*/
MPSP.toggle = function ( forceDirection ) {
var deferred = $.Deferred(),
scrollTopWhenOpen = this.$container.outerHeight() - this.$controlBar.outerHeight(),
scrollTopWhenOpen = this.$container.outerHeight() - parseInt( this.$aboveFold.css( 'min-height' ), 10 ),
scrollTopWhenClosed = 0,
scrollTop = $.scrollTo().scrollTop(),
panelIsOpen = scrollTop > scrollTopWhenClosed,
@ -192,23 +222,16 @@
* Receives the window's scroll events and flips the chevron if necessary.
*/
MPSP.scroll = function () {
var scrolled = !!$.scrollTo().scrollTop();
var panelIsOpen = !!$.scrollTo().scrollTop();
this.$dragIcon.toggleClass( 'panel-open', scrolled );
this.$dragIcon.toggleClass( 'panel-open', panelIsOpen );
if (
!this.hasOpenedMetadata
&& scrolled
&& this.localStorage
) {
this.hasOpenedMetadata = true;
this.$dragIcon.removeClass( 'panel-never-opened' );
try {
this.localStorage.setItem( 'mmv.hasOpenedMetadata', true );
} catch ( e ) {
// localStorage is full or disabled
}
if ( panelIsOpen && !this.panelIsOpen ) { // just opened (this is skipped in some cases, see the $dragIcon click handler)
this.$container.trigger( 'mmv-metadata-open' );
} else if ( !panelIsOpen && this.panelIsOpen ) { // just closed
this.$container.trigger( 'mmv-metadata-close' );
}
this.panelIsOpen = panelIsOpen;
};
mw.mmv.ui.MetadataPanelScroller = MetadataPanelScroller;

View file

@ -83,7 +83,13 @@
localStorage = { getItem : $.noop, setItem : this.sandbox.stub().throwsException( 'I am full' ) },
scroller = new mw.mmv.ui.MetadataPanelScroller( $qf, $( '<div>' ).appendTo( $qf ), localStorage );
this.sandbox.stub( $, 'scrollTo', function() { return { scrollTop : function() { return 10; } }; } );
this.sandbox.stub( $, 'scrollTo', function() { return {
scrollTop : function() { return 10; },
on: $.noop,
off: $.noop
}; } );
scroller.attach();
scroller.scroll();
@ -92,6 +98,8 @@
scroller.scroll();
assert.ok( localStorage.setItem.calledOnce, 'localStorage only written once' );
scroller.unattach();
} );
/**
@ -141,9 +149,9 @@
QUnit.test( 'Metadata scrolling', 7, function ( assert ) {
var $qf = $( '#qunit-fixture' ),
$container = $( '<div>' ).css( 'height', 100 ).appendTo( $qf ),
$controlBar = $( '<div>' ).css( 'height', 50 ).appendTo( $container ),
$aboveFold = $( '<div>' ).css( 'height', 50 ).appendTo( $container ),
fakeLocalStorage = { getItem : $.noop, setItem : $.noop },
scroller = new mw.mmv.ui.MetadataPanelScroller( $container, $controlBar, fakeLocalStorage),
scroller = new mw.mmv.ui.MetadataPanelScroller( $container, $aboveFold, fakeLocalStorage),
keydown = $.Event( 'keydown' );
stubScrollFunctions( this.sandbox, scroller );
@ -176,7 +184,7 @@
scroller.$dragIcon.click();
this.clock.tick( scroller.toggleScrollDuration );
scroller.$dragIcon.click();
scroller.$dragIconBottom.click();
this.clock.tick( scroller.toggleScrollDuration );
assert.strictEqual( $.scrollTo().scrollTop(), 0,
@ -209,8 +217,8 @@
QUnit.test( 'Metadata scroll logging', 6, function ( assert ) {
var $qf = $( '#qunit-fixture' ),
$container = $( '<div>' ).css( 'height', 100 ).appendTo( $qf ),
$controlBar = $( '<div>' ).css( 'height', 50 ).appendTo( $container ),
scroller = new mw.mmv.ui.MetadataPanelScroller( $container, $controlBar ),
$aboveFold = $( '<div>' ).css( 'height', 50 ).appendTo( $container ),
scroller = new mw.mmv.ui.MetadataPanelScroller( $container, $aboveFold ),
keydown = $.Event( 'keydown' );
stubScrollFunctions( this.sandbox, scroller );
@ -251,7 +259,7 @@
assert.ok( mw.mmv.actionLogger.log.calledWithExactly( 'metadata-open' ), 'Opening click logged' );
mw.mmv.actionLogger.log.reset();
scroller.$dragIcon.click();
scroller.$dragIconBottom.click();
this.clock.tick( scroller.toggleScrollDuration );
assert.ok( mw.mmv.actionLogger.log.calledWithExactly( 'metadata-close' ), 'Closing click logged' );