Interlanguage lists can contain language codes that are redirects in language data of ULS. For example, sr is a redirect to sr-cyrl. So, if sr is passes as one of the language to ULS, its region, script grouping is failing and the end result will be missing them in the ULS language list. This should be properly fixed in jquery.uls library. Tracked at https://github.com/wikimedia/jquery.uls/issues/207 In this patch we are following a simple approach of passing the language codes to ULS as redirect resolved. Bug: T100002 Bug: T131005 Bug: T126909 Bug: T123834 Change-Id: I8b89edb60b4d2c6f2b25c8589569f748c5523722
357 lines
10 KiB
JavaScript
357 lines
10 KiB
JavaScript
/*!
|
|
* Compact the interlanguage links in the sidebar
|
|
*
|
|
* Copyright (C) 2012-2014 Alolita Sharma, Amir Aharoni, Arun Ganesh, Brandon Harris,
|
|
* Niklas Laxström, Pau Giner, Santhosh Thottingal, Siebrand Mazeland, Niharika Kohli
|
|
* and other contributors. See CREDITS for a list.
|
|
*
|
|
* UniversalLanguageSelector is dual licensed GPLv2 or later and MIT. You don't
|
|
* have to do anything special to choose one license or the other and you don't
|
|
* have to notify anyone which license you are using. You are free to use
|
|
* UniversalLanguageSelector in commercial projects as long as the copyright
|
|
* header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
|
|
*
|
|
* @file
|
|
* @ingroup Extensions
|
|
* @licence GNU GPL-2.0+
|
|
* @licence MIT License
|
|
*/
|
|
|
|
( function ( $, mw ) {
|
|
'use strict';
|
|
|
|
/**
|
|
* For the given array, remove duplicates
|
|
*
|
|
* @param {Array} originalArray
|
|
* @return {Array} de-duplicated array
|
|
*/
|
|
function unique( originalArray ) {
|
|
var uniqueArray = [];
|
|
|
|
$.each( originalArray, function ( i, v ) {
|
|
if ( $.inArray( v, uniqueArray ) === -1 ) {
|
|
uniqueArray.push( v );
|
|
}
|
|
} );
|
|
|
|
return uniqueArray;
|
|
}
|
|
|
|
/**
|
|
* @class
|
|
*/
|
|
function CompactInterlanguageList( interlanguageList, options ) {
|
|
this.$interlanguageList = $( interlanguageList );
|
|
this.options = $.extend( {}, $.fn.compactInterlanguageList.defaults, options );
|
|
this.interlanguageList = {};
|
|
this.compactList = {};
|
|
this.$trigger = null;
|
|
this.compactSize = 0;
|
|
this.listSize = 0;
|
|
this.init();
|
|
}
|
|
|
|
CompactInterlanguageList.prototype = {
|
|
/**
|
|
* Initialize the plugin
|
|
*/
|
|
init: function () {
|
|
var max = this.options.max;
|
|
this.interlanguageList = this.getInterlanguageList();
|
|
this.listSize = this.getListSize();
|
|
|
|
if ( this.listSize <= max ) {
|
|
// Not enough languages to compact the list
|
|
return;
|
|
}
|
|
|
|
// If we're only a bit beyond max, limit to 7 instead of 9.
|
|
// FIXME: This assumes the max is 9.
|
|
this.compactSize = ( this.listSize <= 12 ) ? 7 : max;
|
|
this.compactList = this.getCompactList();
|
|
this.hideOriginal();
|
|
this.render();
|
|
this.listen();
|
|
},
|
|
|
|
/**
|
|
* Render the compacted interlanguage list and triggers
|
|
*/
|
|
render: function () {
|
|
var language;
|
|
|
|
for ( language in this.compactList ) {
|
|
this.compactList[ language ].element.parentNode.style.display = '';
|
|
}
|
|
|
|
this.addTrigger();
|
|
},
|
|
|
|
/**
|
|
* Bind to event handlers and listen for events
|
|
*/
|
|
listen: function () {
|
|
var languages,
|
|
compactLinks = this,
|
|
dir = $( 'html' ).prop( 'dir' ),
|
|
interlanguageListLeft,
|
|
interlanguageListWidth,
|
|
ulsLanguageList = {};
|
|
|
|
languages = $.map( compactLinks.interlanguageList, function ( language, languageCode ) {
|
|
ulsLanguageList[ languageCode ] = language.autonym;
|
|
|
|
return languageCode;
|
|
} );
|
|
|
|
// Calculate the left and width values
|
|
interlanguageListLeft = compactLinks.$interlanguageList.offset().left;
|
|
interlanguageListWidth = compactLinks.$interlanguageList.width();
|
|
// Attach ULS to the trigger
|
|
compactLinks.$trigger.uls( {
|
|
onReady: function () {
|
|
this.$menu.addClass( 'interlanguage-uls-menu' );
|
|
},
|
|
/**
|
|
* Language selection handler
|
|
*
|
|
* @param {string} language language code
|
|
*/
|
|
onSelect: function ( language ) {
|
|
var previousLanguages = mw.uls.getPreviousLanguages();
|
|
|
|
previousLanguages.push( language );
|
|
previousLanguages = unique( previousLanguages );
|
|
mw.uls.setPreviousLanguages( previousLanguages );
|
|
location.href = compactLinks.interlanguageList[ language ].href;
|
|
},
|
|
onVisible: function () {
|
|
// Calculate the positioning of the panel
|
|
// according to the position of the trigger icon
|
|
if ( dir === 'rtl' ) {
|
|
this.left = interlanguageListLeft - this.$menu.width();
|
|
} else {
|
|
this.left = interlanguageListLeft + interlanguageListWidth;
|
|
}
|
|
this.$menu.css( 'left', this.left );
|
|
},
|
|
languageDecorator: function ( $languageLink, language ) {
|
|
// set href and text exactly same as what was in
|
|
// interlanguage link. The ULS autonym might be different in some
|
|
// cases like sr. In ULS it is "српски", while in interlanguage links
|
|
// it is "српски / srpski"
|
|
$languageLink
|
|
.prop( 'href', compactLinks.interlanguageList[ language ].href )
|
|
.text( compactLinks.interlanguageList[ language ].autonym );
|
|
},
|
|
// Use compact version of ULS
|
|
compact: true,
|
|
// Top position of the language selector. Top it 250px above to take care of
|
|
// caret pointing the trigger. See .interlanguage-uls-menu:after style definition
|
|
top: compactLinks.$trigger.offset().top - compactLinks.$trigger.height() / 2 - 250,
|
|
// List of languages to be shown
|
|
languages: ulsLanguageList,
|
|
// Show common languages
|
|
quickList: compactLinks.filterByCommonLanguages( languages )
|
|
} );
|
|
},
|
|
|
|
/**
|
|
* Get the compacted interlanguage list as associative array
|
|
*
|
|
* @return {Object}
|
|
*/
|
|
getCompactList: function () {
|
|
var language, languages, compactLanguages, i,
|
|
compactedList = {};
|
|
|
|
languages = $.map( this.interlanguageList, function ( item, languageCode ) {
|
|
return languageCode;
|
|
} );
|
|
|
|
compactLanguages = this.compact( languages );
|
|
|
|
for ( i = 0; i < compactLanguages.length; i++ ) {
|
|
language = compactLanguages[ i ];
|
|
compactedList[ language ] = this.interlanguageList[ language ];
|
|
}
|
|
|
|
return compactedList;
|
|
},
|
|
|
|
/**
|
|
* Compact a given array of languages
|
|
*
|
|
* @param {Array} languages
|
|
* @return {Array} Compacted array
|
|
*/
|
|
compact: function ( languages ) {
|
|
var compactLanguages = [];
|
|
|
|
compactLanguages = compactLanguages.concat(
|
|
// Add user-defined assistant languages on wikis with Translate extension.
|
|
this.filterByAssistantLanguages( 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.filterByCommonLanguages( languages ),
|
|
|
|
// Finally add the whole languages array too.
|
|
// We will remove duplicates and cut down to required size.
|
|
languages
|
|
);
|
|
// Remove duplicates
|
|
compactLanguages = unique( compactLanguages );
|
|
|
|
// Cut to compact size and sort
|
|
compactLanguages = compactLanguages.slice( 0, this.compactSize ).sort();
|
|
|
|
return compactLanguages;
|
|
},
|
|
|
|
/**
|
|
* Filter the language list by previous languages.
|
|
* Not all previous languages will be present in interlanguage links,
|
|
* so we are filtering them.
|
|
*
|
|
* @return {Array} List of language codes supported by the article
|
|
*/
|
|
filterByPreviousLanguages: function ( languages ) {
|
|
var previousLanguages = mw.uls.getPreviousLanguages();
|
|
|
|
return $.grep( previousLanguages, function ( language ) {
|
|
return $.inArray( language, languages ) >= 0;
|
|
} );
|
|
},
|
|
|
|
/**
|
|
* Filter the language list by common languages.
|
|
* Common languages are the most probable languages predicted by ULS.
|
|
*
|
|
* @return {Array} List of language codes supported by the article
|
|
*/
|
|
filterByCommonLanguages: function ( languages ) {
|
|
var commonLanguages = mw.uls.getFrequentLanguageList();
|
|
|
|
return $.grep( commonLanguages, function ( language ) {
|
|
return $.inArray( language, languages ) >= 0;
|
|
} );
|
|
},
|
|
|
|
/**
|
|
* Filter the language list by Translate's assistant languages.
|
|
* Where available, they're languages deemed useful by the user.
|
|
*
|
|
* @return {Array} List of those language codes which are supported by article
|
|
*/
|
|
filterByAssistantLanguages: function ( languages ) {
|
|
var assistantLanguages = mw.user.options.get( 'translate-editlangs' );
|
|
|
|
if ( assistantLanguages && assistantLanguages !== 'default' ) {
|
|
return $.grep( assistantLanguages.split( /,\s*/ ), function ( language ) {
|
|
return $.inArray( language, languages ) >= 0;
|
|
} );
|
|
}
|
|
|
|
return [];
|
|
},
|
|
|
|
/**
|
|
* Find out the existing languages supported
|
|
* by the article and fetch their href.
|
|
*
|
|
* @return {Object} List of existing language codes and their hrefs
|
|
*/
|
|
getInterlanguageList: function () {
|
|
var interlanguageList = {};
|
|
|
|
this.$interlanguageList.find( 'li.interlanguage-link > a' ).each( function () {
|
|
var langCode = this.getAttribute( 'lang' );
|
|
|
|
// We keep interlanguageList with redirect resolved language codes as keys.
|
|
langCode = $.uls.data.isRedirect( langCode ) || langCode;
|
|
interlanguageList[ langCode ] = {
|
|
href: this.getAttribute( 'href' ),
|
|
autonym: $( this ).text(),
|
|
element: this
|
|
};
|
|
} );
|
|
|
|
return interlanguageList;
|
|
},
|
|
|
|
/**
|
|
* Get the size of the interlanguage list
|
|
*/
|
|
getListSize: function () {
|
|
return $.map( this.interlanguageList, function ( item, languageCode ) {
|
|
return languageCode;
|
|
} ).length;
|
|
},
|
|
|
|
/**
|
|
* Hide the original interlanguage list
|
|
*/
|
|
hideOriginal: function () {
|
|
this.$interlanguageList.find( '.interlanguage-link' ).css( 'display', 'none' );
|
|
},
|
|
|
|
/**
|
|
* Add the trigger at the bottom of the language list
|
|
*/
|
|
addTrigger: function () {
|
|
var $trigger;
|
|
|
|
$trigger = $( '<button>' )
|
|
.addClass( 'mw-interlanguage-selector mw-ui-button active' )
|
|
.html( $.i18n(
|
|
'ext-uls-compact-link-count',
|
|
mw.language.convertNumber( this.listSize - this.compactSize )
|
|
) );
|
|
|
|
this.$interlanguageList.append( $trigger );
|
|
this.$trigger = $trigger;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* CompactInterlanguageList Plugin
|
|
*
|
|
* @param {Object} [option]
|
|
*/
|
|
$.fn.compactInterlanguageList = function ( option ) {
|
|
return this.each( function () {
|
|
var $this = $( this ),
|
|
data = $this.data( 'compactinterlanguagelist' ),
|
|
options = typeof option === 'object' && option;
|
|
|
|
if ( !data ) {
|
|
data = new CompactInterlanguageList( this, options );
|
|
$this.data( 'compactinterlanguagelist', data );
|
|
}
|
|
|
|
if ( typeof option === 'string' ) {
|
|
data[ option ]();
|
|
}
|
|
} );
|
|
};
|
|
|
|
/**
|
|
* Defaults
|
|
*/
|
|
$.fn.compactInterlanguageList.defaults = {
|
|
// Compact the list to this size
|
|
max: 9
|
|
};
|
|
|
|
$( document ).ready( function () {
|
|
$( '#p-lang ul' ).compactInterlanguageList();
|
|
} );
|
|
}( jQuery, mediaWiki ) );
|