"apihelp-imagerotate-example-simple": "Rotate <kbd>File:Example.png</kbd> by <kbd>90</kbd> degrees.",
"apihelp-imagerotate-example-generator": "Rotate all images in <kbd>Category:Flip</kbd> by <kbd>180</kbd> degrees.",
- "apihelp-import-description": "Import a page from another wiki, or an XML file.\n\nNote that the HTTP POST must be done as a file upload (i.e. using multipart/form-data) when sending a file for the <var>xml</var> parameter.",
+ "apihelp-import-description": "Import a page from another wiki, or from an XML file.\n\nNote that the HTTP POST must be done as a file upload (i.e. using multipart/form-data) when sending a file for the <var>xml</var> parameter.",
"apihelp-import-param-summary": "Import summary.",
"apihelp-import-param-xml": "Uploaded XML file.",
"apihelp-import-param-interwikisource": "For interwiki imports: wiki to import from.",
return isset( $this->mParams['rows'] ) ? $this->mParams['rows'] : static::DEFAULT_ROWS;
}
+ function getSpellCheck() {
+ $val = isset( $this->mParams['spellcheck'] ) ? $this->mParams['spellcheck'] : null;
+ if( is_bool( $val ) ) {
+ // "spellcheck" attribute literally requires "true" or "false" to work.
+ return $val === true ? 'true' : 'false';
+ }
+ return null;
+ }
+
function getInputHTML( $value ) {
$attribs = array(
'id' => $this->mID,
'cols' => $this->getCols(),
'rows' => $this->getRows(),
+ 'spellcheck' => $this->getSpellCheck(),
) + $this->getTooltipAndAccessKey();
if ( $this->mClass !== '' ) {
return isset( $this->mParams['size'] ) ? $this->mParams['size'] : 45;
}
+ function getSpellCheck() {
+ $val = isset( $this->mParams['spellcheck'] ) ? $this->mParams['spellcheck'] : null;
+ if( is_bool( $val ) ) {
+ // "spellcheck" attribute literally requires "true" or "false" to work.
+ return $val === true ? 'true' : 'false';
+ }
+ return null;
+ }
+
function getInputHTML( $value ) {
$attribs = array(
'id' => $this->mID,
'size' => $this->getSize(),
'value' => $value,
'dir' => $this->mDir,
+ 'spellcheck' => $this->getSpellCheck(),
) + $this->getTooltipAndAccessKey();
if ( $this->mClass !== '' ) {
if ( $user->isAllowed( 'suppressrevision' ) ) {
$suppress = Html::openElement( 'div', array( 'id' => 'wpDeleteSuppressRow' ) ) .
- "<strong>" .
- Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
- 'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '4' ) ) .
- "</strong>" .
+ Xml::checkLabel( wfMessage( 'revdelete-suppress' )->text(),
+ 'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '4' ) ) .
Html::closeElement( 'div' );
} else {
$suppress = '';
}
/**
- * Write out all known classes to autoload.php in
- * the provided basedir
+ * Updates the AutoloadClasses field at the given
+ * filename.
*
- * @param string $commandName Value used in file comment to direct
- * developers towards the appropriate way to update the autoload.
+ * @param {string} $filename Filename of JSON
+ * extension/skin registration file
*/
- public function generateAutoload( $commandName = 'AutoloadGenerator' ) {
-
- // We need to check whether an extenson.json exists or not, and
- // incase it doesn't, update the autoload.php file.
-
- if ( file_exists( $this->basepath . '/extension.json' ) ) {
- require_once __DIR__ . '/../../includes/json/FormatJson.php';
- $key = 'AutoloadClasses';
- $json = FormatJson::decode( file_get_contents( $this->basepath
- . '/extension.json' ), true );
- unset( $json[$key] );
- // Inverting the key-value pairs so that they become of the
- // format class-name : path when they get converted into json.
- foreach ( $this->classes as $path => $contained ) {
- foreach ( $contained as $fqcn ) {
-
- // Using substr to remove the leading '/'
- $json[$key][$fqcn] = substr( $path, 1 );
- }
- }
- foreach ( $this->overrides as $path => $fqcn ) {
+ protected function generateJsonAutoload( $filename ) {
+ require_once __DIR__ . '/../../includes/json/FormatJson.php';
+ $key = 'AutoloadClasses';
+ $json = FormatJson::decode( file_get_contents( $filename ), true );
+ unset( $json[$key] );
+ // Inverting the key-value pairs so that they become of the
+ // format class-name : path when they get converted into json.
+ foreach ( $this->classes as $path => $contained ) {
+ foreach ( $contained as $fqcn ) {
// Using substr to remove the leading '/'
$json[$key][$fqcn] = substr( $path, 1 );
}
+ }
+ foreach ( $this->overrides as $path => $fqcn ) {
- // Sorting the list of autoload classes.
- ksort( $json[$key] );
+ // Using substr to remove the leading '/'
+ $json[$key][$fqcn] = substr( $path, 1 );
+ }
- // Update extension.json, using constants for the required
- // formatting.
- file_put_contents( $this->basepath . '/extension.json',
- FormatJson::encode( $json, true ) . "\n" );
- } else {
- $content = array();
-
- // We need to generate a line each rather than exporting the
- // full array so __DIR__ can be prepended to all the paths
- $format = "%s => __DIR__ . %s,";
- foreach ( $this->classes as $path => $contained ) {
- $exportedPath = var_export( $path, true );
- foreach ( $contained as $fqcn ) {
- $content[$fqcn] = sprintf(
- $format,
- var_export( $fqcn, true ),
- $exportedPath
- );
- }
- }
+ // Sorting the list of autoload classes.
+ ksort( $json[$key] );
- foreach ( $this->overrides as $fqcn => $path ) {
+ // Update file, using constants for the required
+ // formatting.
+ file_put_contents( $filename,
+ FormatJson::encode( $json, true ) . "\n" );
+ }
+
+ /**
+ * Generates a PHP file setting up autoload information.
+ *
+ * @param {string} $commandName Command name to include in comment
+ * @param {string} $filename of PHP file to put autoload information in.
+ */
+ protected function generatePHPAutoload( $commandName, $filename ) {
+ // No existing JSON file found; update/generate PHP file
+ $content = array();
+
+ // We need to generate a line each rather than exporting the
+ // full array so __DIR__ can be prepended to all the paths
+ $format = "%s => __DIR__ . %s,";
+ foreach ( $this->classes as $path => $contained ) {
+ $exportedPath = var_export( $path, true );
+ foreach ( $contained as $fqcn ) {
$content[$fqcn] = sprintf(
$format,
var_export( $fqcn, true ),
- var_export( $path, true )
+ $exportedPath
);
}
+ }
- // sort for stable output
- ksort( $content );
+ foreach ( $this->overrides as $fqcn => $path ) {
+ $content[$fqcn] = sprintf(
+ $format,
+ var_export( $fqcn, true ),
+ var_export( $path, true )
+ );
+ }
- // extensions using this generator are appending to the existing
- // autoload.
- if ( $this->variableName === 'wgAutoloadClasses' ) {
- $op = '+=';
- } else {
- $op = '=';
- }
+ // sort for stable output
+ ksort( $content );
+
+ // extensions using this generator are appending to the existing
+ // autoload.
+ if ( $this->variableName === 'wgAutoloadClasses' ) {
+ $op = '+=';
+ } else {
+ $op = '=';
+ }
- $output = implode( "\n\t", $content );
- file_put_contents(
- $this->basepath . '/autoload.php',
- <<<EOD
+ $output = implode( "\n\t", $content );
+ file_put_contents(
+ $filename,
+ <<<EOD
<?php
// This file is generated by $commandName, do not adjust manually
// @codingStandardsIgnoreFile
);
EOD
- );
+ );
+
+ }
+
+ /**
+ * Write out all known classes to autoload.php, extension.json, or skin.json in
+ * the provided basedir
+ *
+ * @param string $commandName Value used in file comment to direct
+ * developers towards the appropriate way to update the autoload.
+ */
+ public function generateAutoload( $commandName = 'AutoloadGenerator' ) {
+
+ // We need to check whether an extenson.json or skin.json exists or not, and
+ // incase it doesn't, update the autoload.php file.
+
+ $jsonFilename = null;
+ if ( file_exists( $this->basepath . "/extension.json" ) ) {
+ $jsonFilename = $this->basepath . "/extension.json";
+ } elseif ( file_exists( $this->basepath . "/skin.json" ) ) {
+ $jsonFilename = $this->basepath . "/skin.json";
+ }
+
+ if ( $jsonFilename !== null ) {
+ $this->generateJsonAutoload( $jsonFilename );
+ } else {
+ $this->generatePHPAutoload( $commandName, $this->basepath . '/autoload.php' );
}
}
/**
"special-characters-group-khmer": "Khmer",
"special-characters-title-endash": "en dash",
"special-characters-title-emdash": "em dash",
- "special-characters-title-minus": "minus sign"
+ "special-characters-title-minus": "minus sign",
+ "mw-widgets-titleinput-description-new-page": "page does not exist yet",
+ "mw-widgets-titleinput-description-redirect": "redirect to $1"
}
"special-characters-group-khmer": "{{Identical|Khmer}}",
"special-characters-title-endash": "Title tooltip for the en dash character (–); See https://en.wikipedia.org/wiki/Dash",
"special-characters-title-emdash": "Title tooltip for the em dash character (—); See https://en.wikipedia.org/wiki/Dash",
- "special-characters-title-minus": "Title tooltip for the minus sign character (−), not to be confused with a hyphen"
+ "special-characters-title-minus": "Title tooltip for the minus sign character (−), not to be confused with a hyphen",
+ "mw-widgets-titleinput-description-new-page": "Description label for a new page in the title input widget.",
+ "mw-widgets-titleinput-description-redirect": "Description label for a redirect in the title input widget."
}
'scripts' => array(
'resources/src/mediawiki.widgets/mw.widgets.js',
'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js',
),
'skinStyles' => array(
'default' => 'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css',
'oojs-ui',
),
'messages' => array(
- // …
+ 'mw-widgets-titleinput-description-new-page',
+ 'mw-widgets-titleinput-description-redirect',
),
'targets' => array( 'desktop', 'mobile' ),
),
background-color: #f9f9f9;
border: 1px solid #ddd;
padding: 1em;
+ /* @noflip */
+ direction: ltr;
+ unicode-bidi: embed;
+ /* Wrap lines in overflow. T103780 */
+ white-space: pre-wrap;
}
/* Tables */
/*!
- * MediaWiki Widgets – TitleInputWidget styles.
+ * MediaWiki Widgets - TitleInputWidget styles.
*
* @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
-.mw-widget-TitleInputWidget {
- width: 30em;
+.mw-widget-titleInputWidget-menu-withImages .mw-widget-titleOptionWidget {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ min-height: 3.75em;
+ margin-left: 3.75em;
+}
+
+.mw-widget-titleInputWidget-menu-withImages .mw-widget-titleOptionWidget:not(:last-child) {
+ margin-bottom: 1px;
+}
+
+.mw-widget-titleInputWidget-menu-withImages .oo-ui-iconElement .oo-ui-iconElement-icon {
+ display: block;
+ width: 3.75em;
+ height: 3.75em;
+ left: -3.75em;
+ background-color: #ccc;
+ opacity: 0.4;
+}
+
+.mw-widget-titleInputWidget-menu-withImages .oo-ui-iconElement .mw-widget-titleOptionWidget-hasImage {
+ border: 0;
+ background-size: cover;
+ opacity: 1;
+}
+
+.mw-widget-titleInputWidget-menu-withImages .mw-widget-titleOptionWidget .oo-ui-labelElement-label {
+ line-height: 2.8em;
+}
+
+.mw-widget-titleOptionWidget-description {
+ display: none;
+}
+
+.mw-widget-titleInputWidget-menu-withDescriptions .mw-widget-titleOptionWidget .oo-ui-labelElement-label {
+ line-height: 1.5em;
+}
+
+.mw-widget-titleInputWidget-menu-withDescriptions .mw-widget-titleOptionWidget-description {
+ display: block;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+.oo-ui-menuOptionWidget:not(.oo-ui-optionWidget-selected) .mw-widget-titleOptionWidget-description,
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted .mw-widget-titleOptionWidget-description {
+ color: #888;
}
/*!
- * MediaWiki Widgets – TitleInputWidget class.
+ * MediaWiki Widgets - TitleInputWidget class.
*
* @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {number} [limit=10] Number of results to show
* @cfg {number} [namespace] Namespace to prepend to queries
+ * @cfg {boolean} [showRedirectTargets=true] Show the targets of redirects
+ * @cfg {boolean} [showRedlink] Show red link to exact match if it doesn't exist
+ * @cfg {boolean} [showImages] Show page images
+ * @cfg {boolean} [showDescriptions] Show page descriptions
+ * @cfg {Object} [cache] Result cache which implements a 'set' method, taking keyed values as an argument
*/
- mw.widgets.TitleInputWidget = function MWWTitleInputWidget( config ) {
+ mw.widgets.TitleInputWidget = function MwWidgetsTitleInputWidget( config ) {
+ var widget = this;
+
// Config initialization
config = config || {};
OO.ui.mixin.LookupElement.call( this, config );
// Properties
+ this.limit = config.limit || 10;
this.namespace = config.namespace || null;
+ this.showRedirectTargets = config.showRedirectTargets !== false;
+ this.showRedlink = !!config.showRedlink;
+ this.showImages = !!config.showImages;
+ this.showDescriptions = !!config.showDescriptions;
+ this.cache = config.cache;
// Initialization
- this.$element.addClass( 'mw-widget-TitleInputWidget' );
- this.lookupMenu.$element.addClass( 'mw-widget-TitleInputWidget-menu' );
+ this.$element.addClass( 'mw-widget-titleInputWidget' );
+ this.lookupMenu.$element.addClass( 'mw-widget-titleInputWidget-menu' );
+ if ( this.showImages ) {
+ this.lookupMenu.$element.addClass( 'mw-widget-titleInputWidget-menu-withImages' );
+ }
+ if ( this.showDescriptions ) {
+ this.lookupMenu.$element.addClass( 'mw-widget-titleInputWidget-menu-withDescriptions' );
+ }
+
+ this.interwikiPrefixes = [];
+ this.interwikiPrefixesPromise = new mw.Api().get( {
+ action: 'query',
+ meta: 'siteinfo',
+ siprop: 'interwikimap'
+ } ).done( function ( data ) {
+ $.each( data.query.interwikimap, function ( index, interwiki ) {
+ widget.interwikiPrefixes.push( interwiki.prefix );
+ } );
+ } );
};
/* Inheritance */
/**
* @inheritdoc
*/
- mw.widgets.TitleInputWidget.prototype.getLookupRequest = function () {
- var value = this.value;
+ mw.widgets.TitleInputWidget.prototype.focus = function () {
+ var retval;
- // Prefix with default namespace name
- if ( this.namespace !== null && mw.Title.newFromText( value, this.namespace ) ) {
- value = mw.Title.newFromText( value, this.namespace ).getPrefixedText();
- }
+ // Prevent programmatic focus from opening the menu
+ this.setLookupsDisabled( true );
- // Dont send leading ':' to open search
- if ( value[0] === ':' ) {
- value = value.slice( 1 );
- }
+ // Parent method
+ retval = OO.ui.TextInputWidget.prototype.focus.apply( this, arguments );
- return new mw.Api().get( {
- action: 'opensearch',
- search: value,
- suggest: ''
- } );
+ this.setLookupsDisabled( false );
+
+ return retval;
};
/**
* @inheritdoc
*/
+ mw.widgets.TitleInputWidget.prototype.getLookupRequest = function () {
+ var req,
+ widget = this,
+ promiseAbortObject = { abort: function () {
+ // Do nothing. This is just so OOUI doesn't break due to abort being undefined.
+ } };
+
+ if ( mw.Title.newFromText( this.value ) ) {
+ return this.interwikiPrefixesPromise.then( function () {
+ var params, props,
+ interwiki = widget.value.substring( 0, widget.value.indexOf( ':' ) );
+ if (
+ interwiki && interwiki !== '' &&
+ widget.interwikiPrefixes.indexOf( interwiki ) !== -1
+ ) {
+ return $.Deferred().resolve( { query: {
+ pages: [{
+ title: widget.value
+ }]
+ } } ).promise( promiseAbortObject );
+ } else {
+ params = {
+ action: 'query',
+ generator: 'prefixsearch',
+ gpssearch: widget.value,
+ gpsnamespace: widget.namespace !== null ? widget.namespace : undefined,
+ gpslimit: widget.limit,
+ ppprop: 'disambiguation'
+ };
+ props = [ 'info', 'pageprops' ];
+ if ( widget.showRedirectTargets ) {
+ params.redirects = '1';
+ }
+ if ( widget.showImages ) {
+ props.push( 'pageimages' );
+ params.pithumbsize = 80;
+ params.pilimit = widget.limit;
+ }
+ if ( widget.showDescriptions ) {
+ props.push( 'pageterms' );
+ params.wbptterms = 'description';
+ }
+ params.prop = props.join( '|' );
+ req = new mw.Api().get( params );
+ promiseAbortObject.abort = req.abort.bind( req ); // todo: ew
+ return req;
+ }
+ } ).promise( promiseAbortObject );
+ } else {
+ // Don't send invalid titles to the API.
+ // Just pretend it returned nothing so we can show the 'invalid title' section
+ return $.Deferred().resolve( {} ).promise( promiseAbortObject );
+ }
+ };
+
+ /**
+ * Get lookup cache item from server response data.
+ *
+ * @method
+ * @param {Mixed} data Response from server
+ */
mw.widgets.TitleInputWidget.prototype.getLookupCacheDataFromResponse = function ( data ) {
- return data[1] || [];
+ return data.query || {};
};
/**
- * @inheritdoc
+ * Get list of menu items from a server response.
+ *
+ * @param {Object} data Query result
+ * @returns {OO.ui.MenuOptionWidget[]} Menu items
*/
mw.widgets.TitleInputWidget.prototype.getLookupMenuOptionsFromData = function ( data ) {
- var i, len, title, value,
+ var i, len, index, pageExists, pageExistsExact, suggestionPage, page, redirect, redirects,
items = [],
- matchingPages = data;
-
- // Matching pages
- if ( matchingPages && matchingPages.length ) {
- for ( i = 0, len = matchingPages.length; i < len; i++ ) {
- title = new mw.Title( matchingPages[i] );
- if ( this.namespace !== null ) {
- value = title.getRelativeText( this.namespace );
- } else {
- value = title.getPrefixedText();
- }
- items.push( new OO.ui.MenuOptionWidget( {
- data: value,
- label: value
- } ) );
+ titles = [],
+ titleObj = mw.Title.newFromText( this.value ),
+ redirectsTo = {},
+ pageData = {};
+
+ if ( data.redirects ) {
+ for ( i = 0, len = data.redirects.length; i < len; i++ ) {
+ redirect = data.redirects[i];
+ redirectsTo[redirect.to] = redirectsTo[redirect.to] || [];
+ redirectsTo[redirect.to].push( redirect.from );
+ }
+ }
+
+ for ( index in data.pages ) {
+ suggestionPage = data.pages[index];
+ pageData[suggestionPage.title] = {
+ missing: suggestionPage.missing !== undefined,
+ redirect: suggestionPage.redirect !== undefined,
+ disambiguation: OO.getProp( suggestionPage, 'pageprops', 'disambiguation' ) !== undefined,
+ imageUrl: OO.getProp( suggestionPage, 'thumbnail', 'source' ),
+ description: OO.getProp( suggestionPage, 'terms', 'description' )
+ };
+ titles.push( suggestionPage.title );
+
+ redirects = redirectsTo[suggestionPage.title] || [];
+ for ( i = 0, len = redirects.length; i < len; i++ ) {
+ pageData[redirects[i]] = {
+ missing: false,
+ redirect: true,
+ disambiguation: false,
+ description: mw.msg( 'mw-widgets-titleinput-description-redirect', suggestionPage.title )
+ };
+ titles.push( redirects[i] );
}
}
+ // If not found, run value through mw.Title to avoid treating a match as a
+ // mismatch where normalisation would make them matching (bug 48476)
+
+ pageExistsExact = titles.indexOf( this.value ) !== -1;
+ pageExists = pageExistsExact || (
+ titleObj && titles.indexOf( titleObj.getPrefixedText() ) !== -1
+ );
+
+ if ( !pageExists ) {
+ pageData[this.value] = {
+ missing: true, redirect: false, disambiguation: false,
+ description: mw.msg( 'mw-widgets-titleinput-description-new-page' )
+ };
+ }
+
+ if ( this.cache ) {
+ this.cache.set( pageData );
+ }
+
+ // Offer the exact text as a suggestion if the page exists
+ if ( pageExists && !pageExistsExact ) {
+ titles.unshift( this.value );
+ }
+ // Offer the exact text as a new page if the title is valid
+ if ( this.showRedlink && !pageExists && titleObj ) {
+ titles.push( this.value );
+ }
+ for ( i = 0, len = titles.length; i < len; i++ ) {
+ page = pageData[titles[i]] || {};
+ items.push( new mw.widgets.TitleOptionWidget( this.getOptionWidgetData( titles[i], page ) ) );
+ }
+
return items;
};
+ /**
+ * Get menu option widget data from the title and page data
+ *
+ * @param {mw.Title} title Title object
+ * @param {Object} data Page data
+ * @return {Object} Data for option widget
+ */
+ mw.widgets.TitleInputWidget.prototype.getOptionWidgetData = function ( title, data ) {
+ var mwTitle = new mw.Title( title );
+ return {
+ data: this.namespace !== null ? mwTitle.getRelativeText( this.namespace ) : title,
+ imageUrl: this.showImages ? data.imageUrl : null,
+ description: this.showDescriptions ? data.description : null,
+ missing: data.missing,
+ redirect: data.redirect,
+ disambiguation: data.disambiguation,
+ query: this.value
+ };
+ };
+
/**
* Get title object corresponding to #getValue
*
--- /dev/null
+/*!
+ * MediaWiki Widgets - TitleOptionWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * Creates a mw.widgets.TitleOptionWidget object.
+ *
+ * @class
+ * @extends OO.ui.MenuOptionWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [data] Page title
+ * @cfg {string} [imageUrl] Thumbnail image URL with URL encoding
+ * @cfg {string} [description] Page description
+ * @cfg {boolean} [missing] Page doesn't exist
+ * @cfg {boolean} [redirect] Page is a redirect
+ * @cfg {boolean} [disambiguation] Page is a disambiguation page
+ * @cfg {string} [query] Matching query string
+ */
+ mw.widgets.TitleOptionWidget = function MwWidgetsTitleOptionWidget( config ) {
+ var icon, title = config.data;
+
+ if ( config.missing ) {
+ icon = 'page-not-found';
+ } else if ( config.redirect ) {
+ icon = 'page-redirect';
+ } else if ( config.disambiguation ) {
+ icon = 'page-disambiguation';
+ } else {
+ icon = 'page-existing';
+ }
+
+ // Config initialization
+ config = $.extend( {
+ icon: icon,
+ label: title,
+ href: mw.util.getUrl( title ),
+ autoFitLabel: false
+ }, config );
+
+ // Parent constructor
+ OO.ui.MenuOptionWidget.call( this, config );
+
+ // Intialization
+ this.$label.wrap( '<a>' );
+ this.$link = this.$label.parent();
+ this.$link.attr( 'href', config.href );
+ this.$element.addClass( 'mw-widget-titleOptionWidget' );
+
+ // Highlight matching parts of link suggestion
+ this.$label.autoEllipsis( { hasSpan: false, tooltip: true, matchText: config.query } );
+
+ if ( config.missing ) {
+ this.$link.addClass( 'new' );
+ }
+
+ if ( config.imageUrl ) {
+ this.$icon
+ .addClass( 'mw-widget-titleOptionWidget-hasImage' )
+ .css( 'background-image', 'url(' + config.imageUrl + ')' );
+ }
+
+ if ( config.description ) {
+ this.$element.append(
+ $( '<span>' )
+ .addClass( 'mw-widget-titleOptionWidget-description' )
+ .text( config.description )
+ );
+ }
+ };
+
+ /* Inheritance */
+
+ OO.inheritClass( mw.widgets.TitleOptionWidget, OO.ui.MenuOptionWidget );
+
+}( jQuery, mediaWiki ) );
'ResourceLoader', 't-rl', 'More info about ResourceLoader on MediaWiki.org ', 'l'
);
- assert.ok( $.isDomElement( tbRL ), 'addPortletLink returns a valid DOM Element according to $.isDomElement' );
+ assert.ok( tbRL && tbRL.nodeType, 'addPortletLink returns a DOM Node' );
tbMW = mw.util.addPortletLink( 'p-test-tb', '//mediawiki.org/',
'MediaWiki.org', 't-mworg', 'Go to MediaWiki.org', 'm', tbRL );