Catrope has uploaded a new change for review. https://gerrit.wikimedia.org/r/209167
Change subject: Add user name suggestions from the API in the mention inspector ...................................................................... Add user name suggestions from the API in the mention inspector Keep the suggestions from the topic: we're able to do more useful search on them (substring match rather than prefix match) and float them to the top. Bug: T93421 Change-Id: I1aa5cfc1e2d645ba977f265fd9f3b13bc2589e46 --- M modules/editor/editors/visualeditor/ui/widgets/mw.flow.ve.ui.MentionTargetInputWidget.js 1 file changed, 54 insertions(+), 78 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow refs/changes/67/209167/1 diff --git a/modules/editor/editors/visualeditor/ui/widgets/mw.flow.ve.ui.MentionTargetInputWidget.js b/modules/editor/editors/visualeditor/ui/widgets/mw.flow.ve.ui.MentionTargetInputWidget.js index 2ea6aab..57fd243 100644 --- a/modules/editor/editors/visualeditor/ui/widgets/mw.flow.ve.ui.MentionTargetInputWidget.js +++ b/modules/editor/editors/visualeditor/ui/widgets/mw.flow.ve.ui.MentionTargetInputWidget.js @@ -25,8 +25,6 @@ return !mw.util.isIPAddress( poster, false ); } ); this.username = null; - // Username to validity promise (promise resolves with true/false for existent/non-existent - this.isUsernameValidCache = {}; this.$element.addClass( 'flow-ve-ui-mentionTargetInputWidget' ); this.lookupMenu.$element.addClass( 'flow-ve-ui-mentionTargetInputWidget-menu' ); @@ -37,81 +35,63 @@ OO.mixinClass( mw.flow.ve.ui.MentionTargetInputWidget, OO.ui.LookupElement ); mw.flow.ve.ui.MentionTargetInputWidget.prototype.isValid = function () { - var api = new mw.Api(), - dfd = $.Deferred(), - promise = dfd.promise(), - username = this.getValue(), - widget = this, - isValid; - - if ( $.trim( username ) === '' ) { - dfd.resolve( false ); - return promise; - } - - username = username[0].toUpperCase() + username.slice( 1 ); - if ( this.isUsernameValidCache[username] !== undefined ) { - return this.isUsernameValidCache[username]; - } - - // Note that we delete this below if it turns out to get an error. - this.isUsernameValidCache[username] = promise; - - api.get( { - action: 'query', - list: 'users', - ususers: username - } ).done( function ( resp ) { - if ( - resp && - resp.query && - resp.query.users && - resp.query.users.length > 0 - ) { - // This is the normal path for either existent or non-existent users. - isValid = resp.query.users[0].missing === undefined; - dfd.resolve( isValid ); - } else { - // This means part of the response is missing, which again shouldn't - // happen (it could for empty string user, but we're not supposed to - // send the request at all then). See explanation under fail. - dfd.resolve( true ); - delete widget.isUsernameValidCache[username]; - } - } ).fail( function () { - // This should only happen on error cases. Even if the user doesn't exist, - // we should still enter done. Since this is an unforseen error, return true - // so we don't block submission, and evict cache. - dfd.resolve( true ); - delete widget.isUsernameValidCache[username]; - } ); - - return promise; + return $.Deferred().resolve( !!mw.Title.newFromText( this.value, 2 ) ); }; /** * Gets a promise representing the auto-complete. - * Right now, the auto-complete is based on the users who have already posted to the topic. + * The auto-complete is based on the users who have already posted to the topic + * and on an API call. * - * It does a case-insensitive search for a string (anywhere in the poster's username) - * matching what the user has typed in so far. - * + * For users who have posted to the topic, we do a case-insensitive search for a string + * (anywhere in the poster's username) matching what the user has typed in so far. * E.g. if one of the posters is "Mary Jane Smith", that will be a suggestion if the user has * entered e.g. "Mary", "jane", or 'Smi'. * + * For the API call, the best we have is a prefix search. + * * @method - * @returns {jQuery.Promise} + * @return {jQuery.Promise} */ mw.flow.ve.ui.MentionTargetInputWidget.prototype.getLookupRequest = function () { - var abortObject = { abort: $.noop }, dfd = $.Deferred(), - lowerValue = this.value.toLowerCase(), matches; + var xhr, + lowerValue = this.value.toLowerCase(), + initialUpperValue = this.value.charAt( 0 ).toUpperCase() + this.value.slice( 1 ), + localMatches = $.grep( this.loggedInTopicPosters, function ( poster ) { + return poster.toLowerCase().indexOf( lowerValue ) >= 0; + } ); - matches = $.grep( this.loggedInTopicPosters, function ( poster ) { - return poster.toLowerCase().indexOf( lowerValue ) >= 0; + if ( this.value === '' ) { + return $.Deferred() + .resolve( { + localMatches: localMatches, + apiMatches: [] } + ) + .promise( { abort: $.noop } ); + } + + xhr = new mw.Api().get( { + action: 'query', + list: 'allusers', + auprefix: initialUpperValue, + aulimit: 5 } ); - - dfd.resolve( matches ); - return dfd.promise( abortObject ); + return xhr + .then( function ( data ) { + var i, len, + users = OO.getProp( data, 'query', 'allusers' ) || [], + apiMatches = []; + for ( i = 0, len = users.length; i < len; i++ ) { + if ( localMatches.indexOf( users[i].name ) === -1 ) { + apiMatches.push( users[i].name ); + } + } + return { + localMatches: localMatches, + apiMatches: apiMatches + }; + } ) + .promise( { abort: xhr.abort } ); }; mw.flow.ve.ui.MentionTargetInputWidget.prototype.getLookupCacheDataFromResponse = function ( data ) { @@ -121,22 +101,18 @@ /** * Converts the raw data to UI objects * - * @param Array list of users + * @param {Object} data Raw data + * @param {string[]} data.localMatches Users in the current conversation + * @param {string[]} data.apiMatches Users from the API * @return {OO.ui.MenuOptionWidget[]} Menu items */ - mw.flow.ve.ui.MentionTargetInputWidget.prototype.getLookupMenuOptionsFromData = function ( users ) { - var items = [], user, i; - - for ( i = 0; i < users.length; i++ ) { - user = users[i]; - - items.push( new OO.ui.MenuOptionWidget( { - data: user, - label: user - } ) ); - } - - return items; + mw.flow.ve.ui.MentionTargetInputWidget.prototype.getLookupMenuOptionsFromData = function ( data ) { + return $.map( data.localMatches.concat( data.apiMatches ), function ( username ) { + return new OO.ui.MenuOptionWidget( { + data: username, + label: username + } ); + } ); }; // Based on ve.ui.MWLinkTargetInputWidget.prototype.initializeLookupMenuSelection -- To view, visit https://gerrit.wikimedia.org/r/209167 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I1aa5cfc1e2d645ba977f265fd9f3b13bc2589e46 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Flow Gerrit-Branch: master Gerrit-Owner: Catrope <roan.katt...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits