],
'mediawiki.widgets.CategoryMultiselectWidget' => [
'scripts' => [
- 'resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.CategoryTagItemWidget.js',
'resources/src/mediawiki.widgets/mw.widgets.CategoryMultiselectWidget.js',
],
'dependencies' => [
+++ /dev/null
-/*!
- * MediaWiki Widgets - CategoryCapsuleItemWidget class.
- *
- * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
- * @license The MIT License (MIT); see LICENSE.txt
- */
-( function ( $, mw ) {
-
- var hasOwn = Object.prototype.hasOwnProperty;
-
- /**
- * @class mw.widgets.PageExistenceCache
- * @private
- * @param {mw.Api} [api]
- */
- function PageExistenceCache( api ) {
- this.api = api || new mw.Api();
- this.processExistenceCheckQueueDebounced = OO.ui.debounce( this.processExistenceCheckQueue );
- this.currentRequest = null;
- this.existenceCache = {};
- this.existenceCheckQueue = {};
- }
-
- /**
- * Check for existence of pages in the queue.
- *
- * @private
- */
- PageExistenceCache.prototype.processExistenceCheckQueue = function () {
- var queue, titles,
- cache = this;
- if ( this.currentRequest ) {
- // Don't fire off a million requests at the same time
- this.currentRequest.always( function () {
- cache.currentRequest = null;
- cache.processExistenceCheckQueueDebounced();
- } );
- return;
- }
- queue = this.existenceCheckQueue;
- this.existenceCheckQueue = {};
- titles = Object.keys( queue ).filter( function ( title ) {
- if ( hasOwn.call( cache.existenceCache, title ) ) {
- queue[ title ].resolve( cache.existenceCache[ title ] );
- }
- return !hasOwn.call( cache.existenceCache, title );
- } );
- if ( !titles.length ) {
- return;
- }
- this.currentRequest = this.api.get( {
- formatversion: 2,
- action: 'query',
- prop: [ 'info' ],
- titles: titles
- } ).done( function ( response ) {
- var
- normalized = {},
- pages = {};
- $.each( response.query.normalized || [], function ( index, data ) {
- normalized[ data.fromencoded ? decodeURIComponent( data.from ) : data.from ] = data.to;
- } );
- $.each( response.query.pages, function ( index, page ) {
- pages[ page.title ] = !page.missing;
- } );
- titles.forEach( function ( title ) {
- var normalizedTitle = title;
- while ( hasOwn.call( normalized, normalizedTitle ) ) {
- normalizedTitle = normalized[ normalizedTitle ];
- }
- cache.existenceCache[ title ] = pages[ normalizedTitle ];
- queue[ title ].resolve( cache.existenceCache[ title ] );
- } );
- } );
- };
-
- /**
- * Register a request to check whether a page exists.
- *
- * @private
- * @param {mw.Title} title
- * @return {jQuery.Promise} Promise resolved with true if the page exists or false otherwise
- */
- PageExistenceCache.prototype.checkPageExistence = function ( title ) {
- var key = title.getPrefixedText();
- if ( !hasOwn.call( this.existenceCheckQueue, key ) ) {
- this.existenceCheckQueue[ key ] = $.Deferred();
- }
- this.processExistenceCheckQueueDebounced();
- return this.existenceCheckQueue[ key ].promise();
- };
-
- /**
- * @class mw.widgets.ForeignTitle
- * @private
- * @extends mw.Title
- *
- * @constructor
- * @param {string} title
- * @param {number} [namespace]
- */
- function ForeignTitle( title, namespace ) {
- // We only need to handle categories here... but we don't know the target language.
- // So assume that any namespace-like prefix is the 'Category' namespace...
- title = title.replace( /^(.+?)_*:_*(.*)$/, 'Category:$2' ); // HACK
- ForeignTitle.parent.call( this, title, namespace );
- }
- OO.inheritClass( ForeignTitle, mw.Title );
- ForeignTitle.prototype.getNamespacePrefix = function () {
- // We only need to handle categories here...
- return 'Category:'; // HACK
- };
-
- /**
- * Category selector capsule item widget. Extends OO.ui.CapsuleItemWidget with the ability to link
- * to the given page, and to show its existence status (i.e., whether it is a redlink).
- *
- * @class mw.widgets.CategoryCapsuleItemWidget
- * @uses mw.Api
- * @extends OO.ui.CapsuleItemWidget
- *
- * @constructor
- * @param {Object} config Configuration options
- * @cfg {mw.Title} title Page title to use (required)
- * @cfg {string} [apiUrl] API URL, if not the current wiki's API
- */
- mw.widgets.CategoryCapsuleItemWidget = function MWWCategoryCapsuleItemWidget( config ) {
- var widget = this;
- // Parent constructor
- mw.widgets.CategoryCapsuleItemWidget.parent.call( this, $.extend( {
- data: config.title.getMainText(),
- label: config.title.getMainText()
- }, config ) );
-
- // Properties
- this.title = config.title;
- this.apiUrl = config.apiUrl || '';
- this.$link = $( '<a>' )
- .text( this.label )
- .attr( 'target', '_blank' )
- .on( 'click', function ( e ) {
- // CapsuleMultiselectWidget really wants to prevent you from clicking the link, don't let it
- e.stopPropagation();
- } );
-
- // Initialize
- this.setMissing( false );
- this.$label.replaceWith( this.$link );
- this.setLabelElement( this.$link );
-
- if ( !this.constructor.static.pageExistenceCaches[ this.apiUrl ] ) {
- this.constructor.static.pageExistenceCaches[ this.apiUrl ] =
- new PageExistenceCache( new mw.ForeignApi( this.apiUrl ) );
- }
- this.constructor.static.pageExistenceCaches[ this.apiUrl ]
- .checkPageExistence( new ForeignTitle( this.title.getPrefixedText() ) )
- .done( function ( exists ) {
- widget.setMissing( !exists );
- } );
- };
-
- /* Setup */
-
- OO.inheritClass( mw.widgets.CategoryCapsuleItemWidget, OO.ui.CapsuleItemWidget );
-
- /* Static Properties */
-
- /**
- * Map of API URLs to PageExistenceCache objects.
- *
- * @static
- * @inheritable
- * @property {Object}
- */
- mw.widgets.CategoryCapsuleItemWidget.static.pageExistenceCaches = {
- '': new PageExistenceCache()
- };
-
- /* Methods */
-
- /**
- * Update label link href and CSS classes to reflect page existence status.
- *
- * @private
- * @param {boolean} missing Whether the page is missing (does not exist)
- */
- mw.widgets.CategoryCapsuleItemWidget.prototype.setMissing = function ( missing ) {
- var
- title = new ForeignTitle( this.title.getPrefixedText() ), // HACK
- prefix = this.apiUrl.replace( '/w/api.php', '' ); // HACK
-
- this.missing = missing;
-
- if ( !missing ) {
- this.$link
- .attr( 'href', prefix + title.getUrl() )
- .attr( 'title', title.getPrefixedText() )
- .removeClass( 'new' );
- } else {
- this.$link
- .attr( 'href', prefix + title.getUrl( { action: 'edit', redlink: 1 } ) )
- .attr( 'title', mw.msg( 'red-link-title', title.getPrefixedText() ) )
- .addClass( 'new' );
- }
- };
-
-}( jQuery, mediaWiki ) );
NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;
/**
- * Category selector widget. Displays an OO.ui.CapsuleMultiselectWidget
+ * Category selector widget. Displays an OO.ui.MenuTagMultiselectWidget
* and autocompletes with available categories.
*
* mw.loader.using( 'mediawiki.widgets.CategoryMultiselectWidget', function () {
*
* @class mw.widgets.CategoryMultiselectWidget
* @uses mw.Api
- * @extends OO.ui.CapsuleMultiselectWidget
+ * @extends OO.ui.MenuTagMultiselectWidget
* @mixins OO.ui.mixin.PendingElement
*
* @constructor
OO.ui.mixin.PendingElement.call( this, $.extend( {}, config, { $pending: this.$handle } ) );
// Event handler to call the autocomplete methods
- this.$input.on( 'change input cut paste', OO.ui.debounce( this.updateMenuItems.bind( this ), 100 ) );
+ this.input.$input.on( 'change input cut paste', OO.ui.debounce( this.updateMenuItems.bind( this ), 100 ) );
// Initialize
this.api = config.api || new mw.Api();
/* Setup */
- OO.inheritClass( mw.widgets.CategoryMultiselectWidget, OO.ui.CapsuleMultiselectWidget );
+ OO.inheritClass( mw.widgets.CategoryMultiselectWidget, OO.ui.MenuTagMultiselectWidget );
OO.mixinClass( mw.widgets.CategoryMultiselectWidget, OO.ui.mixin.PendingElement );
/* Methods */
*/
mw.widgets.CategoryMultiselectWidget.prototype.updateMenuItems = function () {
this.getMenu().clearItems();
- this.getNewMenuItems( this.$input.val() ).then( function ( items ) {
+ this.getNewMenuItems( this.input.$input.val() ).then( function ( items ) {
var existingItems, filteredItems,
menu = this.getMenu();
// Never show the menu if the input lost focus in the meantime
- if ( !this.$input.is( ':focus' ) ) {
+ if ( !this.input.$input.is( ':focus' ) ) {
return;
}
/**
* @inheritdoc
*/
- mw.widgets.CategoryMultiselectWidget.prototype.createItemWidget = function ( data ) {
+ mw.widgets.CategoryMultiselectWidget.prototype.createTagItemWidget = function ( data ) {
var title = mw.Title.makeTitle( NS_CATEGORY, data );
- if ( !title ) {
- return null;
- }
- return new mw.widgets.CategoryCapsuleItemWidget( {
+
+ return new mw.widgets.CategoryTagItemWidget( {
apiUrl: this.api.apiUrl || undefined,
title: title
} );
*/
mw.widgets.CategoryMultiselectWidget.prototype.findItemFromData = function ( data ) {
// This is a bit of a hack... We have to canonicalize the data in the same way that
- // #createItemWidget and CategoryCapsuleItemWidget will do, otherwise we won't find duplicates.
+ // #createItemWidget and CategoryTagItemWidget will do, otherwise we won't find duplicates.
var title = mw.Title.makeTitle( NS_CATEGORY, data );
if ( !title ) {
return null;
--- /dev/null
+/*!
+ * MediaWiki Widgets - CategoryTagItemWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ /**
+ * @class mw.widgets.PageExistenceCache
+ * @private
+ * @param {mw.Api} [api]
+ */
+ function PageExistenceCache( api ) {
+ this.api = api || new mw.Api();
+ this.processExistenceCheckQueueDebounced = OO.ui.debounce( this.processExistenceCheckQueue );
+ this.currentRequest = null;
+ this.existenceCache = {};
+ this.existenceCheckQueue = {};
+ }
+
+ /**
+ * Check for existence of pages in the queue.
+ *
+ * @private
+ */
+ PageExistenceCache.prototype.processExistenceCheckQueue = function () {
+ var queue, titles,
+ cache = this;
+ if ( this.currentRequest ) {
+ // Don't fire off a million requests at the same time
+ this.currentRequest.always( function () {
+ cache.currentRequest = null;
+ cache.processExistenceCheckQueueDebounced();
+ } );
+ return;
+ }
+ queue = this.existenceCheckQueue;
+ this.existenceCheckQueue = {};
+ titles = Object.keys( queue ).filter( function ( title ) {
+ if ( hasOwn.call( cache.existenceCache, title ) ) {
+ queue[ title ].resolve( cache.existenceCache[ title ] );
+ }
+ return !hasOwn.call( cache.existenceCache, title );
+ } );
+ if ( !titles.length ) {
+ return;
+ }
+ this.currentRequest = this.api.get( {
+ formatversion: 2,
+ action: 'query',
+ prop: [ 'info' ],
+ titles: titles
+ } ).done( function ( response ) {
+ var
+ normalized = {},
+ pages = {};
+ $.each( response.query.normalized || [], function ( index, data ) {
+ normalized[ data.fromencoded ? decodeURIComponent( data.from ) : data.from ] = data.to;
+ } );
+ $.each( response.query.pages, function ( index, page ) {
+ pages[ page.title ] = !page.missing;
+ } );
+ titles.forEach( function ( title ) {
+ var normalizedTitle = title;
+ while ( hasOwn.call( normalized, normalizedTitle ) ) {
+ normalizedTitle = normalized[ normalizedTitle ];
+ }
+ cache.existenceCache[ title ] = pages[ normalizedTitle ];
+ queue[ title ].resolve( cache.existenceCache[ title ] );
+ } );
+ } );
+ };
+
+ /**
+ * Register a request to check whether a page exists.
+ *
+ * @private
+ * @param {mw.Title} title
+ * @return {jQuery.Promise} Promise resolved with true if the page exists or false otherwise
+ */
+ PageExistenceCache.prototype.checkPageExistence = function ( title ) {
+ var key = title.getPrefixedText();
+ if ( !hasOwn.call( this.existenceCheckQueue, key ) ) {
+ this.existenceCheckQueue[ key ] = $.Deferred();
+ }
+ this.processExistenceCheckQueueDebounced();
+ return this.existenceCheckQueue[ key ].promise();
+ };
+
+ /**
+ * @class mw.widgets.ForeignTitle
+ * @private
+ * @extends mw.Title
+ *
+ * @constructor
+ * @param {string} title
+ * @param {number} [namespace]
+ */
+ function ForeignTitle( title, namespace ) {
+ // We only need to handle categories here... but we don't know the target language.
+ // So assume that any namespace-like prefix is the 'Category' namespace...
+ title = title.replace( /^(.+?)_*:_*(.*)$/, 'Category:$2' ); // HACK
+ ForeignTitle.parent.call( this, title, namespace );
+ }
+ OO.inheritClass( ForeignTitle, mw.Title );
+ ForeignTitle.prototype.getNamespacePrefix = function () {
+ // We only need to handle categories here...
+ return 'Category:'; // HACK
+ };
+
+ /**
+ * Category selector capsule item widget. Extends OO.ui.CapsuleItemWidget with the ability to link
+ * to the given page, and to show its existence status (i.e., whether it is a redlink).
+ *
+ * @class mw.widgets.CategoryTagItemWidget
+ * @uses mw.Api
+ * @extends OO.ui.TagItemWidget
+ *
+ * @constructor
+ * @param {Object} config Configuration options
+ * @cfg {mw.Title} title Page title to use (required)
+ * @cfg {string} [apiUrl] API URL, if not the current wiki's API
+ */
+ mw.widgets.CategoryTagItemWidget = function MWWCategoryTagItemWidget( config ) {
+ var widget = this;
+ // Parent constructor
+ mw.widgets.CategoryTagItemWidget.parent.call( this, $.extend( {
+ data: config.title.getMainText(),
+ label: config.title.getMainText()
+ }, config ) );
+
+ // Properties
+ this.title = config.title;
+ this.apiUrl = config.apiUrl || '';
+ this.$link = $( '<a>' )
+ .text( this.label )
+ .attr( 'target', '_blank' )
+ .on( 'click', function ( e ) {
+ // TagMultiselectWidget really wants to prevent you from clicking the link, don't let it
+ e.stopPropagation();
+ } );
+
+ // Initialize
+ this.setMissing( false );
+ this.$label.replaceWith( this.$link );
+ this.setLabelElement( this.$link );
+
+ if ( !this.constructor.static.pageExistenceCaches[ this.apiUrl ] ) {
+ this.constructor.static.pageExistenceCaches[ this.apiUrl ] =
+ new PageExistenceCache( new mw.ForeignApi( this.apiUrl ) );
+ }
+ this.constructor.static.pageExistenceCaches[ this.apiUrl ]
+ .checkPageExistence( new ForeignTitle( this.title.getPrefixedText() ) )
+ .done( function ( exists ) {
+ widget.setMissing( !exists );
+ } );
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.CategoryTagItemWidget, OO.ui.TagItemWidget );
+
+ /* Static Properties */
+
+ /**
+ * Map of API URLs to PageExistenceCache objects.
+ *
+ * @static
+ * @inheritable
+ * @property {Object}
+ */
+ mw.widgets.CategoryTagItemWidget.static.pageExistenceCaches = {
+ '': new PageExistenceCache()
+ };
+
+ /* Methods */
+
+ /**
+ * Update label link href and CSS classes to reflect page existence status.
+ *
+ * @private
+ * @param {boolean} missing Whether the page is missing (does not exist)
+ */
+ mw.widgets.CategoryTagItemWidget.prototype.setMissing = function ( missing ) {
+ var
+ title = new ForeignTitle( this.title.getPrefixedText() ), // HACK
+ prefix = this.apiUrl.replace( '/w/api.php', '' ); // HACK
+
+ this.missing = missing;
+
+ if ( !missing ) {
+ this.$link
+ .attr( 'href', prefix + title.getUrl() )
+ .attr( 'title', title.getPrefixedText() )
+ .removeClass( 'new' );
+ } else {
+ this.$link
+ .attr( 'href', prefix + title.getUrl( { action: 'edit', redlink: 1 } ) )
+ .attr( 'title', mw.msg( 'red-link-title', title.getPrefixedText() ) )
+ .addClass( 'new' );
+ }
+ };
+
+ // For backwards compatibility. See T183299.
+ mw.widgets.CategoryCapsuleItemWidget = mw.widgets.CategoryTagItemWidget;
+}( jQuery, mediaWiki ) );