mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-15 18:39:52 +00:00
18cde8a420
Turns out that by skipping the last item, the following logic which depended on that item being in the existing items list failed to keep it's grubby hands off it. Yes, I know I +2'd it. Shame on me too. Bug: 48556 Bug: 48565 I93ce05f7cbb28313a3f0827539f0528c366aeb7e Change-Id: If48e001b92c217bee0a35b6da41d1c1ff0e3271c
204 lines
5.9 KiB
JavaScript
204 lines
5.9 KiB
JavaScript
/*!
|
|
* VisualEditor UserInterface MWCategoryInputWidget class.
|
|
*
|
|
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
/*global mw */
|
|
|
|
/**
|
|
* Creates an ve.ui.MWCategoryInputWidget object.
|
|
*
|
|
* @class
|
|
* @extends ve.ui.TextInputWidget
|
|
* @mixins ve.ui.LookupInputWidget
|
|
*
|
|
* @constructor
|
|
* @param {ve.ui.MWCategoryWidget} categoryWidget
|
|
* @param {Object} [config] Config options
|
|
*/
|
|
ve.ui.MWCategoryInputWidget = function VeUiMWCategoryInputWidget( categoryWidget, config ) {
|
|
// Config intialization
|
|
config = ve.extendObject( {
|
|
'placeholder': ve.msg( 'visualeditor-dialog-meta-categories-input-placeholder' )
|
|
}, config );
|
|
|
|
// Parent constructor
|
|
ve.ui.TextInputWidget.call( this, config );
|
|
|
|
// Mixin constructors
|
|
ve.ui.LookupInputWidget.call( this, this, config );
|
|
|
|
// Properties
|
|
this.categoryWidget = categoryWidget;
|
|
this.forceCapitalization = mw.config.get( 'wgCaseSensitiveNamespaces' ).indexOf( 14 ) === -1;
|
|
this.categoryPrefix = mw.config.get( 'wgFormattedNamespaces' )['14'] + ':';
|
|
|
|
// Initialization
|
|
this.$.addClass( 've-ui-mwCategoryInputWidget' );
|
|
this.lookupMenu.$.addClass( 've-ui-mwCategoryInputWidget-menu' );
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
ve.inheritClass( ve.ui.MWCategoryInputWidget, ve.ui.TextInputWidget );
|
|
|
|
ve.mixinClass( ve.ui.MWCategoryInputWidget, ve.ui.LookupInputWidget );
|
|
|
|
/* Methods */
|
|
|
|
/**
|
|
* Gets a new request object of the current lookup query value.
|
|
*
|
|
* @method
|
|
* @returns {jQuery.Deferred} Deferred object with success and fail handlers already attached
|
|
*/
|
|
ve.ui.MWCategoryInputWidget.prototype.getLookupRequest = function () {
|
|
return $.ajax( {
|
|
'url': mw.util.wikiScript( 'api' ),
|
|
'data': {
|
|
'format': 'json',
|
|
'action': 'opensearch',
|
|
'search': this.categoryPrefix + this.value,
|
|
'suggest': ''
|
|
},
|
|
'dataType': 'json'
|
|
} );
|
|
};
|
|
|
|
/**
|
|
* Get lookup cache item from server response data.
|
|
*
|
|
* @method
|
|
* @param {Mixed} data Response from server
|
|
*/
|
|
ve.ui.MWCategoryInputWidget.prototype.getLookupCacheItemFromData = function ( data ) {
|
|
var i, len, title, result = [];
|
|
if ( ve.isArray( data ) && data.length ) {
|
|
for ( i = 0, len = data[1].length; i < len; i++ ) {
|
|
try {
|
|
title = new mw.Title( data[1][i] );
|
|
result.push( title.getNameText() );
|
|
} catch ( e ) { }
|
|
// If the received title isn't valid, just ignore it
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Get list of menu items from a server response.
|
|
*
|
|
* @param {Object} data Query result
|
|
* @returns {ve.ui.MenuItemWidget[]} Menu items
|
|
*/
|
|
ve.ui.MWCategoryInputWidget.prototype.getLookupMenuItemsFromData = function ( data ) {
|
|
var i, len, item,
|
|
exactMatch = false,
|
|
newCategoryItems = [],
|
|
existingCategoryItems = [],
|
|
matchingCategoryItems = [],
|
|
items = [],
|
|
menu$$ = this.lookupMenu.$$,
|
|
category = this.getCategoryItemFromValue( this.value ),
|
|
existingCategories = this.categoryWidget.getCategories(),
|
|
matchingCategories = data || [];
|
|
|
|
// Existing categories
|
|
for ( i = 0, len = existingCategories.length; i < len; i++ ) {
|
|
item = existingCategories[i];
|
|
// Verify that item starts with category.value
|
|
if ( item.lastIndexOf( category.value, 0 ) === 0 ) {
|
|
if ( item === category.value ) {
|
|
exactMatch = true;
|
|
}
|
|
existingCategoryItems.push( item );
|
|
}
|
|
}
|
|
// Matching categories
|
|
for ( i = 0, len = matchingCategories.length; i < len; i++ ) {
|
|
item = matchingCategories[i];
|
|
if (
|
|
ve.indexOf( item, existingCategoryItems ) === -1 &&
|
|
item.lastIndexOf( category.value, 0 ) === 0
|
|
) {
|
|
if ( item === category.value ) {
|
|
exactMatch = true;
|
|
}
|
|
matchingCategoryItems.push( item );
|
|
}
|
|
}
|
|
// New category
|
|
if ( !exactMatch ) {
|
|
newCategoryItems.push( category.value );
|
|
}
|
|
|
|
// bug 48556: Don't actually offer to move the very last category in the list - we kept it in
|
|
// the list thus far so that other lists would not grab it for themselves, but now it's time to
|
|
// say goodbye
|
|
if (
|
|
existingCategoryItems[existingCategoryItems.length - 1] ===
|
|
existingCategories[existingCategories.length - 1] ) {
|
|
existingCategoryItems.pop();
|
|
}
|
|
|
|
// Add sections for non-empty groups
|
|
if ( newCategoryItems.length ) {
|
|
items.push( new ve.ui.MenuSectionItemWidget(
|
|
'newCategory', { '$$': menu$$, 'label': ve.msg( 'visualeditor-dialog-meta-categories-input-newcategorylabel' ) }
|
|
) );
|
|
for ( i = 0, len = newCategoryItems.length; i < len; i++ ) {
|
|
item = newCategoryItems[i];
|
|
items.push( new ve.ui.MenuItemWidget( item, { '$$': menu$$, 'label': item } ) );
|
|
}
|
|
}
|
|
if ( existingCategoryItems.length ) {
|
|
items.push( new ve.ui.MenuSectionItemWidget(
|
|
'inArticle', { '$$': menu$$, 'label': ve.msg( 'visualeditor-dialog-meta-categories-input-movecategorylabel' ) }
|
|
) );
|
|
for ( i = 0, len = existingCategoryItems.length; i < len; i++ ) {
|
|
item = existingCategoryItems[i];
|
|
items.push( new ve.ui.MenuItemWidget( item, { '$$': menu$$, 'label': item } ) );
|
|
}
|
|
}
|
|
if ( matchingCategoryItems.length ) {
|
|
items.push( new ve.ui.MenuSectionItemWidget(
|
|
'matchingCategories', { '$$': menu$$, 'label': ve.msg( 'visualeditor-dialog-meta-categories-input-matchingcategorieslabel' ) }
|
|
) );
|
|
for ( i = 0, len = matchingCategoryItems.length; i < len; i++ ) {
|
|
item = matchingCategoryItems[i];
|
|
items.push( new ve.ui.MenuItemWidget( item, { '$$': menu$$, 'label': item } ) );
|
|
}
|
|
}
|
|
|
|
return items;
|
|
};
|
|
|
|
/**
|
|
* Get a category item.
|
|
*
|
|
* @method
|
|
* @param {string} value Category name
|
|
* @returns {Object} Category item with name, value and metaItem properties
|
|
*/
|
|
ve.ui.MWCategoryInputWidget.prototype.getCategoryItemFromValue = function ( value ) {
|
|
var title;
|
|
|
|
// Normalize
|
|
try {
|
|
title = new mw.Title( this.categoryPrefix + value );
|
|
return {
|
|
'name': title.getPrefixedText(),
|
|
'value': title.getNameText(),
|
|
'metaItem': {}
|
|
};
|
|
} catch ( e ) { }
|
|
|
|
if ( this.forceCapitalization ) {
|
|
value = value.substr( 0, 1 ).toUpperCase() + value.substr( 1 );
|
|
}
|
|
|
|
return { 'name': this.categoryPrefix + value, 'value': value, 'metaItem': {} };
|
|
};
|