mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/MultimediaViewer
synced 2024-11-24 08:13:38 +00:00
Highlight chevron when the wrong direction is pressed
Change-Id: I0d43c58a16fa805611f9fdef329b5ab6a32ed651 Mingle: https://wikimedia.mingle.thoughtworks.com/projects/multimedia/cards/554
This commit is contained in:
parent
44311cddd4
commit
c7fe85154b
|
@ -39,11 +39,21 @@
|
|||
*/
|
||||
this.hasAnimatedMetadata = undefined;
|
||||
|
||||
/**
|
||||
* Timer used to highlight the chevron when the wrong key is pressed
|
||||
* @property {number}
|
||||
* @private
|
||||
*/
|
||||
this.highlightTimeout = undefined;
|
||||
|
||||
this.initialize();
|
||||
}
|
||||
oo.inheritClass( MetadataPanelScroller, mw.mmv.ui.Element );
|
||||
MPSP = MetadataPanelScroller.prototype;
|
||||
|
||||
MPSP.highlightDuration = 500;
|
||||
MPSP.toggleScrollDuration = 400;
|
||||
|
||||
MPSP.attach = function() {
|
||||
var panel = this;
|
||||
|
||||
|
@ -69,6 +79,10 @@
|
|||
|
||||
// need to remove this to avoid animating again when reopening lightbox on same page
|
||||
this.$container.removeClass( 'invite' );
|
||||
|
||||
if ( this.highlightTimeout ) {
|
||||
clearTimeout( this.highlightTimeout );
|
||||
}
|
||||
};
|
||||
|
||||
MPSP.initialize = function () {
|
||||
|
@ -100,7 +114,8 @@
|
|||
* Toggles the metadata div being totally visible.
|
||||
*/
|
||||
MPSP.toggle = function ( forceDirection ) {
|
||||
var scrollTopWhenOpen = this.$container.outerHeight() - this.$controlBar.outerHeight(),
|
||||
var self = this,
|
||||
scrollTopWhenOpen = this.$container.outerHeight() - this.$controlBar.outerHeight(),
|
||||
scrollTopWhenClosed = 0,
|
||||
scrollTop = $.scrollTo().scrollTop(),
|
||||
panelIsOpen = scrollTop > scrollTopWhenClosed,
|
||||
|
@ -110,14 +125,25 @@
|
|||
scrollTopTarget = forceDirection === 'down' ? scrollTopWhenClosed : scrollTopWhenOpen;
|
||||
if ( scrollTop === scrollTopTarget ) {
|
||||
// The user pressed down when the panel was closed already (or up when fully open).
|
||||
// Not a real toggle; do not log.
|
||||
// Not a real toggle; highlight the chevron to attract attention.
|
||||
this.$container.addClass( 'mw-mmv-highlight-chevron' );
|
||||
|
||||
if ( this.highlightTimeout ) {
|
||||
clearTimeout( this.highlightTimeout );
|
||||
}
|
||||
|
||||
this.highlightTimeout = setTimeout( function() {
|
||||
if ( self.$container ) {
|
||||
self.$container.removeClass( 'mw-mmv-highlight-chevron' );
|
||||
}
|
||||
}, this.highlightDuration );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mw.mmv.logger.log( scrollTopTarget === scrollTopWhenOpen ? 'metadata-open' : 'metadata-close' );
|
||||
|
||||
$.scrollTo( scrollTopTarget, 400 );
|
||||
$.scrollTo( scrollTopTarget, this.toggleScrollDuration );
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -132,7 +158,7 @@
|
|||
targetHeight = $target.height(),
|
||||
targetTop = $target.offset().top,
|
||||
targetBottom = targetTop + targetHeight,
|
||||
viewportHeight = $(window).height(),
|
||||
viewportHeight = $( window ).height(),
|
||||
viewportTop = $.scrollTo().scrollTop(),
|
||||
viewportBottom = viewportTop + viewportHeight;
|
||||
|
||||
|
|
|
@ -86,7 +86,9 @@
|
|||
background-position: center top;
|
||||
.rotate(180deg);
|
||||
}
|
||||
.mw-mmv-post-image.invite & {
|
||||
|
||||
.mw-mmv-post-image.invite &, .mw-mmv-post-image.mw-mmv-highlight-chevron & {
|
||||
/* @embed */
|
||||
background-image: url(img/drag-active.svg);
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
|
|
@ -240,183 +240,6 @@
|
|||
restoreScrollTo();
|
||||
} );
|
||||
|
||||
/**
|
||||
* We need to set up a proxy on the jQuery scrollTop function and the jQuery.scrollTo plugin,
|
||||
* that will let us pretend that the document really scrolled and that will return values
|
||||
* as if the scroll happened.
|
||||
* @param {sinon.sandbox} sandbox
|
||||
* @param {mw.mmv.LightboxInterface} ui
|
||||
*/
|
||||
function stubScrollFunctions( sandbox, ui ) {
|
||||
var memorizedScrollToScroll = 0,
|
||||
originalJQueryScrollTop = $.fn.scrollTop,
|
||||
originalJQueryScrollTo = $.scrollTo;
|
||||
|
||||
sandbox.stub( $.fn, 'scrollTop', function ( scrollTop ) {
|
||||
// On some browsers $.scrollTo() != $document
|
||||
if ( $.scrollTo().is( this ) ) {
|
||||
if ( scrollTop !== undefined ) {
|
||||
memorizedScrollToScroll = scrollTop;
|
||||
return this;
|
||||
} else {
|
||||
return memorizedScrollToScroll;
|
||||
}
|
||||
}
|
||||
|
||||
return originalJQueryScrollTop.call( this, scrollTop );
|
||||
} );
|
||||
|
||||
sandbox.stub( $, 'scrollTo', function ( scrollTo ) {
|
||||
var $element;
|
||||
|
||||
if ( scrollTo !== undefined ) {
|
||||
memorizedScrollToScroll = scrollTo;
|
||||
}
|
||||
|
||||
$element = originalJQueryScrollTo.call( this, scrollTo, 0 );
|
||||
|
||||
if ( scrollTo !== undefined ) {
|
||||
// Trigger event manually
|
||||
ui.panel.scroller.scroll();
|
||||
}
|
||||
|
||||
return $element;
|
||||
} );
|
||||
}
|
||||
|
||||
QUnit.test( 'Metadata scrolling', 14, function ( assert ) {
|
||||
var ui = new mw.mmv.LightboxInterface(),
|
||||
keydown = $.Event( 'keydown' ),
|
||||
$document = $( document );
|
||||
|
||||
stubScrollFunctions( this.sandbox, ui );
|
||||
|
||||
// First phase of the test: up and down arrows
|
||||
|
||||
ui.panel.scroller.hasAnimatedMetadata = false;
|
||||
localStorage.removeItem( 'mmv.hasOpenedMetadata' );
|
||||
|
||||
// Attach lightbox to testing fixture to avoid interference with other tests.
|
||||
ui.attach( '#qunit-fixture' );
|
||||
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 0, 'scrollTo scrollTop should be set to 0' );
|
||||
assert.ok( !ui.panel.scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing up' );
|
||||
|
||||
assert.ok( !localStorage.getItem( 'mmv.hasOpenedMetadata' ),
|
||||
'The metadata hasn\'t been open yet, no entry in localStorage' );
|
||||
|
||||
keydown.which = 40; // Down arrow
|
||||
$document.trigger( keydown );
|
||||
|
||||
keydown.which = 38; // Up arrow
|
||||
$document.trigger( keydown );
|
||||
|
||||
assert.strictEqual( Math.round( $.scrollTo().scrollTop() ),
|
||||
ui.panel.$imageMetadata.outerHeight(),
|
||||
'scrollTo scrollTop should be set to the metadata height after pressing up arrow' );
|
||||
assert.ok( ui.panel.scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing down after pressing up arrow' );
|
||||
assert.ok( localStorage.getItem( 'mmv.hasOpenedMetadata' ),
|
||||
'localStorage knows that the metadata has been open' );
|
||||
|
||||
keydown.which = 40; // Down arrow
|
||||
$document.trigger( keydown );
|
||||
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 0,
|
||||
'scrollTo scrollTop should be set to 0 after pressing down arrow' );
|
||||
assert.ok( !ui.panel.scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing up after pressing down arrow' );
|
||||
|
||||
ui.panel.scroller.$dragIcon.click();
|
||||
|
||||
assert.strictEqual( Math.round( $.scrollTo().scrollTop() ),
|
||||
ui.panel.$imageMetadata.outerHeight(),
|
||||
'scrollTo scrollTop should be set to the metadata height after clicking the chevron once' );
|
||||
assert.ok( ui.panel.scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing down after clicking the chevron once' );
|
||||
|
||||
ui.panel.scroller.$dragIcon.click();
|
||||
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 0,
|
||||
'scrollTo scrollTop should be set to 0 after clicking the chevron twice' );
|
||||
assert.ok( !ui.panel.scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing up after clicking the chevron twice' );
|
||||
|
||||
// Unattach lightbox from document
|
||||
ui.unattach();
|
||||
|
||||
|
||||
// Second phase of the test: scroll memory
|
||||
|
||||
// Attach lightbox to testing fixture to avoid interference with other tests.
|
||||
ui.attach( '#qunit-fixture' );
|
||||
|
||||
// To make sure that the details are out of view, the lightbox is supposed to scroll to the top when open
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 0, 'Page scrollTop should be set to 0' );
|
||||
|
||||
// Scroll down to check that the scrollTop memory doesn't affect prev/next (bug 59861)
|
||||
$.scrollTo( 20, 0 );
|
||||
|
||||
// This extra attach() call simulates the effect of prev/next seen in bug 59861
|
||||
ui.attach( '#qunit-fixture' );
|
||||
|
||||
// The lightbox was already open at this point, the scrollTop should be left untouched
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 20, 'Page scrollTop should be set to 20' );
|
||||
|
||||
// Unattach lightbox from document
|
||||
ui.unattach();
|
||||
} );
|
||||
|
||||
QUnit.test( 'Metadata scroll logging', 6, function ( assert ) {
|
||||
var ui = new mw.mmv.LightboxInterface(),
|
||||
keydown = $.Event( 'keydown' ),
|
||||
$document = $( document );
|
||||
|
||||
stubScrollFunctions( this.sandbox, ui );
|
||||
this.sandbox.stub( mw.mmv.logger, 'log' );
|
||||
|
||||
// Attach lightbox to testing fixture to avoid interference with other tests.
|
||||
ui.attach( '#qunit-fixture' );
|
||||
|
||||
keydown.which = 40; // Down arrow
|
||||
$document.trigger( keydown );
|
||||
|
||||
assert.ok( !mw.mmv.logger.log.called, 'Closing keypress not logged when the panel is closed already' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
keydown.which = 38; // Up arrow
|
||||
$document.trigger( keydown );
|
||||
|
||||
assert.ok( mw.mmv.logger.log.calledWithExactly( 'metadata-open' ), 'Opening keypress logged' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
keydown.which = 38; // Up arrow
|
||||
$document.trigger( keydown );
|
||||
|
||||
assert.ok( !mw.mmv.logger.log.called, 'Opening keypress not logged when the panel is opened already' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
keydown.which = 40; // Down arrow
|
||||
$document.trigger( keydown );
|
||||
|
||||
assert.ok( mw.mmv.logger.log.calledWithExactly( 'metadata-close' ), 'Closing keypress logged' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
ui.panel.scroller.$dragIcon.click();
|
||||
|
||||
assert.ok( mw.mmv.logger.log.calledWithExactly( 'metadata-open' ), 'Opening click logged' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
ui.panel.scroller.$dragIcon.click();
|
||||
|
||||
assert.ok( mw.mmv.logger.log.calledWithExactly( 'metadata-close' ), 'Closing click logged' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
// Unattach lightbox from document
|
||||
ui.unattach();
|
||||
} );
|
||||
|
||||
QUnit.test( 'Keyboard prev/next', 2, function ( assert ) {
|
||||
var viewer = new mw.mmv.MultimediaViewer(),
|
||||
lightbox = new mw.mmv.LightboxInterface();
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
*/
|
||||
|
||||
( function( mw, $ ) {
|
||||
QUnit.module( 'mmv.ui.metadataPanelScroller', QUnit.newMwEnvironment() );
|
||||
QUnit.module( 'mmv.ui.metadataPanelScroller', QUnit.newMwEnvironment( {
|
||||
setup: function () {
|
||||
this.clock = this.sandbox.useFakeTimers();
|
||||
}
|
||||
} ) );
|
||||
|
||||
QUnit.test( 'empty()', 2, function ( assert ) {
|
||||
var $qf = $( '#qunit-fixture' ),
|
||||
|
@ -84,4 +88,191 @@
|
|||
|
||||
assert.ok( scroller.savedHasOpenedMetadata, 'Full localStorage, we don\'t try to save the opened flag more than once' );
|
||||
} );
|
||||
|
||||
/**
|
||||
* We need to set up a proxy on the jQuery scrollTop function and the jQuery.scrollTo plugin,
|
||||
* that will let us pretend that the document really scrolled and that will return values
|
||||
* as if the scroll happened.
|
||||
* @param {sinon.sandbox} sandbox
|
||||
* @param {mw.mmv.ui.MetadataPanelScroller} scroller
|
||||
*/
|
||||
function stubScrollFunctions( sandbox, scroller ) {
|
||||
var memorizedScrollToScroll = 0,
|
||||
originalJQueryScrollTop = $.fn.scrollTop,
|
||||
originalJQueryScrollTo = $.scrollTo;
|
||||
|
||||
sandbox.stub( $.fn, 'scrollTop', function ( scrollTop ) {
|
||||
// On some browsers $.scrollTo() != $document
|
||||
if ( $.scrollTo().is( this ) ) {
|
||||
if ( scrollTop !== undefined ) {
|
||||
memorizedScrollToScroll = scrollTop;
|
||||
return this;
|
||||
} else {
|
||||
return memorizedScrollToScroll;
|
||||
}
|
||||
}
|
||||
|
||||
return originalJQueryScrollTop.call( this, scrollTop );
|
||||
} );
|
||||
|
||||
sandbox.stub( $, 'scrollTo', function ( scrollTo ) {
|
||||
var $element;
|
||||
|
||||
if ( scrollTo !== undefined ) {
|
||||
memorizedScrollToScroll = scrollTo;
|
||||
}
|
||||
|
||||
$element = originalJQueryScrollTo.call( this, scrollTo, 0 );
|
||||
|
||||
if ( scrollTo !== undefined ) {
|
||||
// Trigger event manually
|
||||
scroller.scroll();
|
||||
}
|
||||
|
||||
return $element;
|
||||
} );
|
||||
}
|
||||
|
||||
QUnit.test( 'Metadata scrolling', 12, function ( assert ) {
|
||||
var $qf = $( '#qunit-fixture' ),
|
||||
$container = $( '<div>' ).css( 'height', 100 ).appendTo( $qf ),
|
||||
$controlBar = $( '<div>' ).css( 'height', 50 ).appendTo( $container ),
|
||||
fakeLocalStorage = { getItem : $.noop, setItem : $.noop },
|
||||
scroller = new mw.mmv.ui.MetadataPanelScroller( $container, $controlBar, fakeLocalStorage),
|
||||
keydown = $.Event( 'keydown' );
|
||||
|
||||
stubScrollFunctions( this.sandbox, scroller );
|
||||
|
||||
this.sandbox.stub( fakeLocalStorage, 'setItem' );
|
||||
|
||||
// First phase of the test: up and down arrows
|
||||
|
||||
scroller.hasAnimatedMetadata = false;
|
||||
|
||||
scroller.attach();
|
||||
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 0, 'scrollTo scrollTop should be set to 0' );
|
||||
assert.ok( !scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing up' );
|
||||
|
||||
assert.ok( !fakeLocalStorage.setItem.called, 'The metadata hasn\'t been open yet, no entry in localStorage' );
|
||||
|
||||
keydown.which = 40; // Down arrow
|
||||
scroller.keydown( keydown );
|
||||
this.clock.tick( scroller.highlightDuration );
|
||||
|
||||
keydown.which = 38; // Up arrow
|
||||
scroller.keydown( keydown );
|
||||
this.clock.tick( scroller.toggleScrollDuration );
|
||||
|
||||
assert.ok( scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing down after pressing up arrow' );
|
||||
assert.ok( fakeLocalStorage.setItem.calledWithExactly( 'mmv.hasOpenedMetadata', true ), 'localStorage knows that the metadata has been open' );
|
||||
|
||||
keydown.which = 40; // Down arrow
|
||||
scroller.keydown( keydown );
|
||||
this.clock.tick( scroller.toggleScrollDuration );
|
||||
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 0,
|
||||
'scrollTo scrollTop should be set to 0 after pressing down arrow' );
|
||||
assert.ok( !scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing up after pressing down arrow' );
|
||||
|
||||
scroller.$dragIcon.click();
|
||||
this.clock.tick( scroller.toggleScrollDuration );
|
||||
|
||||
assert.ok( scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing down after clicking the chevron once' );
|
||||
|
||||
scroller.$dragIcon.click();
|
||||
this.clock.tick( scroller.toggleScrollDuration );
|
||||
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 0,
|
||||
'scrollTo scrollTop should be set to 0 after clicking the chevron twice' );
|
||||
assert.ok( !scroller.$dragIcon.hasClass( 'pointing-down' ),
|
||||
'Chevron pointing up after clicking the chevron twice' );
|
||||
|
||||
// Unattach lightbox from document
|
||||
scroller.unattach();
|
||||
|
||||
|
||||
// Second phase of the test: scroll memory
|
||||
|
||||
scroller.attach();
|
||||
|
||||
// To make sure that the details are out of view, the lightbox is supposed to scroll to the top when open
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 0, 'Page scrollTop should be set to 0' );
|
||||
|
||||
// Scroll down to check that the scrollTop memory doesn't affect prev/next (bug 59861)
|
||||
$.scrollTo( 20, 0 );
|
||||
this.clock.tick( 100 );
|
||||
|
||||
// This extra attach() call simulates the effect of prev/next seen in bug 59861
|
||||
scroller.attach();
|
||||
|
||||
// The lightbox was already open at this point, the scrollTop should be left untouched
|
||||
assert.strictEqual( $.scrollTo().scrollTop(), 20, 'Page scrollTop should be set to 20' );
|
||||
|
||||
scroller.unattach();
|
||||
} );
|
||||
|
||||
QUnit.test( 'Metadata scroll logging', 12, 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 ),
|
||||
keydown = $.Event( 'keydown' );
|
||||
|
||||
stubScrollFunctions( this.sandbox, scroller );
|
||||
|
||||
this.sandbox.stub( mw.mmv.logger, 'log' );
|
||||
|
||||
assert.ok( !$container.hasClass( 'mw-mmv-highlight-chevron' ), 'Chevron is not highlighted' );
|
||||
|
||||
keydown.which = 40; // Down arrow
|
||||
scroller.keydown( keydown );
|
||||
|
||||
assert.ok( !mw.mmv.logger.log.called, 'Closing keypress not logged when the panel is closed already' );
|
||||
assert.ok( $container.hasClass( 'mw-mmv-highlight-chevron' ), 'Chevron is highlighted' );
|
||||
this.clock.tick( scroller.highlightDuration );
|
||||
assert.ok( !$container.hasClass( 'mw-mmv-highlight-chevron' ), 'Chevron is not highlighted' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
keydown.which = 38; // Up arrow
|
||||
scroller.keydown( keydown );
|
||||
this.clock.tick( scroller.toggleScrollDuration );
|
||||
|
||||
assert.ok( mw.mmv.logger.log.calledWithExactly( 'metadata-open' ), 'Opening keypress logged' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
assert.ok( !$container.hasClass( 'mw-mmv-highlight-chevron' ), 'Chevron is not highlighted' );
|
||||
|
||||
keydown.which = 38; // Up arrow
|
||||
scroller.keydown( keydown );
|
||||
|
||||
assert.ok( !mw.mmv.logger.log.called, 'Opening keypress not logged when the panel is opened already' );
|
||||
assert.ok( $container.hasClass( 'mw-mmv-highlight-chevron' ), 'Chevron is highlighted' );
|
||||
this.clock.tick( scroller.highlightDuration );
|
||||
assert.ok( !$container.hasClass( 'mw-mmv-highlight-chevron' ), 'Chevron is not highlighted' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
keydown.which = 40; // Down arrow
|
||||
scroller.keydown( keydown );
|
||||
this.clock.tick( scroller.toggleScrollDuration );
|
||||
|
||||
assert.ok( mw.mmv.logger.log.calledWithExactly( 'metadata-close' ), 'Closing keypress logged' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
scroller.$dragIcon.click();
|
||||
this.clock.tick( scroller.toggleScrollDuration );
|
||||
|
||||
assert.ok( mw.mmv.logger.log.calledWithExactly( 'metadata-open' ), 'Opening click logged' );
|
||||
mw.mmv.logger.log.reset();
|
||||
|
||||
scroller.$dragIcon.click();
|
||||
this.clock.tick( scroller.toggleScrollDuration );
|
||||
|
||||
assert.ok( mw.mmv.logger.log.calledWithExactly( 'metadata-close' ), 'Closing click logged' );
|
||||
mw.mmv.logger.log.reset();
|
||||
} );
|
||||
}( mediaWiki, jQuery ) );
|
||||
|
|
Loading…
Reference in a new issue