]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blobdiff - extensions/Cite/modules/ve-cite/ve.ui.MWReferenceSearchWidget.js
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / extensions / Cite / modules / ve-cite / ve.ui.MWReferenceSearchWidget.js
diff --git a/extensions/Cite/modules/ve-cite/ve.ui.MWReferenceSearchWidget.js b/extensions/Cite/modules/ve-cite/ve.ui.MWReferenceSearchWidget.js
new file mode 100644 (file)
index 0000000..49c5d3d
--- /dev/null
@@ -0,0 +1,232 @@
+/*!
+ * VisualEditor UserInterface MWReferenceSearchWidget class.
+ *
+ * @copyright 2011-2017 Cite 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 initialization
+       config = ve.extendObject( {
+               placeholder: ve.msg( 'cite-ve-reference-input-placeholder' )
+       }, config );
+
+       // Parent constructor
+       ve.ui.MWReferenceSearchWidget.super.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 );
+
+/* Methods */
+
+/**
+ * Handle query change events.
+ *
+ * @method
+ * @param {string} value New value
+ */
+ve.ui.MWReferenceSearchWidget.prototype.onQueryChange = function () {
+       // Parent method
+       ve.ui.MWReferenceSearchWidget.super.prototype.onQueryChange.call( this );
+
+       // Populate
+       this.addResults();
+};
+
+/**
+ * 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();
+
+       if ( this.results.getSelectedItem() ) {
+               this.results.getSelectedItem().setSelected( false );
+       }
+
+       this.internalList = internalList;
+       this.internalList.connect( this, { update: 'onInternalListUpdate' } );
+       this.internalList.getListNode().connect( this, { update: 'onListNodeUpdate' } );
+
+       groupNames = Object.keys( 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;
+               }
+       }
+       this.indexEmpty = true;
+};
+
+/**
+ * Handle the updating of the InternalList object.
+ *
+ * This will occur after a document transaction.
+ *
+ * @method
+ * @param {string[]} groupsChanged A list of groups which have changed in this transaction
+ */
+ve.ui.MWReferenceSearchWidget.prototype.onInternalListUpdate = function ( groupsChanged ) {
+       var i, len;
+       for ( i = 0, len = groupsChanged.length; i < len; i++ ) {
+               if ( groupsChanged[ i ].indexOf( 'mwReference/' ) === 0 ) {
+                       this.built = false;
+                       break;
+               }
+       }
+};
+
+/**
+ * Handle the updating of the InternalListNode.
+ *
+ * This will occur after changes to any InternalItemNode.
+ *
+ * @method
+ */
+ve.ui.MWReferenceSearchWidget.prototype.onListNodeUpdate = function () {
+       this.built = false;
+};
+
+/**
+ * Build a searchable index of references.
+ *
+ * @method
+ */
+ve.ui.MWReferenceSearchWidget.prototype.buildIndex = function () {
+       var n, i, iLen, j, jLen, refModel, group, groupName, groupNames, view, text, firstNodes, indexOrder,
+               refGroup, refNode, matches, name, citation,
+               groups = this.internalList.getNodeGroups();
+
+       if ( this.built ) {
+               return;
+       }
+
+       function extractAttrs() {
+               text += ' ' + this.getAttribute( 'href' );
+       }
+
+       this.index = [];
+       groupNames = Object.keys( 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;
+
+               n = 0;
+               for ( j = 0, jLen = indexOrder.length; j < jLen; j++ ) {
+                       refNode = firstNodes[ indexOrder[ j ] ];
+                       // Exclude placeholder references
+                       if ( refNode.getAttribute( 'placeholder' ) ) {
+                               continue;
+                       }
+                       // Only increment counter for real references
+                       n++;
+                       refModel = ve.dm.MWReferenceModel.static.newFromReferenceNode( refNode );
+                       view = new ve.ui.MWPreviewElement(
+                               this.internalList.getItemNode( refModel.getListIndex() )
+                       );
+
+                       refGroup = refModel.getGroup();
+                       citation = ( refGroup && refGroup.length ? refGroup + ' ' : '' ) + n;
+                       matches = refModel.getListKey().match( /^literal\/(.*)$/ );
+                       name = matches && matches[ 1 ] || '';
+                       // Hide previously auto-generated reference names
+                       if ( name.match( /^:[0-9]+$/ ) ) {
+                               name = '';
+                       }
+
+                       // TODO: At some point we need to make sure this text is updated in
+                       // case the view node is still rendering. This shouldn't happen because
+                       // all references are supposed to be in the store and therefore are
+                       // immediately rendered, but we shouldn't trust that on principle to
+                       // account for edge cases.
+
+                       // 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,
+                               text: text,
+                               reference: refModel,
+                               citation: citation,
+                               name: name
+                       } );
+               }
+       }
+
+       // Re-populate
+       this.onQueryChange();
+
+       this.built = true;
+};
+
+/**
+ * Check whether buildIndex will create an empty index based on the current internalList.
+ *
+ * @return {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,
+               query = this.query.getValue().trim().toLowerCase(),
+               items = [];
+
+       for ( i = 0, len = this.index.length; i < len; i++ ) {
+               item = this.index[ i ];
+               if ( item.text.indexOf( query ) >= 0 ) {
+                       $citation = $( '<div>' )
+                               .addClass( 've-ui-mwReferenceSearchWidget-citation' )
+                               .text( '[' + item.citation + ']' );
+                       $name = $( '<div>' )
+                               .addClass( 've-ui-mwReferenceSearchWidget-name' )
+                               .text( item.name );
+                       items.push(
+                               new ve.ui.MWReferenceResultWidget( {
+                                       data: item.reference,
+                                       label: $citation.add( $name ).add( item.$element )
+                               } )
+                       );
+               }
+       }
+
+       this.results.addItems( items );
+};