Follow redirects in the category widgets

Display the redirects nicely in the UI, etc.

Bug: 52414
Change-Id: Ib62144cb90899d0c525d6f08f6b5f1159b7d2a86
This commit is contained in:
Krenair 2014-03-11 19:02:16 +00:00 committed by Jforrester
parent 8d99aa88c8
commit 9c2e1d8048
3 changed files with 103 additions and 14 deletions

View file

@ -38,6 +38,7 @@ ve.ui.MWCategoryInputWidget = function VeUiMWCategoryInputWidget( categoryWidget
// Initialization
this.$element.addClass( 've-ui-mwCategoryInputWidget' );
this.lookupMenu.$element.addClass( 've-ui-mwCategoryInputWidget-menu' );
this.categoryRedirects = [];
};
/* Inheritance */
@ -67,7 +68,8 @@ ve.ui.MWCategoryInputWidget.prototype.getLookupRequest = function () {
'action': 'query',
'prop': 'pageprops',
'titles': ( data[1] || [] ).join( '|' ),
'ppprop': 'hiddencat'
'ppprop': 'hiddencat',
'redirects': ''
} );
return propsJqXhr;
} ).promise( { abort: function () {
@ -86,18 +88,31 @@ ve.ui.MWCategoryInputWidget.prototype.getLookupRequest = function () {
* @param {Mixed} data Response from server
*/
ve.ui.MWCategoryInputWidget.prototype.getLookupCacheItemFromData = function ( data ) {
var categoryWidget = this.categoryWidget, result = {};
var categoryInputWidget = this, result = {};
if ( data.query && data.query.pages ) {
$.each( data.query.pages, function ( pageId, pageInfo ) {
var title = mw.Title.newFromText( pageInfo.title );
if ( title ) {
result[title.getMainText()] = !!( pageInfo.pageprops && pageInfo.pageprops.hiddencat !== undefined );
categoryWidget.categoryHiddenStatus[pageInfo.title] = result[title.getMainText()];
categoryInputWidget.categoryWidget.categoryHiddenStatus[pageInfo.title] = result[title.getMainText()];
} else {
mw.log.warning( '"' + pageInfo.title + '" is an invalid title!' );
}
} );
}
if ( data.query && data.query.redirects ) {
$.each( data.query.redirects, function ( index, redirectInfo ) {
var foundIdentical = false;
$.each( categoryInputWidget.categoryRedirects, function ( index, existingRedirectInfo ) {
if ( existingRedirectInfo.from === redirectInfo.from && existingRedirectInfo.to === redirectInfo.to ) {
foundIdentical = true;
}
} );
if ( !foundIdentical ) {
categoryInputWidget.categoryRedirects.push( redirectInfo );
}
} );
}
return result;
};
@ -119,7 +134,20 @@ ve.ui.MWCategoryInputWidget.prototype.getLookupMenuItemsFromData = function ( da
category = this.getCategoryItemFromValue( this.value ),
existingCategories = this.categoryWidget.getCategories(),
matchingCategories = [],
hiddenCategories = [];
hiddenCategories = [],
redirectStorage = {},
itemTitle,
searchForQueryWithinRedirectInfo = function ( element ) {
return element.lastIndexOf( new mw.Title( 'Category:' + category.value ).getPrefixedText(), 0 ) === 0;
};
$.each( this.categoryRedirects, function () {
if ( redirectStorage.hasOwnProperty( this.to ) && redirectStorage[this.to].indexOf( this.from ) === -1 ) {
redirectStorage[this.to].push( this.from );
} else {
redirectStorage[this.to] = [this.from];
}
} );
$.each( data, function ( title, hiddenStatus ) {
if ( hiddenStatus ) {
@ -140,14 +168,22 @@ ve.ui.MWCategoryInputWidget.prototype.getLookupMenuItemsFromData = function ( da
existingCategoryItems.push( item );
}
}
// Matching categories
for ( i = 0, len = matchingCategories.length; i < len; i++ ) {
item = matchingCategories[i];
itemTitle = new mw.Title( 'Category:' + item ).getPrefixedText();
if (
ve.indexOf( item, existingCategories ) === -1 &&
item.lastIndexOf( category.value, 0 ) === 0
item.lastIndexOf( category.value, 0 ) === 0 || (
redirectStorage[itemTitle] !== undefined &&
$.grep( redirectStorage[itemTitle], searchForQueryWithinRedirectInfo ).length
)
) {
if ( item === category.value ) {
if ( ( item === category.value ) || (
redirectStorage[itemTitle] !== undefined &&
redirectStorage[itemTitle].indexOf( new mw.Title( 'Category:' + category.value ).getPrefixedText() ) !== -1
) ) {
exactMatch = true;
}
matchingCategoryItems.push( item );
@ -156,16 +192,24 @@ ve.ui.MWCategoryInputWidget.prototype.getLookupMenuItemsFromData = function ( da
// Hidden categories
for ( i = 0, len = hiddenCategories.length; i < len; i++ ) {
item = hiddenCategories[i];
itemTitle = new mw.Title( 'Category:' + item ).getPrefixedText();
if (
ve.indexOf( item, existingCategories ) === -1 &&
item.lastIndexOf( category.value, 0 ) === 0
item.lastIndexOf( category.value, 0 ) === 0 || (
redirectStorage[itemTitle] !== undefined &&
$.grep( redirectStorage[itemTitle], searchForQueryWithinRedirectInfo ).length
)
) {
if ( item === category.value ) {
if ( ( item === category.value ) || (
redirectStorage[itemTitle] !== undefined &&
redirectStorage[itemTitle].indexOf( new mw.Title( 'Category:' + category.value ).getPrefixedText() ) !== -1
) ) {
exactMatch = true;
}
hiddenCategoryItems.push( item );
}
}
// New category
if ( !exactMatch ) {
newCategoryItems.push( category.value );
@ -196,7 +240,7 @@ ve.ui.MWCategoryInputWidget.prototype.getLookupMenuItemsFromData = function ( da
) );
for ( i = 0, len = matchingCategoryItems.length; i < len; i++ ) {
item = matchingCategoryItems[i];
items.push( new OO.ui.MenuItemWidget( item, { '$': menu$, 'label': item } ) );
items.push( this.getMenuItemWidgetFromCategoryName( item, menu$ ) );
}
}
if ( hiddenCategoryItems.length ) {
@ -205,13 +249,41 @@ ve.ui.MWCategoryInputWidget.prototype.getLookupMenuItemsFromData = function ( da
) );
for ( i = 0, len = hiddenCategoryItems.length; i < len; i++ ) {
item = hiddenCategoryItems[i];
items.push( new OO.ui.MenuItemWidget( item, { '$': menu$, 'label': item } ) );
items.push( this.getMenuItemWidgetFromCategoryName( item, menu$ ) );
}
}
return items;
};
/**
* Get a OO.ui.MenuSectionItemWidget object for a given category name.
* Deals with redirects.
*
* @method
* @param {string} item Category name
* @param {jQuery} menu$ Lookup menu jQuery
* @returns {OO.ui.MenuSectionItemWidget} Menu item
*/
ve.ui.MWCategoryInputWidget.prototype.getMenuItemWidgetFromCategoryName = function ( item, menu$ ) {
var itemTitle = new mw.Title( 'Category:' + item ).getPrefixedText(),
redirectInfo = $.grep( this.categoryRedirects, function ( redirectInfo ) {
return redirectInfo.to === itemTitle;
} );
if ( redirectInfo.length ) {
return new OO.ui.MenuItemWidget( item, {
'$': menu$,
'autoFitLabel': false,
'label': this.$( '<span>' )
.text( new mw.Title( redirectInfo[0].from ).getMainText() )
.append( '<br>↳ ' )
.append( $( '<span>' ).text( new mw.Title( item ).getMainText() ) )
} );
} else {
return new OO.ui.MenuItemWidget( item, { '$': menu$, 'label': item } );
}
};
/**
* Get a category item.
*

View file

@ -17,6 +17,7 @@
* @param {Object} [config] Configuration options
* @cfg {Object} [item] Category item
* @cfg {boolean} [hidden] Whether the category is hidden or not
* @cfg {string} [redirectTo] The name of the category this category's page redirects to.
*/
ve.ui.MWCategoryItemWidget = function VeUiMWCategoryItemWidget( config ) {
// Config intialization
@ -47,7 +48,7 @@ ve.ui.MWCategoryItemWidget = function VeUiMWCategoryItemWidget( config ) {
// Initialization
this.$label
.addClass( 've-ui-mwCategoryItemWidget-label' )
.text( this.value );
.text( config.redirectTo || this.value );
this.$categoryItem
.addClass( 've-ui-mwCategoryItemWidget-button' )
.append( this.$label, this.$indicator );

View file

@ -29,6 +29,7 @@ ve.ui.MWCategoryWidget = function VeUiMWCategoryWidget( config ) {
// Properties
this.categories = {};
this.categoryHiddenStatus = {};
this.categoryRedirects = {}; // Source -> target
this.popupState = false;
this.savedPopupState = false;
this.popup = new ve.ui.MWCategoryPopupWidget( {
@ -215,7 +216,8 @@ ve.ui.MWCategoryWidget.prototype.queryCategoryHiddenStatus = function ( category
action: 'query',
prop: 'pageprops',
titles: categoryNamesToQuery.join( '|' ),
ppprop: 'hiddencat'
ppprop: 'hiddencat',
redirects: ''
} ).then( function ( result ) {
if ( result && result.query && result.query.pages ) {
$.each( result.query.pages, function ( index, pageInfo ) {
@ -223,6 +225,11 @@ ve.ui.MWCategoryWidget.prototype.queryCategoryHiddenStatus = function ( category
categoryWidget.categoryHiddenStatus[pageInfo.title] = hiddenStatus;
} );
}
if ( result && result.query && result.query.redirects ) {
$.each( result.query.redirects, function ( index, redirectInfo ) {
categoryWidget.categoryRedirects[redirectInfo.from] = redirectInfo.to;
} );
}
} );
};
@ -244,15 +251,24 @@ ve.ui.MWCategoryWidget.prototype.addItems = function ( items, index ) {
categoryWidget = this;
return this.queryCategoryHiddenStatus( categoryNames ).then( function () {
var itemTitle, config;
for ( i = 0, len = items.length; i < len; i++ ) {
item = items[i];
itemTitle = new mw.Title( item.name, mw.config.get( 'wgNamespaceIds' ).category ).getPrefixedText();
// Create a widget using the item data
categoryItem = new ve.ui.MWCategoryItemWidget( {
config = {
'$': categoryWidget.$,
'item': item,
'hidden': categoryWidget.categoryHiddenStatus[item.name]
} );
};
if ( Object.prototype.hasOwnProperty.call( categoryWidget.categoryRedirects, itemTitle ) ) {
config.redirectTo = new mw.Title(
categoryWidget.categoryRedirects[itemTitle],
mw.config.get( 'wgNamespaceIds' ).category
).getMainText();
}
categoryItem = new ve.ui.MWCategoryItemWidget( config );
categoryItem.connect( categoryWidget, {
'savePopupState': 'onSavePopupState',
'togglePopupMenu': 'onTogglePopupMenu'