From b477e384d86e9233aed55448598352d2c42a1525 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 6 Dec 2016 07:36:40 -0500 Subject: Added support for autocompleting at mentions for users with non-alphanumeric names (#4717) --- .../components/suggestion/at_mention_provider.jsx | 3 +- webapp/components/suggestion/suggestion_box.jsx | 45 ++++++++++++++-------- 2 files changed, 31 insertions(+), 17 deletions(-) (limited to 'webapp/components/suggestion') diff --git a/webapp/components/suggestion/at_mention_provider.jsx b/webapp/components/suggestion/at_mention_provider.jsx index 6118b8d98..f1b36d697 100644 --- a/webapp/components/suggestion/at_mention_provider.jsx +++ b/webapp/components/suggestion/at_mention_provider.jsx @@ -15,6 +15,7 @@ import {Constants, ActionTypes} from 'utils/constants.jsx'; import React from 'react'; import {FormattedMessage} from 'react-intl'; +import XRegExp from 'xregexp'; class AtMentionSuggestion extends Suggestion { render() { @@ -124,7 +125,7 @@ export default class AtMentionProvider { handlePretextChanged(suggestionId, pretext) { const hadSuggestions = this.clearTimeout(this.timeoutId); - const captured = (/(?:^|\W)@([a-z0-9\-._]*)$/i).exec(pretext.toLowerCase()); + const captured = XRegExp.cache('(?:^|\\W)@([\\pL\\d\\-_.]*)$', 'i').exec(pretext.toLowerCase()); if (captured) { const prefix = captured[1]; diff --git a/webapp/components/suggestion/suggestion_box.jsx b/webapp/components/suggestion/suggestion_box.jsx index 514227394..a1f89efb5 100644 --- a/webapp/components/suggestion/suggestion_box.jsx +++ b/webapp/components/suggestion/suggestion_box.jsx @@ -22,11 +22,15 @@ export default class SuggestionBox extends React.Component { this.handleCompleteWord = this.handleCompleteWord.bind(this); this.handleChange = this.handleChange.bind(this); + this.handleCompositionUpdate = this.handleCompositionUpdate.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this); this.handlePretextChanged = this.handlePretextChanged.bind(this); this.suggestionId = Utils.generateId(); SuggestionStore.registerSuggestionBox(this.suggestionId); + + // Keep track of whether we're composing a CJK character so we can make suggetsions for partial characters + this.partialCharacter = ''; } componentDidMount() { @@ -83,20 +87,28 @@ export default class SuggestionBox extends React.Component { handleChange(e) { const textbox = this.getTextbox(); const caret = Utils.getCaretPosition(textbox); - const pretext = textbox.value.substring(0, caret); + const pretext = textbox.value.substring(0, caret) + this.partialCharacter; - GlobalActions.emitSuggestionPretextChanged(this.suggestionId, pretext); + if (SuggestionStore.getPretext(this.suggestionId) !== pretext) { + GlobalActions.emitSuggestionPretextChanged(this.suggestionId, pretext); + } if (this.props.onChange) { this.props.onChange(e); } } + handleCompositionUpdate(e) { + // Save the currently composing character so that it can be used for autocomplete suggestions + // when handleChange is called immediately after this + this.partialCharacter = e.data; + } + handleCompleteWord(term, matchedPretext) { const textbox = this.getTextbox(); const caret = Utils.getCaretPosition(textbox); const text = this.props.value; - const pretext = text.substring(0, caret); + const pretext = text.substring(0, caret) + this.partialCharacter; let prefix; if (pretext.endsWith(matchedPretext)) { @@ -168,37 +180,38 @@ export default class SuggestionBox extends React.Component { ...props } = this.props; + // Don't pass props used by SuggestionBox + Reflect.deleteProperty(props, 'providers'); + + const childProps = { + ref: 'textbox', + onInput: this.handleChange, + onCompositionUpdate: this.handleCompositionUpdate, + onKeyDown: this.handleKeyDown + }; + let textbox = null; if (type === 'input') { textbox = ( ); } else if (type === 'search') { - const newProps = {...props}; - Reflect.deleteProperty(newProps, 'providers'); textbox = ( ); } else if (type === 'textarea') { textbox = ( ); } -- cgit v1.2.3-1-g7c22