mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/WikiEditor
synced 2024-11-24 08:14:33 +00:00
d96435cd18
* When the link target text is changed, only change the URL mode if the user hasn't explicitely set the type (internal/external). * Improve the conditions for the display of the 'external' and 'exists' link-target messages. * Validate the link target (i.e. show messages) not only when the text is changed but also when the target type radio is changed. * Rename the TitleInputWidget.isExternalLink() method to looksLikeExternalLink(), to make its purpose clearer. Bug: T293168 Change-Id: Ie40e8bdebe6f1330fc75ea1861f120e51ad58224
157 lines
4.7 KiB
JavaScript
157 lines
4.7 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.
|
|
var $overlay = OO.ui.getDefaultOverlay()
|
|
.clone()
|
|
.css( 'z-index', '1010' );
|
|
$( document.body ).append( $overlay );
|
|
return $overlay;
|
|
};
|
|
|
|
/**
|
|
* 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 ) {
|
|
var matches = urlString.match( this.constructor.static.urlRegex );
|
|
return matches !== null && matches.length > 0;
|
|
};
|
|
|
|
module.exports = TitleInputWidget;
|