WMDE-leszek has uploaded a new change for review.
https://gerrit.wikimedia.org/r/300881
Change subject: Add support for GENDER to the username label in the tooltip
......................................................................
Add support for GENDER to the username label in the tooltip
After fetching a batch of revision data, user names are extracted
and another API query is made to get gender preferences for users.
This change also moves a code responsible for MediaWiki API calls
to its own class.
Bug: T136367
Change-Id: Id11fe14e9ca37829141ae92b13b51f10f992eb96
---
M extension.json
M i18n/en.json
M i18n/qqq.json
A modules/ext.RevisionSlider.Api.js
M modules/ext.RevisionSlider.Revision.js
M modules/ext.RevisionSlider.RevisionList.js
M modules/ext.RevisionSlider.RevisionListView.js
D modules/ext.RevisionSlider.fetchRevisions.js
M modules/ext.RevisionSlider.init.js
M tests/qunit/RevisionSlider.Revision.test.js
M tests/qunit/RevisionSlider.RevisionList.test.js
11 files changed, 255 insertions(+), 70 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/RevisionSlider
refs/changes/81/300881/1
diff --git a/extension.json b/extension.json
index bc8bc38..315ead3 100644
--- a/extension.json
+++ b/extension.json
@@ -36,7 +36,7 @@
"ext.RevisionSlider.Revision",
"ext.RevisionSlider.RevisionList",
"ext.RevisionSlider.HelpDialog",
- "ext.RevisionSlider.fetchRevisions",
+ "ext.RevisionSlider.Api",
"ext.RevisionSlider.arrows.left",
"ext.RevisionSlider.arrows.right",
"ext.RevisionSlider.pointers.lower",
@@ -54,9 +54,9 @@
"ext.RevisionSlider.noscript": {
"styles": "modules/ext.RevisionSlider.noscript.css"
},
- "ext.RevisionSlider.fetchRevisions": {
+ "ext.RevisionSlider.Api": {
"scripts": [
- "modules/ext.RevisionSlider.fetchRevisions.js"
+ "modules/ext.RevisionSlider.Api.js"
]
},
"ext.RevisionSlider.Revision": {
diff --git a/i18n/en.json b/i18n/en.json
index 48fdf34..f86e3e0 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -12,7 +12,7 @@
"revisionslider-label-page-size": "<strong>Page size:</strong> $1
{{PLURAL:$2|byte|bytes}}",
"revisionslider-label-change-size": "<strong>Change size:</strong> $1
{{PLURAL:$2|byte|bytes}}",
"revisionslider-label-comment": "Comment: ",
- "revisionslider-label-username": "<strong>Username:</strong> [[$2|$1]]",
+ "revisionslider-label-username": "<strong>{{GENDER:$2|Username}}:</strong>
[[$3|$1]]",
"revisionslider-minoredit": "This is a minor edit",
"revisionslider-loading-placeholder": "The RevisionSlider is loading...",
"revisionslider-loading-failed": "The RevisionSlider failed to load.",
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 334aa97..24d86d5 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -14,7 +14,7 @@
"revisionslider-label-page-size": "Label describing the size of this
revision.\nParameters:\n* $1 - Formatted page size.\n* $2 - Page size as raw
number used for PLURAL.\n{{Identical|Page size}}",
"revisionslider-label-change-size": "Label describing the size of the
change compared to the revision before.\nParameters:\n* $1 - Formatted change
size colored with markup.\n* $2 - Change size as raw number used for PLURAL",
"revisionslider-label-comment": "Label showing the edit summary of a
revision.\n{{Identical|Comment}}",
- "revisionslider-label-username": "Label for the revision's author's
username.\n{{doc-important|<nowiki>{{</nowiki>[[Gender|GENDER]]<nowiki>}}</nowiki>
is '''NOT''' supported.}}\n\nParameters:\n* $1 - Username, $2 - user page or
Special:Contributors subpage for IP addresses.\n\n{{Identical|Username}}",
+ "revisionslider-label-username": "Label for the revision's author's
username.\nParameters:\n* $1 - Username,\n* $2 - Gender as in user preferences
(\"male\", \"female\" or \"unknown\", passed to GENDER),\n* $3 - User page or
Special:Contributors subpage for IP addresses.\n\n{{Identical|Username}}",
"revisionslider-minoredit": "Text labeling a minor edit.",
"revisionslider-loading-placeholder": "Message shown while the
RevisionSlider is still loading on a diff page. Once loaded the message is
removed.",
"revisionslider-loading-failed": "Message shown if the RevisionSlider
fails to initially load.",
diff --git a/modules/ext.RevisionSlider.Api.js
b/modules/ext.RevisionSlider.Api.js
new file mode 100644
index 0000000..3a7cdb1
--- /dev/null
+++ b/modules/ext.RevisionSlider.Api.js
@@ -0,0 +1,63 @@
+( function ( mw, $ ) {
+ /**
+ * @param {string} apiUrl
+ * @constructor
+ */
+ var Api = function ( apiUrl ) {
+ this.url = apiUrl;
+ };
+
+ $.extend( Api.prototype, {
+ url: '',
+
+ /**
+ * Fetches up to 500 revisions at a time
+ *
+ * @param {Object} options - Options containing callbacks for
`success` and `error` as well as fields for
+ * `pageName` and `startId`
+ */
+ fetchRevisions: function ( options ) {
+ $.ajax( {
+ url: this.url,
+ data: {
+ action: 'query',
+ prop: 'revisions',
+ format: 'json',
+ rvprop:
'ids|timestamp|user|comment|parsedcomment|size|flags',
+ titles: options.pageName,
+ formatversion: 2,
+ rvstartid: options.startId,
+ 'continue': '',
+ rvlimit: 500
+ },
+ success: options.success,
+ error: options.error
+ } );
+ },
+
+ /**
+ * Fetches gender data for up to 500 user names
+ *
+ * @param {Object} options - Options containing callbacks for
`success` and `error` as well as list
+ * of user names in `users`
+ */
+ fetchUserGenderData: function ( options ) {
+ $.ajax( {
+ url: this.url,
+ data: {
+ action: 'query',
+ list: 'users',
+ format: 'json',
+ usprop: 'gender',
+ ususers: options.users.join( '|' ),
+ uslimit: 500
+ },
+ success: options.success,
+ error: options.error
+ } );
+ }
+ } );
+
+ mw.libs.revisionSlider = mw.libs.revisionSlider || {};
+ mw.libs.revisionSlider.Api = Api;
+}( mediaWiki, jQuery ) );
diff --git a/modules/ext.RevisionSlider.Revision.js
b/modules/ext.RevisionSlider.Revision.js
index bd8cc10..1aadb44 100644
--- a/modules/ext.RevisionSlider.Revision.js
+++ b/modules/ext.RevisionSlider.Revision.js
@@ -59,6 +59,11 @@
user: '',
/**
+ * @type {string}
+ */
+ userGender: '',
+
+ /**
* @type {number}
*/
relativeSize: 0,
@@ -133,6 +138,20 @@
},
/**
+ * @param {string} gender
+ */
+ setUserGender: function ( gender ) {
+ this.userGender = gender;
+ },
+
+ /**
+ * @return {string}
+ */
+ getUserGender: function () {
+ return this.userGender;
+ },
+
+ /**
* @param {number} size
*/
setRelativeSize: function ( size ) {
diff --git a/modules/ext.RevisionSlider.RevisionList.js
b/modules/ext.RevisionSlider.RevisionList.js
index e346990..e4a6591 100644
--- a/modules/ext.RevisionSlider.RevisionList.js
+++ b/modules/ext.RevisionSlider.RevisionList.js
@@ -65,6 +65,29 @@
},
/**
+ * @return {string[]}
+ */
+ getUserNames: function () {
+ var allUsers = this.revisions.map( function ( revision
) {
+ return revision.getUser();
+ } );
+ return allUsers.filter( function ( value, index, array
) {
+ return value !== '' && array.indexOf( value )
=== index;
+ } );
+ },
+
+ /**
+ * @param {Object} userGenderData
+ */
+ setUserGenders: function ( userGenderData ) {
+ this.revisions.forEach( function ( revision ) {
+ if ( revision.getUser() !== '' && typeof
userGenderData[ revision.getUser() ] !== 'undefined' ) {
+ revision.setUserGender( userGenderData[
revision.getUser() ] );
+ }
+ } );
+ },
+
+ /**
* @return {RevisionListView}
*/
getView: function () {
diff --git a/modules/ext.RevisionSlider.RevisionListView.js
b/modules/ext.RevisionSlider.RevisionListView.js
index fa2408d..2eed472 100644
--- a/modules/ext.RevisionSlider.RevisionListView.js
+++ b/modules/ext.RevisionSlider.RevisionListView.js
@@ -141,7 +141,7 @@
$( '<p>' ).append(
mw.message(
'revisionslider-label-date', rev.getFormattedDate() ).parseDom()
),
- this.makeUserLine( rev.getUser() ),
+ this.makeUserLine( rev.getUser(),
rev.getUserGender() ),
this.makeCommentLine( rev ),
this.makePageSizeLine( rev.getSize() ),
this.makeChangeSizeLine(
rev.getRelativeSize() ),
@@ -164,15 +164,19 @@
* Generates the HTML for the user label
*
* @param {string} userString
+ * @param {string} userGender
* @return {string|jQuery}
*/
- makeUserLine: function ( userString ) {
+ makeUserLine: function ( userString, userGender ) {
if ( !userString ) {
return '';
}
+ if ( !userGender ) {
+ userGender = 'unknown';
+ }
return $( '<bdi>' ).append( $( '<p>' ).append(
- mw.message( 'revisionslider-label-username',
mw.html.escape( userString ), this.getUserPage( userString ) ).parseDom()
+ mw.message( 'revisionslider-label-username',
mw.html.escape( userString ), userGender, this.getUserPage( userString )
).parseDom()
) );
},
diff --git a/modules/ext.RevisionSlider.fetchRevisions.js
b/modules/ext.RevisionSlider.fetchRevisions.js
deleted file mode 100644
index ca02918..0000000
--- a/modules/ext.RevisionSlider.fetchRevisions.js
+++ /dev/null
@@ -1,29 +0,0 @@
-( function ( mw, $ ) {
- mw.libs.revisionSlider = mw.libs.revisionSlider || {};
-
- /**
- * @member RevisionSlider
- * Fetches up to 500 revisions at a time
- *
- * @param {Object} options - Options containing callbacks for `success`
and `error` as well as fields for
- * `pageName` and `startId`
- */
- mw.libs.revisionSlider.fetchRevisions = function ( options ) {
- $.ajax( {
- url: mw.util.wikiScript( 'api' ),
- data: {
- action: 'query',
- prop: 'revisions',
- format: 'json',
- rvprop:
'ids|timestamp|user|comment|parsedcomment|size|flags',
- titles: options.pageName,
- formatversion: 2,
- rvstartid: options.startId,
- 'continue': '',
- rvlimit: 500
- },
- success: options.success,
- error: options.error
- } );
- };
-}( mediaWiki, jQuery ) );
diff --git a/modules/ext.RevisionSlider.init.js
b/modules/ext.RevisionSlider.init.js
index de04bc3..c65afdb 100644
--- a/modules/ext.RevisionSlider.init.js
+++ b/modules/ext.RevisionSlider.init.js
@@ -1,7 +1,25 @@
( function ( mw, $ ) {
+ var api = new mw.libs.revisionSlider.Api( mw.util.wikiScript( 'api' ) );
+
+ /**
+ * @param {Array} data
+ * @return {Object}
+ */
+ function getUserGenderData( data ) {
+ var genderData = {},
+ usersWithGender = data.filter( function ( item ) {
+ return typeof item.gender !== 'undefined' &&
item.gender !== 'unknown';
+ } );
+ usersWithGender.forEach( function ( item ) {
+ genderData[ item.name ] = item.gender;
+ } );
+ return genderData;
+ }
+
mw.track( 'counter.MediaWiki.RevisionSlider.event.init' );
mw.libs.revisionSlider.userOffset =
mw.user.options.values.timecorrection ?
mw.user.options.values.timecorrection.split( '|' )[ 1 ] :
mw.config.values.extRevisionSliderTimeOffset;
- mw.libs.revisionSlider.fetchRevisions( {
+
+ api.fetchRevisions( {
pageName: mw.config.get( 'wgPageName' ),
startId: mw.config.get( 'wgCurRevisionId' ),
@@ -19,32 +37,50 @@
revs.reverse();
revisionList = new
mw.libs.revisionSlider.RevisionList( mw.libs.revisionSlider.makeRevisions( revs
) );
- $container = $( '#mw-revslider-container' );
- slider = new mw.libs.revisionSlider.Slider(
revisionList );
- slider.getView().render( $container );
- if ( !mw.user.options.get(
'userjs-revslider-hidehelp' ) ) {
-
mw.libs.revisionSlider.HelpDialog.show();
- ( new mw.Api() ).saveOption(
'userjs-revslider-hidehelp', true );
- }
+ api.fetchUserGenderData( {
+ users: revisionList.getUserNames(),
+ success: function ( data ) {
+ var users = data.query.users;
- $container.append(
- $( '<button>' )
- .click( function () {
+ if ( users ) {
+
revisionList.setUserGenders( getUserGenderData( users ) );
+ }
+
+ $container = $(
'#mw-revslider-container' );
+ slider = new
mw.libs.revisionSlider.Slider( revisionList );
+ slider.getView().render(
$container );
+
+ if ( !mw.user.options.get(
'userjs-revslider-hidehelp' ) ) {
mw.libs.revisionSlider.HelpDialog.show();
- } )
- .text( mw.message(
'revisionslider-show-help' ).text() )
- .addClass(
'mw-revslider-show-help' )
- .tipsy( {
- gravity: $( 'body'
).hasClass( 'ltr' ) ? 'se' : 'sw',
- offset: 15,
- title: function () {
- return mw.msg(
'revisionslider-show-help-tooltip' );
- }
- } )
- );
+ ( new mw.Api()
).saveOption( 'userjs-revslider-hidehelp', true );
+ }
- $( '#mw-revslider-placeholder' ).remove();
+ $container.append(
+ $( '<button>' )
+ .click(
function () {
+
mw.libs.revisionSlider.HelpDialog.show();
+ } )
+ .text(
mw.message( 'revisionslider-show-help' ).text() )
+ .addClass(
'mw-revslider-show-help' )
+ .tipsy( {
+
gravity: $( 'body' ).hasClass( 'ltr' ) ? 'se' : 'sw',
+ offset:
15,
+ title:
function () {
+
return mw.msg( 'revisionslider-show-help-tooltip' );
+ }
+ } )
+ );
+
+ $( '#mw-revslider-placeholder'
).remove();
+ },
+ error: function ( err ) {
+ $( '#mw-revslider-placeholder' )
+ .text( mw.message(
'revisionslider-loading-failed' ).text() );
+ console.log( err );
+ mw.track(
'counter.MediaWiki.RevisionSlider.error.init.genders' );
+ }
+ } );
} catch ( err ) {
if ( err === 'RS-rev-out-of-range' ) {
$( '#mw-revslider-placeholder' )
diff --git a/tests/qunit/RevisionSlider.Revision.test.js
b/tests/qunit/RevisionSlider.Revision.test.js
index 38ccc81..eb9a958 100644
--- a/tests/qunit/RevisionSlider.Revision.test.js
+++ b/tests/qunit/RevisionSlider.Revision.test.js
@@ -1,4 +1,6 @@
( function ( mw ) {
+ var Revision = mw.libs.revisionSlider.Revision;
+
QUnit.module( 'ext.RevisionSlider.Revision' );
QUnit.test( 'create Revision', function ( assert ) {
@@ -9,7 +11,7 @@
timestamp: '2016-04-26T10:27:14Z', // 10:27, 26
Apr 2016
user: 'meh'
},
- rev = new mw.libs.revisionSlider.Revision( data );
+ rev = new Revision( data );
mw.libs.revisionSlider.userOffset = 0;
@@ -17,6 +19,7 @@
assert.equal( rev.getComment(), data.comment );
assert.equal( rev.getParsedComment(), data.parsedcomment );
assert.equal( rev.getUser(), data.user );
+ assert.equal( rev.getUserGender(), '' );
assert.equal( rev.isMinor(), false );
if ( mw.config.get( 'wgUserLanguage' ) === 'en' ) {
@@ -25,7 +28,7 @@
} );
QUnit.test( 'isMinor with minor empty string', function ( assert ) {
- var rev = new mw.libs.revisionSlider.Revision( {
+ var rev = new Revision( {
minor: ''
} );
@@ -33,7 +36,7 @@
} );
QUnit.test( 'isMinor with minor true', function ( assert ) {
- var rev = new mw.libs.revisionSlider.Revision( {
+ var rev = new Revision( {
minor: true
} );
@@ -42,13 +45,13 @@
QUnit.test( 'get and set relative size', function ( assert ) {
var size = 5,
- rev = new mw.libs.revisionSlider.Revision( {} );
+ rev = new Revision( {} );
rev.setRelativeSize( size );
assert.equal( rev.getRelativeSize(), size );
} );
QUnit.revisionSlider.testOrSkip( 'getFormattedDate, offset: 0',
function ( assert ) {
- var rev = new mw.libs.revisionSlider.Revision( {
+ var rev = new Revision( {
timestamp: '2016-04-26T10:27:14Z' // 10:27, 26 Apr 2016
} );
@@ -58,7 +61,7 @@
}, mw.config.get( 'wgUserLanguage' ) !== 'en' );
QUnit.revisionSlider.testOrSkip( 'getFormattedDate, offset: 120 (treat
as hours, +2h)', function ( assert ) {
- var rev = new mw.libs.revisionSlider.Revision( {
+ var rev = new Revision( {
timestamp: '2016-04-26T10:27:14Z' // 10:27, 26 Apr 2016
} );
@@ -69,7 +72,7 @@
}, mw.config.get( 'wgUserLanguage' ) !== 'en' );
QUnit.revisionSlider.testOrSkip( 'getFormattedDate, negative offset:
-420 (treat as hours, -7h)', function ( assert ) {
- var rev = new mw.libs.revisionSlider.Revision( {
+ var rev = new Revision( {
timestamp: '2016-04-26T10:27:14Z' // 10:27, 26 Apr 2016
} );
@@ -80,7 +83,7 @@
}, mw.config.get( 'wgUserLanguage' ) !== 'en' );
QUnit.test( 'hasEmptyComment comment with whitespaces', function (
assert ) {
- var rev = new mw.libs.revisionSlider.Revision( {
+ var rev = new Revision( {
comment: ' '
} );
@@ -88,7 +91,7 @@
} );
QUnit.test( 'hasEmptyComment comment with chars', function ( assert ) {
- var rev = new mw.libs.revisionSlider.Revision( {
+ var rev = new Revision( {
comment: ' comment '
} );
@@ -96,12 +99,22 @@
} );
QUnit.test( 'hasEmptyComment comment with unicode chars', function (
assert ) {
- var rev = new mw.libs.revisionSlider.Revision( {
+ var rev = new Revision( {
comment: 'ברוכים'
} );
assert.notOk( rev.hasEmptyComment() );
} );
+ QUnit.test( 'setUserGender adjusts a gender', function ( assert ) {
+ var rev = new Revision( { user: 'Foo' } );
+
+ assert.equal( rev.getUserGender(), '' );
+
+ rev.setUserGender( 'female' );
+
+ assert.equal( rev.getUserGender(), 'female' );
+ } );
+
} )( mediaWiki );
diff --git a/tests/qunit/RevisionSlider.RevisionList.test.js
b/tests/qunit/RevisionSlider.RevisionList.test.js
index 0557b6c..9a4186b 100644
--- a/tests/qunit/RevisionSlider.RevisionList.test.js
+++ b/tests/qunit/RevisionSlider.RevisionList.test.js
@@ -27,6 +27,62 @@
assert.equal( revs.getRevisions()[ 2 ].getRelativeSize(), -8 );
} );
+ QUnit.test( 'getUserNames returns a list of unique names', function (
assert ) {
+ var revs = new RevisionList( [
+ new Revision( { revid: 1, user: 'User1' } ),
+ new Revision( { revid: 2, user: 'User2' } ),
+ new Revision( { revid: 3, user: 'User1' } )
+ ] ),
+ userNames = revs.getUserNames();
+
+ assert.deepEqual( userNames, [ 'User1', 'User2' ] );
+ } );
+
+ QUnit.test( 'getUserNames skips revisions without user specified',
function ( assert ) {
+ var revs = new RevisionList( [
+ new Revision( { revid: 1, user: 'User1' } ),
+ new Revision( { revid: 2 } )
+ ] ),
+ userNames = revs.getUserNames();
+
+ assert.deepEqual( userNames, [ 'User1' ] );
+ } );
+
+ QUnit.test( 'setUserGenders adjusts revision data', function ( assert )
{
+ var revs = new RevisionList( [
+ new Revision( { revid: 1, user: 'User1' } ),
+ new Revision( { revid: 2, user: 'User2' } ),
+ new Revision( { revid: 3, user: 'User3' } )
+ ] ),
+ genders = { User1: 'female', User2: 'male', User3:
'unknown' };
+
+ assert.equal( revs.getRevisions()[ 0 ].getUserGender(), '' );
+ assert.equal( revs.getRevisions()[ 1 ].getUserGender(), '' );
+ assert.equal( revs.getRevisions()[ 2 ].getUserGender(), '' );
+
+ revs.setUserGenders( genders );
+
+ assert.equal( revs.getRevisions()[ 0 ].getUserGender(),
'female' );
+ assert.equal( revs.getRevisions()[ 1 ].getUserGender(), 'male'
);
+ assert.equal( revs.getRevisions()[ 2 ].getUserGender(),
'unknown' );
+ } );
+
+ QUnit.test( 'setUserGenders no gender for a user', function ( assert ) {
+ var revs = new RevisionList( [
+ new Revision( { revid: 1, user: 'User1' } ),
+ new Revision( { revid: 2, user: 'User2' } )
+ ] ),
+ genders = { User1: 'female' };
+
+ assert.equal( revs.getRevisions()[ 0 ].getUserGender(), '' );
+ assert.equal( revs.getRevisions()[ 1 ].getUserGender(), '' );
+
+ revs.setUserGenders( genders );
+
+ assert.equal( revs.getRevisions()[ 0 ].getUserGender(),
'female' );
+ assert.equal( revs.getRevisions()[ 1 ].getUserGender(), '' );
+ } );
+
QUnit.test( 'makeRevisions converts revision data into list of Revision
objects', function ( assert ) {
var revs = [
{ revid: 1, size: 5 },
--
To view, visit https://gerrit.wikimedia.org/r/300881
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Id11fe14e9ca37829141ae92b13b51f10f992eb96
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/RevisionSlider
Gerrit-Branch: master
Gerrit-Owner: WMDE-leszek <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits