mediawiki-extensions-WikiEd.../modules/insertlink/TitleInputWidget.js
Thiemo Kreuz dbb6583bbb Streamline smaller pieces of JavaScript code
The main idea is to make the code shorter and easier to read.

One notable change is to use .test() for boolean tests instead of the
actual .match() function.

Change-Id: Ic43442b75f839906b644d4586c907601f4d5d521
2022-03-04 09:22:07 +00:00

155 lines
4.6 KiB
JavaScript

var InsertLinkTitleOptionWidget = require( './TitleOptionWidget.js' );
/**
* A custom TitleInputWidget that adds support for external links
* (any string that starts with a protocol or `www.` and doesn't exist as a page).
*
* @class
* @extends mw.widgets.TitleInputWidget
* @constructor
*/
function TitleInputWidget() {
TitleInputWidget.parent.call( this, {
showImages: true,
showDescriptions: true,
showDisambigsLast: true,
placeholder: mw.msg( 'wikieditor-toolbar-tool-link-int-target-tooltip' ),
$overlay: this.getOverlay(),
validateTitle: false,
showInterwikis: true,
required: true,
addQueryInput: true
} );
}
OO.inheritClass( TitleInputWidget, mw.widgets.TitleInputWidget );
/**
* Regular expression for determining what might be an external link.
*
* @static
* @property {RegExp}
*/
TitleInputWidget.static.urlRegex = new RegExp( '^(' + mw.config.get( 'wgUrlProtocols' ) + '|www\\.)', 'i' );
/**
* When leaving the input without selecting a menu item,
* automatically select a matching item if there is one.
* Even though we specify addQueryInput=true in the config, the entered string
* is not always available to be selected. See T291056.
*/
TitleInputWidget.prototype.onLookupInputBlur = function () {
TitleInputWidget.parent.prototype.onLookupInputBlur.apply( this );
this.selectFirstMatch();
};
/**
* Select the first matching search result
* The first match might not be at the top of the list, nor an exact match.
*
* @public
*/
TitleInputWidget.prototype.selectFirstMatch = function () {
var that = this;
this.getLookupMenuItems().done( function ( items ) {
// The matching item is not always the first,
// because disambiguation pages are moved to the end.
for ( var i = 0; i < items.length; i++ ) {
var item = items[ i ];
var queryVal = that.getQueryValue();
// Check for exact match, or a match with uppercase first character.
if ( item.getData() === queryVal ||
item.getData() === queryVal.charAt( 0 ).toUpperCase() + queryVal.slice( 1 )
) {
// If a matching title is is found, fire an event and stop looking.
that.emit( 'select', item );
break;
}
}
} );
};
/**
* Get menu option widget data from the title and page data,
* adding an `external` property.
*
* @param {string} title Page title
* @param {Object} data Page data
* @return {Object} Data for option widget
*/
TitleInputWidget.prototype.getOptionWidgetData = function ( title, data ) {
var widgetData = TitleInputWidget.parent.prototype.getOptionWidgetData.call( this, title, data );
widgetData.external = data.originalData.external;
return widgetData;
};
/**
* Create a InsertLinkTitleOptionWidget.
*
* @param {Object} data Data for option widget
* @return {OO.ui.MenuOptionWidget} The option widget
*/
TitleInputWidget.prototype.createOptionWidget = function ( data ) {
return new InsertLinkTitleOptionWidget( data );
};
/**
* Get pages' data from the API response, adding an `external` property for
* pages that do not exist and which look like external URLs.
*
* @param {Object} response
* @return {Object}
*/
TitleInputWidget.prototype.getLookupCacheDataFromResponse = function ( response ) {
var res = TitleInputWidget.parent.prototype.getLookupCacheDataFromResponse( response );
// Guard against zero responses.
if ( res.pages === undefined ) {
return res;
}
for ( var pageId in res.pages ) {
if ( Object.prototype.hasOwnProperty.call( res.pages, pageId ) ) {
var page = res.pages[ pageId ];
page.external = page.missing !== undefined && this.looksLikeExternalLink( page.title );
}
}
return res;
};
/**
* Handle menu item 'choose' event, updating the text input value to the value of the clicked item.
*
* @param {OO.ui.MenuOptionWidget} item Selected item
*/
TitleInputWidget.prototype.onLookupMenuChoose = function ( item ) {
TitleInputWidget.parent.prototype.onLookupMenuChoose.call( this, item );
this.emit( 'select', item );
};
/**
* Get a custom overlay for the dropdown menu, so it's not contained within the jQuery UI dialog.
*
* @private
* @return {jQuery}
*/
TitleInputWidget.prototype.getOverlay = function () {
// Overlay z-index must be greater than the jQuery UI dialog's of 1002.
return OO.ui.getDefaultOverlay()
.clone()
.css( 'z-index', '1010' )
.appendTo( document.body );
};
/**
* Determine if a given string is likely to be an external URL.
* External URLs start with either a valid protocol (from $wgUrlProtocols) or `www.`.
*
* @public
* @param {string} urlString The possible URL.
* @return {boolean}
*/
TitleInputWidget.prototype.looksLikeExternalLink = function ( urlString ) {
this.constructor.static.urlRegex.test( urlString );
};
module.exports = TitleInputWidget;