Gergő Tisza has uploaded a new change for review. https://gerrit.wikimedia.org/r/140247
Change subject: Make the metadata panel opening affordance more obvious ...................................................................... Make the metadata panel opening affordance more obvious - rearrange DOM structure of above-fold part of the metadata panel: - rename .mw-mmv-controls to .mw-mmv-above-fold - the above-fold part is a single positioned div now, with height explitcitly set - less LESS gymnastics, above-fold height is a single variable - add paddings to the p elements instead of the containers - make all title elements align to baseline (except the logo which would look horrible) - discard some CSS which was superfluous - overspecified sizes/positions - some top/bottoms for staticly positioned elements - get rid of the .mw-mmv-drag-affordance div, since a full-width bar wouldn't really make sense on the bottom of the above-fold section - flip the chevron and place it to the bottom of the above-fold part; add colors etc. per spec Mingle: https://wikimedia.mingle.thoughtworks.com/projects/multimedia/cards/706 Change-Id: Ic37b4150288055c3fae8d22919ed7b1249db1f09 --- M resources/mmv/mmv.globals.less M resources/mmv/mmv.lightboxinterface.js M resources/mmv/mmv.lightboxinterface.less M resources/mmv/ui/mmv.ui.canvasButtons.less M resources/mmv/ui/mmv.ui.metadataPanel.less M resources/mmv/ui/mmv.ui.metadataPanelScroller.js M resources/mmv/ui/mmv.ui.metadataPanelScroller.less M resources/mmv/ui/mmv.ui.progressBar.less M resources/mmv/ui/mmv.ui.stripeButtons.less M tests/qunit/mmv/ui/mmv.ui.metadataPanelScroller.test.js 10 files changed, 123 insertions(+), 113 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MultimediaViewer refs/changes/47/140247/1 diff --git a/resources/mmv/mmv.globals.less b/resources/mmv/mmv.globals.less index 0d4dfb3..f3574f3 100644 --- a/resources/mmv/mmv.globals.less +++ b/resources/mmv/mmv.globals.less @@ -1,6 +1,5 @@ -// Height of the drag affordance on the top of the metadata bar. -@metadatabar-drag-height: 18px; +// Height of the area of the metadata bar which is visible without scrolling. +@metadatabar-above-fold-height: 82px; -// Height of the top content area of the metadata bar (.mw-mmv-title-contain). Together with -// the drag affordance, these two constitute the above-the-fold part of the metadata bar. -@metadatabar-top-content-height: 64px; +// Height of the same area in fullscreen mode (which can be slightly less since it has less controls). +@metadatabar-above-fold-fullscreen-height: 64px; diff --git a/resources/mmv/mmv.lightboxinterface.js b/resources/mmv/mmv.lightboxinterface.js index 7b98572..ddcfd5e 100644 --- a/resources/mmv/mmv.lightboxinterface.js +++ b/resources/mmv/mmv.lightboxinterface.js @@ -73,7 +73,7 @@ .addClass( 'mw-mmv-post-image' ); this.$controlBar = $( '<div>' ) - .addClass( 'mw-mmv-controls' ); + .addClass( 'mw-mmv-above-fold' ); this.$main.append( this.$preDiv, diff --git a/resources/mmv/mmv.lightboxinterface.less b/resources/mmv/mmv.lightboxinterface.less index 8c77870..a952597 100644 --- a/resources/mmv/mmv.lightboxinterface.less +++ b/resources/mmv/mmv.lightboxinterface.less @@ -1,7 +1,6 @@ @import "mmv.globals"; @import "mmv.mixins"; -@bottom-height: (@metadatabar-top-content-height + @metadatabar-drag-height); @metadata-background: rgb(251, 251, 251); .mw-mmv-wrapper { @@ -23,14 +22,10 @@ } } -.mw-mmv-image-wrapper, -.mw-mmv-controls { - top: 0px; - bottom: @bottom-height; -} - .mw-mmv-image-wrapper { position: fixed; + top: 0px; + bottom: @metadatabar-above-fold-height; left: 0px; right: 0px; } @@ -56,17 +51,19 @@ height: auto; color: #333333; background-color: @metadata-background; - min-height: (@bottom-height + 1); + min-height: (@metadatabar-above-fold-height + 1); z-index: 2; } -.mw-mmv-controls { +// above-the-fold part of the metadata panel +.mw-mmv-above-fold { width: 100%; - height: auto; + height: @metadatabar-above-fold-height; + position: relative; border-bottom: 1px solid #cccccc; } -/* Fullscreen styles */ +// Fullscreen styles .cursor-hidden { cursor: none; @@ -77,22 +74,17 @@ } .jq-fullscreened { - .mw-mmv-image-wrapper, - .mw-mmv-post-image, - .mw-mmv-controls { + .mw-mmv-image-wrapper, // make the image occupy the whole screen + .mw-mmv-post-image { // make sure the panel fits in the screen and does not cause scrollbars to appear bottom: 0px; } - .mw-mmv-post-image, - .mw-mmv-controls { - @fullscreen-padding: 10px; - padding: (@fullscreen-padding / 2) 0; - height: (@metadatabar-top-content-height + @fullscreen-padding); - min-height: 0; + .mw-mmv-above-fold { + height: @metadatabar-above-fold-fullscreen-height; } .mw-mmv-post-image { - position: fixed; + min-height: 0; opacity: 0; transition: opacity 0.25s; diff --git a/resources/mmv/ui/mmv.ui.canvasButtons.less b/resources/mmv/ui/mmv.ui.canvasButtons.less index e30effb..7628162 100644 --- a/resources/mmv/ui/mmv.ui.canvasButtons.less +++ b/resources/mmv/ui/mmv.ui.canvasButtons.less @@ -82,7 +82,7 @@ } .mw-mmv-viewfile { - bottom: (@buttons-offset + @metadatabar-drag-height + @metadatabar-top-content-height); + bottom: (@buttons-offset + @metadatabar-above-fold-height); /* @embed */ background-image: url(img/mw-open-control-ltr.svg); width: 23px; diff --git a/resources/mmv/ui/mmv.ui.metadataPanel.less b/resources/mmv/ui/mmv.ui.metadataPanel.less index 33c92c1..6a87c68 100644 --- a/resources/mmv/ui/mmv.ui.metadataPanel.less +++ b/resources/mmv/ui/mmv.ui.metadataPanel.less @@ -22,15 +22,13 @@ position: relative; } -.mw-mmv-license, -.mw-mmv-title-contain { - vertical-align: middle; -} - .mw-mmv-title-para { - margin-bottom: 1px; - margin-top: 0px; - padding: 0px; + margin: 0; + padding: 10px 0 0; +} +.mw-mmv-credit { + margin: 0; + padding: 5px 0; } .mw-mmv-title { @@ -166,7 +164,7 @@ } .mw-mmv-title-credit { - height: @metadatabar-top-content-height; + height: @metadatabar-above-fold-height; } .mw-mmv-license { diff --git a/resources/mmv/ui/mmv.ui.metadataPanelScroller.js b/resources/mmv/ui/mmv.ui.metadataPanelScroller.js index bcc81fe..c677f12 100644 --- a/resources/mmv/ui/mmv.ui.metadataPanelScroller.js +++ b/resources/mmv/ui/mmv.ui.metadataPanelScroller.js @@ -33,11 +33,18 @@ this.localStorage = localStorage; /** + * 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. + * @type {boolean} + */ + this.hasOpenedMetadata = undefined; + + /** * Whether we've already fired an animation for the metadata div in this lightbox session. * @property {boolean} * @private */ - this.hasAnimatedMetadata = undefined; + this.hasAnimatedMetadata = false; this.initialize(); } @@ -58,7 +65,7 @@ } ) ); // reset animation flag when the viewer is reopened - this.hasAnimatedMetadata = !this.localStorage || this.localStorage.getItem( 'mmv.hasOpenedMetadata' ); + this.hasAnimatedMetadata = false; }; MPSP.unattach = function() { @@ -67,7 +74,7 @@ }; MPSP.empty = function () { - this.$dragIcon.removeClass( 'pointing-down' ); + this.$dragIcon.toggleClass( 'panel-never-opened', !this.hasOpenedMetadata ); // need to remove this to avoid animating again when reopening lightbox on same page this.$container.removeClass( 'invite' ); @@ -76,32 +83,33 @@ MPSP.initialize = function () { var panel = this; - this.dragBarGravity = 's'; - - this.$dragBar = $( '<div>' ) + this.$dragIcon = $( '<div>' ) + .addClass( 'mw-mmv-drag-icon mw-mmv-drag-icon-pointing-down' ) + .toggleClass( 'panel-never-opened', !this.hasOpenedMetadata ) .prop( 'title', mw.message( 'multimediaviewer-panel-open-popup-text' ).text() ) - .tipsy( { - delayIn: mw.config.get( 'wgMultimediaViewer').tooltipDelay, - gravity: function () { - return panel.dragBarGravity; - } - } ) - .addClass( 'mw-mmv-drag-affordance' ) + .tipsy( { gravity: 's', delayIn: mw.config.get( 'wgMultimediaViewer').tooltipDelay } ) .appendTo( this.$controlBar ) .click( function () { panel.toggle(); } ); - this.$dragIcon = $( '<div>' ) - .addClass( 'mw-mmv-drag-icon' ) - .appendTo( this.$dragBar ); + this.$dragIconBottom = $( '<div>' ) + .addClass( 'mw-mmv-drag-icon mw-mmv-drag-icon-pointing-up' ) + .prop( 'title', mw.message( 'multimediaviewer-panel-close-popup-text' ).text() ) + .tipsy( { gravity: 's', delayIn: mw.config.get( 'wgMultimediaViewer').tooltipDelay } ) + .appendTo( this.$container ) + .click( function () { + panel.toggle(); + } ); + + this.hasOpenedMetadata = !this.localStorage || this.localStorage.getItem( 'mmv.hasOpenedMetadata' ); }; /** * Animates the metadata area when the viewer is first opened. */ MPSP.animateMetadataOnce = function () { - if ( !this.hasAnimatedMetadata ) { + if ( !this.hasOpenedMetadata && !this.hasAnimatedMetadata ) { this.hasAnimatedMetadata = true; this.$container.addClass( 'invite' ); } @@ -123,17 +131,6 @@ } mw.mmv.actionLogger.log( wasOpen ? 'metadata-open' : 'metadata-close' ); - - this.$dragBar - .prop( 'title', - mw.message( - 'multimediaviewer-panel-' + - ( !wasOpen ? 'open' : 'close' ) + - '-popup-text' - ).text() - ); - - this.dragBarGravity = wasOpen ? 'n' : 's'; $.scrollTo( scrollTopTarget, this.toggleScrollDuration ); }; @@ -183,21 +180,20 @@ MPSP.scroll = function () { var scrolled = !!$.scrollTo().scrollTop(); - this.$dragIcon.toggleClass( 'pointing-down', scrolled ); + this.$dragIcon.toggleClass( 'panel-open', scrolled ); if ( - !this.savedHasOpenedMetadata && - scrolled && - this.localStorage - ) { + !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 } - - // We mark it as saved even when localStorage failed, because retrying will very likely fail as well - this.savedHasOpenedMetadata = true; } }; diff --git a/resources/mmv/ui/mmv.ui.metadataPanelScroller.less b/resources/mmv/ui/mmv.ui.metadataPanelScroller.less index ddb7c6b..0c0266b 100644 --- a/resources/mmv/ui/mmv.ui.metadataPanelScroller.less +++ b/resources/mmv/ui/mmv.ui.metadataPanelScroller.less @@ -2,6 +2,11 @@ @import "../mmv.mixins"; @import "mediawiki.mixins.animation"; +@drag-icon-width: 64px; +@drag-icon-height: 18px; +@drag-icon-color: #e6e6e6; +@drag-icon-invite-color: #347bff; + .mw-mmv-post-image { .animation( mw-mmv-appear-animation 0.5s ease 0s 1 normal forwards ); &.invite { @@ -69,39 +74,66 @@ .mw-mmv-invite-animation; } -.mw-mmv-drag-affordance { - width: 100%; - height: @metadatabar-drag-height; - cursor: pointer; - - .jq-fullscreened & { - display: none; - } -} - .mw-mmv-drag-icon { - width: 64px; - height: @metadatabar-drag-height; + width: @drag-icon-width; + height: @drag-icon-height; + + position: absolute; + left: 50%; + bottom: 0; + margin: 0 0 0 -(@drag-icon-width / 2); + /* @embed */ background-image: url(img/drag.svg); background-repeat: no-repeat; background-position: center bottom; - margin: 0 auto; + background-color: @drag-icon-color; + + cursor: pointer; + z-index: 1; // make sure it is above the text - the icon is visually at the bottom but in the DOM at the top opacity: 0.7; transition: opacity 0.25s; - &.pointing-down { + &-pointing-down { // use single-class selector - chevron direction is important enough to make it IE6-compatible background-position: center top; .rotate(180deg); + + -webkit-border-bottom-left-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-bottomright: 3px; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + + .mw-mmv-post-image:hover & { + opacity: 1; + } + } + &-pointing-up { + -webkit-border-top-left-radius: 3px; + -webkit-border-top-right-radius: 3px; + -moz-border-radius-topleft: 3px; + -moz-border-radius-topright: 3px; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + + &:hover { + opacity: 1; + } } - .mw-mmv-post-image.invite & { + &.panel-open { + display: none; + } + + &.panel-never-opened { /* @embed */ background-image: url(img/drag-active.svg); - opacity: 0.9; + background-color: @drag-icon-invite-color; + opacity: 1; } -} -.mw-mmv-post-image:hover .mw-mmv-drag-icon { - opacity: 1; + .jq-fullscreened & { + display: none; + } } diff --git a/resources/mmv/ui/mmv.ui.progressBar.less b/resources/mmv/ui/mmv.ui.progressBar.less index 147c19d..9aa7f7f 100644 --- a/resources/mmv/ui/mmv.ui.progressBar.less +++ b/resources/mmv/ui/mmv.ui.progressBar.less @@ -5,9 +5,10 @@ .mw-mmv-progress { width: 100%; height: @progress-height; + position:relative; + bottom: @progress-height; background-color: #cccccc; background-color: rgba( 221, 221, 221, 0.5 ); - margin-top: -@progress-height; } .mw-mmv-progress.empty { diff --git a/resources/mmv/ui/mmv.ui.stripeButtons.less b/resources/mmv/ui/mmv.ui.stripeButtons.less index 05175c7..d15804b 100644 --- a/resources/mmv/ui/mmv.ui.stripeButtons.less +++ b/resources/mmv/ui/mmv.ui.stripeButtons.less @@ -14,7 +14,7 @@ float: right; height: @button-height; - margin-top: @metadatabar-top-content-height - ( @button-height + 2 * @button-vertical-padding ); + margin-top: @metadatabar-above-fold-height - ( @button-height + 2 * @button-vertical-padding ); border-left: 1px solid @border-text-color; padding: @button-vertical-padding 20px; diff --git a/tests/qunit/mmv/ui/mmv.ui.metadataPanelScroller.test.js b/tests/qunit/mmv/ui/mmv.ui.metadataPanelScroller.test.js index 663cd7e..8077da5 100644 --- a/tests/qunit/mmv/ui/mmv.ui.metadataPanelScroller.test.js +++ b/tests/qunit/mmv/ui/mmv.ui.metadataPanelScroller.test.js @@ -22,12 +22,11 @@ } } ) ); - QUnit.test( 'empty()', 2, function ( assert ) { + QUnit.test( 'empty()', 1, function ( assert ) { var $qf = $( '#qunit-fixture' ), scroller = new mw.mmv.ui.MetadataPanelScroller( $qf, $( '<div>' ).appendTo( $qf ) ); scroller.empty(); - assert.ok( !scroller.$dragIcon.hasClass( 'pointing-down' ), 'We successfully reset the chevron' ); assert.ok( !scroller.$container.hasClass( 'invite' ), 'We successfully reset the invite' ); } ); @@ -76,19 +75,23 @@ scroller.scroll(); - assert.ok( !scroller.savedHasOpenedMetadata, 'No localStorage, we don\'t try to save the opened flag' ); + assert.strictEqual( scroller.hasOpenedMetadata, true, 'We store hasOpenedMetadata flag for the session' ); } ); - QUnit.test( 'localStorage is full', 1, function( assert ) { + QUnit.test( 'localStorage is full', 2, function( assert ) { var $qf = $( '#qunit-fixture' ), - scroller = new mw.mmv.ui.MetadataPanelScroller( $qf, $( '<div>' ).appendTo( $qf ), - { getItem : $.noop, setItem : function() { throw 'I am full'; } } ); + 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; } }; } ); scroller.scroll(); - assert.ok( scroller.savedHasOpenedMetadata, 'Full localStorage, we don\'t try to save the opened flag more than once' ); + assert.strictEqual( scroller.hasOpenedMetadata, true, 'We store hasOpenedMetadata flag for the session' ); + + scroller.scroll(); + + assert.ok( localStorage.setItem.calledOnce, 'localStorage only written once' ); } ); /** @@ -135,7 +138,7 @@ } ); } - QUnit.test( 'Metadata scrolling', 12, function ( assert ) { + 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 ), @@ -154,8 +157,6 @@ 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' ); @@ -163,8 +164,6 @@ 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 @@ -173,22 +172,15 @@ 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(); -- To view, visit https://gerrit.wikimedia.org/r/140247 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ic37b4150288055c3fae8d22919ed7b1249db1f09 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/MultimediaViewer Gerrit-Branch: master Gerrit-Owner: Gergő Tisza <gti...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits