Compact links: Execute the compact strategies on need basis

We were executing all compacting strategies even when we have
more than enough items as candidates. If the strategy is expensive,
(performance wise) this is a problem.

In this commit, we execute them one by one and stop when we have enough
candidates.

The methods in CompactInterlanguageList class also arranged as
individual function declarations than comma seperated method list.

Change-Id: Idce6489387d139852125f4448d0e192f6a7e1353
This commit is contained in:
Santhosh Thottingal
2016-06-30 16:42:05 +05:30
committed by Niklas Laxström
parent d46be65c68
commit d109bddf20

View File

@@ -21,22 +21,18 @@
'use strict'; 'use strict';
var DEFAULT_LIST_SIZE = 9; var DEFAULT_LIST_SIZE = 9;
/** /**
* For the given array, remove duplicates * Concatenate two arrays, remove duplicates
* *
* @param {Array} originalArray * @param {Array} a First array
* @return {Array} de-duplicated array * @param {Array} b Second array
* @return {Array} Resulting array
*/ */
function unique( originalArray ) { function concatWithoutDuplicates( a, b ) {
var uniqueArray = []; return a.concat( b.filter( function ( item ) {
return a.indexOf( item ) < 0;
$.each( originalArray, function ( i, v ) { } ) );
if ( $.inArray( v, uniqueArray ) === -1 ) {
uniqueArray.push( v );
}
} );
return uniqueArray;
} }
/** /**
@@ -53,11 +49,10 @@
this.listSize = 0; this.listSize = 0;
} }
CompactInterlanguageList.prototype = {
/** /**
* Initialize the plugin * Initialize the plugin
*/ */
init: function () { CompactInterlanguageList.prototype.init = function () {
var self = this, var self = this,
max = this.options.max || DEFAULT_LIST_SIZE; max = this.options.max || DEFAULT_LIST_SIZE;
@@ -78,12 +73,12 @@
self.render(); self.render();
self.listen(); self.listen();
} ); } );
}, };
/** /**
* Render the compacted interlanguage list and triggers * Render the compacted interlanguage list and triggers
*/ */
render: function () { CompactInterlanguageList.prototype.render = function () {
var language; var language;
for ( language in this.compactList ) { for ( language in this.compactList ) {
@@ -91,14 +86,14 @@
} }
this.addTrigger(); this.addTrigger();
}, };
/** /**
* Attaches the actual selector to the trigger. * Attaches the actual selector to the trigger.
* *
* @param {jQuery} $trigger Element to use as trigger. * @param {jQuery} $trigger Element to use as trigger.
*/ */
createSelector: function ( $trigger ) { CompactInterlanguageList.prototype.createSelector = function ( $trigger ) {
var languages, var languages,
self = this, self = this,
dir = $( 'html' ).prop( 'dir' ), dir = $( 'html' ).prop( 'dir' ),
@@ -175,12 +170,12 @@
// Show common languages // Show common languages
quickList: self.getCommonLanguages( languages ) quickList: self.getCommonLanguages( languages )
} ); } );
}, };
/** /**
* Bind to event handlers and listen for events * Bind to event handlers and listen for events
*/ */
listen: function () { CompactInterlanguageList.prototype.listen = function () {
var self = this; var self = this;
this.$trigger.one( 'click', function () { this.$trigger.one( 'click', function () {
@@ -190,14 +185,14 @@
self.$trigger.click(); self.$trigger.click();
} ); } );
} ); } );
}, };
/** /**
* Get the compacted interlanguage list as associative array * Get the compacted interlanguage list as associative array
* *
* @return {Object} * @return {Object}
*/ */
getCompactList: function () { CompactInterlanguageList.prototype.getCompactList = function () {
var language, languages, compactLanguages, i, var language, languages, compactLanguages, i,
compactedList = {}; compactedList = {};
@@ -213,7 +208,34 @@
} }
return compactedList; return compactedList;
}, };
/**
* Get compacting strategies.
* The items will be executed in the given order till the required
* compact size is achieved. Each item should be an array and should
* take the whole language list as argument.
*
* @return {Function[]} Array of comacting functions
*/
CompactInterlanguageList.prototype.getCompactStrategies = function () {
return [
// Add user-defined assistant languages on wikis with Translate extension.
filterByAssistantLanguages,
// Add previously selected languages.
// Previous languages are always the better suggestion
// because the user has explicitly chosen them.
filterByPreviousLanguages,
// Add all common languages to the beginning of array.
// These are the most probable languages predicted by ULS.
this.getCommonLanguages,
// Some global fallbacks to avoid showing languages in the beginning of the alphabet
getExtraCommonLanguages,
// Finally add the whole languages array too.
// We will remove duplicates and cut down to required size.
this.finalFallback
];
};
/** /**
* Compact a given array of languages * Compact a given array of languages
@@ -221,37 +243,24 @@
* @param {Array} languages * @param {Array} languages
* @return {Array} Compacted array * @return {Array} Compacted array
*/ */
compact: function ( languages ) { CompactInterlanguageList.prototype.compact = function ( languages ) {
var compactLanguages = []; var i, strategies,
compactLanguages = [];
compactLanguages = compactLanguages.concat( strategies = this.getCompactStrategies();
// Add user-defined assistant languages on wikis with Translate extension. for ( i = 0; i < strategies.length; i++ ) {
this.filterByAssistantLanguages( languages ), compactLanguages = concatWithoutDuplicates(
compactLanguages, strategies[ i ].call( this, languages )
// Add previously selected languages.
// Previous languages are always the better suggestion
// because the user has explicitly chosen them.
this.filterByPreviousLanguages( languages ),
// Add all common languages to the beginning of array.
// These are the most probable languages predicted by ULS.
this.getCommonLanguages( languages ),
// Some global fallbacks to avoid showing languages in the beginning of the alphabet
this.getExtraCommonLanguages( languages ),
// Finally add the whole languages array too.
// We will remove duplicates and cut down to required size.
languages
); );
// Remove duplicates if ( compactLanguages.length >= this.compactSize ) {
compactLanguages = unique( compactLanguages ); // We have more than enough items. Stop here.
compactLanguages = compactLanguages.slice( 0, this.compactSize );
// Cut to compact size and sort break;
compactLanguages = compactLanguages.slice( 0, this.compactSize ).sort(); }
}
return compactLanguages; return compactLanguages;
}, };
/** /**
* Filter the language list by previous languages. * Filter the language list by previous languages.
@@ -260,13 +269,13 @@
* *
* @return {Array} List of language codes supported by the article * @return {Array} List of language codes supported by the article
*/ */
filterByPreviousLanguages: function ( languages ) { function filterByPreviousLanguages( languages ) {
var previousLanguages = mw.uls.getPreviousLanguages(); var previousLanguages = mw.uls.getPreviousLanguages();
return $.grep( previousLanguages, function ( language ) { return $.grep( previousLanguages, function ( language ) {
return $.inArray( language, languages ) >= 0; return $.inArray( language, languages ) >= 0;
} ); } );
}, }
/** /**
* Filter the language list by common languages. * Filter the language list by common languages.
@@ -274,13 +283,13 @@
* *
* @return {Array} List of language codes supported by the article * @return {Array} List of language codes supported by the article
*/ */
filterByCommonLanguages: function ( languages ) { function filterByCommonLanguages( languages ) {
var commonLanguages = mw.uls.getFrequentLanguageList(); var commonLanguages = mw.uls.getFrequentLanguageList();
return $.grep( commonLanguages, function ( language ) { return $.grep( commonLanguages, function ( language ) {
return $.inArray( language, languages ) >= 0; return $.inArray( language, languages ) >= 0;
} ); } );
}, }
/** /**
* Filter the language list by globally common languages, i.e. * Filter the language list by globally common languages, i.e.
@@ -288,7 +297,7 @@
* *
* @return {Array} List of language codes supported by the article * @return {Array} List of language codes supported by the article
*/ */
getExtraCommonLanguages: function ( languages ) { function getExtraCommonLanguages( languages ) {
var commonLanguages = [ 'zh', 'en', 'hi', 'ur', 'es', 'ar', 'ru', 'id', 'ms', 'pt', var commonLanguages = [ 'zh', 'en', 'hi', 'ur', 'es', 'ar', 'ru', 'id', 'ms', 'pt',
'fr', 'de', 'bn', 'ja', 'pnb', 'pa', 'jv', 'te', 'ta', 'ko', 'mr', 'tr', 'vi', 'fr', 'de', 'bn', 'ja', 'pnb', 'pa', 'jv', 'te', 'ta', 'ko', 'mr', 'tr', 'vi',
'it', 'fa', 'sv', 'nl', 'pl' ]; 'it', 'fa', 'sv', 'nl', 'pl' ];
@@ -296,7 +305,7 @@
return $.grep( commonLanguages, function ( language ) { return $.grep( commonLanguages, function ( language ) {
return $.inArray( language, languages ) >= 0; return $.inArray( language, languages ) >= 0;
} ); } );
}, }
/** /**
* Filter the language list by Translate's assistant languages. * Filter the language list by Translate's assistant languages.
@@ -304,7 +313,7 @@
* *
* @return {Array} List of those language codes which are supported by article * @return {Array} List of those language codes which are supported by article
*/ */
filterByAssistantLanguages: function ( languages ) { function filterByAssistantLanguages( languages ) {
var assistantLanguages = mw.user.options.get( 'translate-editlangs' ); var assistantLanguages = mw.user.options.get( 'translate-editlangs' );
if ( assistantLanguages && assistantLanguages !== 'default' ) { if ( assistantLanguages && assistantLanguages !== 'default' ) {
@@ -314,7 +323,7 @@
} }
return []; return [];
}, }
/** /**
* Find out the existing languages supported * Find out the existing languages supported
@@ -322,7 +331,7 @@
* *
* @return {Object} List of existing language codes and their hrefs * @return {Object} List of existing language codes and their hrefs
*/ */
getInterlanguageList: function () { CompactInterlanguageList.prototype.getInterlanguageList = function () {
var interlanguageList = {}; var interlanguageList = {};
this.$interlanguageList.find( 'li.interlanguage-link > a' ).each( function () { this.$interlanguageList.find( 'li.interlanguage-link > a' ).each( function () {
@@ -338,32 +347,36 @@
} ); } );
return interlanguageList; return interlanguageList;
}, };
/** /**
* Get common languages - the most probable languages predicted by ULS. * Get common languages - the most probable languages predicted by ULS.
* *
* @param {Array} languages Array of all languages. * @param {Array} languages Array of all languages.
*/ */
getCommonLanguages: function ( languages ) { CompactInterlanguageList.prototype.getCommonLanguages = function ( languages ) {
if ( this.commonInterlanguageList === null ) { if ( this.commonInterlanguageList === null ) {
this.commonInterlanguageList = this.filterByCommonLanguages( languages ); this.commonInterlanguageList = filterByCommonLanguages( languages );
} }
return this.commonInterlanguageList; return this.commonInterlanguageList;
}, };
CompactInterlanguageList.prototype.finalFallback = function ( languages ) {
return languages;
};
/** /**
* Hide the original interlanguage list * Hide the original interlanguage list
*/ */
hideOriginal: function () { CompactInterlanguageList.prototype.hideOriginal = function () {
this.$interlanguageList.find( '.interlanguage-link' ).css( 'display', 'none' ); this.$interlanguageList.find( '.interlanguage-link' ).css( 'display', 'none' );
}, };
/** /**
* Add the trigger at the bottom of the language list * Add the trigger at the bottom of the language list
*/ */
addTrigger: function () { CompactInterlanguageList.prototype.addTrigger = function () {
var $trigger; var $trigger;
$trigger = $( '<button>' ) $trigger = $( '<button>' )
@@ -376,7 +389,6 @@
this.$interlanguageList.append( $trigger ); this.$interlanguageList.append( $trigger );
this.$trigger = $trigger; this.$trigger = $trigger;
}
}; };
$( document ).ready( function () { $( document ).ready( function () {