Merge "Show tooltip when all sorts of conditions are met"

This commit is contained in:
jenkins-bot 2014-04-09 09:40:53 +00:00 committed by Gerrit Code Review
commit c42f5425f9
4 changed files with 175 additions and 4 deletions

View file

@ -632,6 +632,33 @@
}
};
/**
* @event mmv.close
* Fired when the viewer should be closed. This is used by components (e.g. the close button)
* to notify the main app that it should close.
*/
/**
* @event mmv-close
* Fired when the viewer is closed. This is used by the main app to notify other components
* (notably the bootstrap).
*/
/**
* @event mmv-next
* Fired when the user requests the next image.
*/
/**
* @event mmv-prev
* Fired when the user requests the previous image.
*/
/**
* @event mmv-resize
* Fired when the screen size changes.
*/
/**
* @event mmv-request-thumbnail
* Used by components to request a thumbnail URL for the current thumbnail, with a given size.
* @param {number} size
*/
/**
* Registers all event handlers
*/

View file

@ -215,7 +215,7 @@
};
MPP.initializeButtons = function () {
this.buttons = new mw.mmv.ui.StripeButtons( this.$titleDiv );
this.buttons = new mw.mmv.ui.StripeButtons( this.$titleDiv, window.localStorage );
};
/**

View file

@ -25,10 +25,14 @@
* metadata panel).
* @constructor
* @param {jQuery} $container
* @param {Object} localStorage the localStorage object, for dependency injection
*/
function StripeButtons( $container ) {
function StripeButtons( $container, localStorage ) {
mw.mmv.ui.Element.call( this, $container );
/** @property {Object} localStorage the window.localStorage object */
this.localStorage = localStorage;
this.$buttonContainer = $( '<div>' )
.addClass( 'mw-mmv-stripe-button-container' )
.appendTo( $container );
@ -106,10 +110,83 @@
href: this.getFeedbackSurveyUrl()
} ).click( function ( e ) {
buttons.openSurveyInNewWindow();
buttons.maxOutTooltipDisplayCount();
e.preventDefault();
} );
};
SBP.feedbackSettings = {
/** Show the tooltip this many seconds to get the user's attention, even when it is not hovered. */
tooltipDisplayDuration: 5,
/** Wait for this long after the viewer is opened, before showing the tooltip. */
tooltipDelay: 5,
/** Only show the tooltip this many times */
tooltipMaxDisplayCount: 3
};
/**
* Returns the number of times the tooltip was shown so far. This number is set to 999 if the
* user clicked on the link already, or we cannot count how many times the tooltip was shown
* already.
* @return {number}
*/
SBP.getTooltipDisplayCount = function () {
if ( !this.localStorage ) {
return 999;
}
if ( this.tooltipDisplayCount === undefined ) {
this.tooltipDisplayCount = this.localStorage.getItem( 'mmv.tooltipDisplayCount' );
if ( this.tooltipDisplayCount === null ) {
this.tooltipDisplayCount = 0;
this.localStorage.setItem( 'mmv.tooltipDisplayCount', 0 );
}
}
return this.tooltipDisplayCount;
};
/**
* Increases tooltip display count.
*/
SBP.increaseTooltipDisplayCount = function () {
this.getTooltipDisplayCount();
if ( this.tooltipDisplayCount !== undefined ) {
this.tooltipDisplayCount++;
this.localStorage.setItem( 'mmv.tooltipDisplayCount', this.tooltipDisplayCount );
}
};
/**
* Sets tooltip display count so large that the tooltip will never be shown again.
* We use this for users who already opened the form.
*/
SBP.maxOutTooltipDisplayCount = function () {
this.getTooltipDisplayCount();
if ( this.tooltipDisplayCount !== undefined ) {
this.tooltipDisplayCount = 999;
this.localStorage.setItem( 'mmv.tooltipDisplayCount', this.tooltipDisplayCount );
}
};
/**
* Show the tooltip to the user if it was not shown often enough yet.
*/
SBP.maybeDisplayTooltip = function () {
if (
this.readyToShowFeedbackTooltip &&
this.getTooltipDisplayCount() < this.feedbackSettings.tooltipMaxDisplayCount
) {
this.buttons.$feedback.tipsy( 'show' );
this.setTimer( 'feedbackTooltip.hide', function () {
this.buttons.$feedback.tipsy( 'hide' );
}, this.feedbackSettings.tooltipDisplayDuration * 1000 );
this.increaseTooltipDisplayCount();
this.readyToShowFeedbackTooltip = false;
} else {
// if the tooltip is visible already, make sure it is not hidden too quickly
this.resetTimer( 'feedbackTooltip.hide' );
}
};
/**
* Checks if it is suitable to show a survey to the current user.
*/
@ -193,6 +270,8 @@
if ( !mw.user.isAnon() ) {
this.setDescriptionPageButton( imageInfo, repoInfo );
}
this.maybeDisplayTooltip();
};
/**
@ -221,7 +300,7 @@
this.setInlineStyle( 'stripe-button-description-page',
'.mw-mmv-stripe-button-dynamic:before {' +
'background-image: url("' + repoInfo.favIcon + '");' +
'}'
'}'
);
}
};
@ -263,6 +342,12 @@
this.handleEvent( 'mmv-reuse-closed', function () {
buttons.$reuse.removeClass( 'open' );
} );
this.readyToShowFeedbackTooltip = false;
this.setTimer( 'feedbackTooltip.show', function () {
this.readyToShowFeedbackTooltip = true;
this.maybeDisplayTooltip();
}, this.feedbackSettings.tooltipDelay * 1000 );
};
/**
@ -271,6 +356,8 @@
SBP.unattach = function () {
this.constructor.super.prototype.unattach.call( this );
this.buttons.$reuse.off( 'click.mmv-stripeButtons' );
this.clearTimer( 'feedbackTooltip.show' );
};
mw.mmv.ui.StripeButtons = StripeButtons;

View file

@ -23,6 +23,7 @@
// pretend surveys are enabled for this site
oldShowSurvey = mw.config.get( 'wgMultimediaViewer' ).showSurvey;
mw.config.get( 'wgMultimediaViewer' ).showSurvey = true;
this.clock = this.sandbox.useFakeTimers();
},
teardown: function () {
mw.config.get( 'wgMultimediaViewer' ).showSurvey = oldShowSurvey;
@ -31,7 +32,10 @@
function createStripeButtons() {
var fixture = $( '#qunit-fixture' );
return new mw.mmv.ui.StripeButtons( fixture );
return new mw.mmv.ui.StripeButtons( fixture, {
getItem: function () { return 999; },
setItem: $.noop
} );
}
QUnit.test( 'Sanity test, object creation and UI construction', 4, function ( assert ) {
@ -110,4 +114,57 @@
$( document ).off( 'mmv-reuse-open.test' );
} );
QUnit.test( 'Feedback tooltip', 8, function ( assert ) {
var buttons = createStripeButtons(),
displayCount,
hasTooltip = function () { return !!$( '.tipsy' ).length; };
this.sandbox.stub( buttons.localStorage, 'getItem', function () { return displayCount; } );
this.sandbox.stub( buttons.localStorage, 'setItem', function ( _, val ) { displayCount = val; } );
displayCount = 0;
buttons.attach();
assert.ok( !hasTooltip(), 'No tooltip initially' );
this.clock.tick( 1000 );
assert.ok( !hasTooltip(), 'No tooltip after 1s' );
this.clock.tick( 5000 );
assert.ok( hasTooltip(), 'Tooltip visible after 6s' );
assert.strictEqual( displayCount, 1, 'displayCount was increased' );
this.clock.tick( 5000 );
assert.ok( !hasTooltip(), 'Tooltip hidden again after 11s' );
buttons.unattach();
delete buttons.tooltipDisplayCount;
displayCount = 3;
buttons.attach();
this.clock.tick( 6000 );
assert.ok( !hasTooltip(), 'No tooltip after 6s when display count limit reached' );
buttons.unattach();
delete buttons.tooltipDisplayCount;
displayCount = 0;
buttons.openSurveyInNewWindow = this.sandbox.stub();
buttons.attach();
buttons.buttons.$feedback.triggerHandler( 'click' );
this.clock.tick( 6000 );
assert.ok( !hasTooltip(), 'No tooltip if button was clicked' );
buttons.unattach();
delete buttons.tooltipDisplayCount;
displayCount = 0;
buttons.attach();
buttons.unattach();
this.clock.tick( 6000 );
assert.ok( !hasTooltip(), 'No tooltip when unattached' );
} );
}( mediaWiki, jQuery ) );