diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js index 1104458f22..e7767cb3cd 100644 --- a/src/ScalarMessaging.js +++ b/src/ScalarMessaging.js @@ -481,7 +481,7 @@ const onMessage = function(event) { // All strings start with the empty string, so for sanity return if the length // of the event origin is 0. let url = SdkConfig.get().integrations_ui_url; - if (event.origin.length === 0 || !url.startsWith(event.origin)) { + if (event.origin.length === 0 || !url.startsWith(event.origin) || !event.data.action) { return; // don't log this - debugging APIs like to spam postMessage which floods the log otherwise } diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 009fdabb53..fef84468ec 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -25,11 +25,6 @@ import { _t } from './languageHandler'; export default { LABS_FEATURES: [ - { - name: "-", - id: 'rich_text_editor', - default: false, - }, { name: "-", id: 'matrix_apps', @@ -39,8 +34,7 @@ export default { // horrible but it works. The locality makes this somewhat more palatable. doTranslations: function() { - this.LABS_FEATURES[0].name = _t("New Composer & Autocomplete"); - this.LABS_FEATURES[1].name = _t("Matrix Apps"); + this.LABS_FEATURES[0].name = _t("Matrix Apps"); }, loadProfileInfo: function() { diff --git a/src/autocomplete/EmojiProvider.js b/src/autocomplete/EmojiProvider.js index 35e9cc7b68..f70ff7f200 100644 --- a/src/autocomplete/EmojiProvider.js +++ b/src/autocomplete/EmojiProvider.js @@ -18,7 +18,7 @@ limitations under the License. import React from 'react'; import { _t } from '../languageHandler'; import AutocompleteProvider from './AutocompleteProvider'; -import {emojioneList, shortnameToImage, shortnameToUnicode, asciiRegexp} from 'emojione'; +import {emojioneList, shortnameToImage, shortnameToUnicode, asciiRegexp, unicodeRegexp} from 'emojione'; import FuzzyMatcher from './FuzzyMatcher'; import sdk from '../index'; import {PillCompletion} from './Components'; @@ -41,7 +41,15 @@ const CATEGORY_ORDER = [ ]; // Match for ":wink:" or ascii-style ";-)" provided by emojione -const EMOJI_REGEX = new RegExp('(' + asciiRegexp + '|:\\w*:?)$', 'g'); +// (^|\s|(emojiUnicode)) to make sure we're either at the start of the string or there's a +// whitespace character or an emoji before the emoji. The reason for unicodeRegexp is +// that we need to support inputting multiple emoji with no space between them. +const EMOJI_REGEX = new RegExp('(?:^|\\s|' + unicodeRegexp + ')(' + asciiRegexp + '|:\\w*:?)$', 'g'); + +// We also need to match the non-zero-length prefixes to remove them from the final match, +// and update the range so that we don't replace the whitespace or the previous emoji. +const MATCH_PREFIX_REGEX = new RegExp('(\\s|' + unicodeRegexp + ')'); + const EMOJI_SHORTNAMES = Object.keys(EmojiData).map((key) => EmojiData[key]).sort( (a, b) => { if (a.category === b.category) { @@ -73,9 +81,18 @@ export default class EmojiProvider extends AutocompleteProvider { const EmojiText = sdk.getComponent('views.elements.EmojiText'); let completions = []; - let {command, range} = this.getCurrentCommand(query, selection); + const {command, range} = this.getCurrentCommand(query, selection); if (command) { - completions = this.matcher.match(command[0]).map(result => { + let matchedString = command[0]; + + // Remove prefix of any length (single whitespace or unicode emoji) + const prefixMatch = MATCH_PREFIX_REGEX.exec(matchedString); + if (prefixMatch) { + matchedString = matchedString.slice(prefixMatch[0].length); + range.start += prefixMatch[0].length; + } + + completions = this.matcher.match(matchedString).map((result) => { const {shortname} = result; const unicode = shortnameToUnicode(shortname); return { diff --git a/src/autocomplete/UserProvider.js b/src/autocomplete/UserProvider.js index 26ec15e124..0025a3c5e9 100644 --- a/src/autocomplete/UserProvider.js +++ b/src/autocomplete/UserProvider.js @@ -91,8 +91,8 @@ export default class UserProvider extends AutocompleteProvider { if (member.userId !== currentUserId) return true; }); - this.users = _sortBy(this.users, (completion) => - 1E20 - lastSpoken[completion.user.userId] || 1E20, + this.users = _sortBy(this.users, (member) => + 1E20 - lastSpoken[member.userId] || 1E20, ); this.matcher.setObjects(this.users); diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 8a93af403b..2b44e9eec4 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -190,7 +190,7 @@ export default React.createClass({ ; let nameNode; - if (summary.profile.name) { + if (summary.profile && summary.profile.name) { nameNode =