mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-29 00:30:44 +00:00
d8d3a8c98e
It can be very slow on pages with lots of references and isn't required until you click 'Use existing reference'. What is required is knowing if the list will be empty for greying out the button, but that can be precomputed very cheaply. Change-Id: I56909801a5685bb04e0c83cfb95463f705b8dfae
216 lines
5.4 KiB
JavaScript
216 lines
5.4 KiB
JavaScript
/*!
|
|
* VisualEditor UserInterface MWReferenceSearchWidget class.
|
|
*
|
|
* @copyright 2011-2014 VisualEditor Team and others; see AUTHORS.txt
|
|
* @license The MIT License (MIT); see LICENSE.txt
|
|
*/
|
|
|
|
/**
|
|
* Creates an ve.ui.MWReferenceSearchWidget object.
|
|
*
|
|
* @class
|
|
* @extends OO.ui.SearchWidget
|
|
*
|
|
* @constructor
|
|
* @param {Object} [config] Configuration options
|
|
*/
|
|
ve.ui.MWReferenceSearchWidget = function VeUiMWReferenceSearchWidget( config ) {
|
|
// Configuration intialization
|
|
config = ve.extendObject( {
|
|
'placeholder': ve.msg( 'visualeditor-reference-input-placeholder' )
|
|
}, config );
|
|
|
|
// Parent constructor
|
|
OO.ui.SearchWidget.call( this, config );
|
|
|
|
// Properties
|
|
this.index = [];
|
|
this.indexEmpty = true;
|
|
this.built = false;
|
|
|
|
// Initialization
|
|
this.$element.addClass( 've-ui-mwReferenceSearchWidget' );
|
|
};
|
|
|
|
/* Inheritance */
|
|
|
|
OO.inheritClass( ve.ui.MWReferenceSearchWidget, OO.ui.SearchWidget );
|
|
|
|
/* Events */
|
|
|
|
/**
|
|
* @event select
|
|
* @param {ve.dm.MWReferenceModel|null} data Reference model, null if no item is selected
|
|
*/
|
|
|
|
/* Methods */
|
|
|
|
/**
|
|
* Handle query change events.
|
|
*
|
|
* @method
|
|
* @param {string} value New value
|
|
*/
|
|
ve.ui.MWReferenceSearchWidget.prototype.onQueryChange = function () {
|
|
// Parent method
|
|
OO.ui.SearchWidget.prototype.onQueryChange.call( this );
|
|
|
|
// Populate
|
|
this.addResults();
|
|
};
|
|
|
|
/**
|
|
* Handle select widget select events.
|
|
*
|
|
* @method
|
|
* @param {OO.ui.OptionWidget} item Selected item
|
|
* @fires select
|
|
*/
|
|
ve.ui.MWReferenceSearchWidget.prototype.onResultsSelect = function ( item ) {
|
|
var data;
|
|
|
|
if ( item ) {
|
|
data = item.getData();
|
|
// Resolve indexed values
|
|
if ( this.index[data] ) {
|
|
data = this.index[data].reference;
|
|
}
|
|
} else {
|
|
data = null;
|
|
}
|
|
|
|
this.emit( 'select', data );
|
|
};
|
|
|
|
/**
|
|
* Set the internal list and check if it contains any references
|
|
* @param {ve.dm.InternalList} internalList Internal list
|
|
*/
|
|
ve.ui.MWReferenceSearchWidget.prototype.setInternalList = function ( internalList ) {
|
|
var i, iLen, groupNames, groupName, groups = internalList.getNodeGroups();
|
|
|
|
this.internalList = internalList;
|
|
|
|
groupNames = ve.getObjectKeys( groups );
|
|
for ( i = 0, iLen = groupNames.length; i < iLen; i++ ) {
|
|
groupName = groupNames[i];
|
|
if ( groupName.lastIndexOf( 'mwReference/' ) !== 0 ) {
|
|
continue;
|
|
}
|
|
if ( groups[groupName].indexOrder.length ) {
|
|
this.indexEmpty = false;
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Build a serchable index of references.
|
|
*
|
|
* @method
|
|
*/
|
|
ve.ui.MWReferenceSearchWidget.prototype.buildIndex = function () {
|
|
if ( this.built ) {
|
|
return;
|
|
}
|
|
|
|
var i, iLen, j, jLen, ref, group, groupName, groupNames, view, text, firstNodes, indexOrder,
|
|
refGroup, refNode, matches, name, citation,
|
|
groups = this.internalList.getNodeGroups();
|
|
|
|
function extractAttrs() {
|
|
text += ' ' + this.getAttribute( 'href' );
|
|
}
|
|
|
|
this.index = [];
|
|
groupNames = ve.getObjectKeys( groups ).sort();
|
|
|
|
for ( i = 0, iLen = groupNames.length; i < iLen; i++ ) {
|
|
groupName = groupNames[i];
|
|
if ( groupName.lastIndexOf( 'mwReference/' ) !== 0 ) {
|
|
continue;
|
|
}
|
|
group = groups[groupName];
|
|
firstNodes = group.firstNodes;
|
|
indexOrder = group.indexOrder;
|
|
for ( j = 0, jLen = indexOrder.length; j < jLen; j++ ) {
|
|
refNode = firstNodes[indexOrder[j]];
|
|
ref = ve.dm.MWReferenceModel.static.newFromReferenceNode( refNode );
|
|
view = new ve.ce.InternalItemNode( this.internalList.getItemNode( ref.getListIndex() ) );
|
|
|
|
// HACK: PHP parser doesn't wrap single lines in a paragraph
|
|
if ( view.$element.children().length === 1 && view.$element.children( 'p' ).length === 1 ) {
|
|
// unwrap inner
|
|
view.$element.children().replaceWith( view.$element.children().contents() );
|
|
}
|
|
|
|
refGroup = ref.getGroup();
|
|
citation = ( refGroup && refGroup.length ? refGroup + ' ' : '' ) + ( j + 1 );
|
|
matches = ref.getListKey().match( /^literal\/(.*)$/ );
|
|
name = matches && matches[1] || '';
|
|
// Hide previously auto-generated reference names
|
|
if ( name.match( /^:[0-9]+$/ ) ) {
|
|
name = '';
|
|
}
|
|
// Make visible text, citation and reference name searchable
|
|
text = [ view.$element.text().toLowerCase(), citation, name ].join( ' ' );
|
|
// Make URLs searchable
|
|
view.$element.find( 'a[href]' ).each( extractAttrs );
|
|
|
|
this.index.push( {
|
|
'$element': view.$element.clone(),
|
|
'text': text,
|
|
'reference': ref,
|
|
'citation': citation,
|
|
'name': name
|
|
} );
|
|
view.destroy();
|
|
}
|
|
}
|
|
|
|
// Re-populate
|
|
this.onQueryChange();
|
|
|
|
this.built = true;
|
|
};
|
|
|
|
/**
|
|
* Check whether buildIndex will create an empty index based on the current internalList.
|
|
*
|
|
* @returns {boolean} Index is empty
|
|
*/
|
|
ve.ui.MWReferenceSearchWidget.prototype.isIndexEmpty = function () {
|
|
return this.indexEmpty;
|
|
};
|
|
|
|
/**
|
|
* Handle media query response events.
|
|
*
|
|
* @method
|
|
*/
|
|
ve.ui.MWReferenceSearchWidget.prototype.addResults = function () {
|
|
var i, len, item, $citation, $name,
|
|
value = this.query.getValue(),
|
|
query = value.toLowerCase(),
|
|
items = [];
|
|
|
|
for ( i = 0, len = this.index.length; i < len; i++ ) {
|
|
item = this.index[i];
|
|
if ( item.text.indexOf( query ) >= 0 ) {
|
|
$citation = this.$( '<div>' )
|
|
.addClass( 've-ui-mwReferenceSearchWidget-citation' )
|
|
.text( '[' + item.citation + ']' );
|
|
$name = this.$( '<div>' )
|
|
.addClass( 've-ui-mwReferenceSearchWidget-name' )
|
|
.text( item.name );
|
|
items.push(
|
|
new ve.ui.MWReferenceResultWidget( i, {
|
|
'$': this.$, 'label': $citation.add( $name ).add( item.$element )
|
|
} )
|
|
);
|
|
}
|
|
}
|
|
|
|
this.results.addItems( items );
|
|
};
|