mirror of https://github.com/vector-im/riot-web
Implement ascii emoji tab completion
When a fully plaintext, ascii emoji is typed like ";-)", pressing tab will suggest emojione to replace it with based off of the meta data provided by emojione. e.g. the aliases_ascii for `😃` are [":D",":-D","=D"] so typing ":D *tab*" will insert a real 😃pull/21833/head
parent
8912400675
commit
982b009b90
|
@ -5,13 +5,17 @@ const fs = require('fs');
|
||||||
const output = Object.keys(EMOJI_DATA).map(
|
const output = Object.keys(EMOJI_DATA).map(
|
||||||
(key) => {
|
(key) => {
|
||||||
const datum = EMOJI_DATA[key];
|
const datum = EMOJI_DATA[key];
|
||||||
return {
|
const newDatum = {
|
||||||
name: datum.name,
|
name: datum.name,
|
||||||
shortname: datum.shortname,
|
shortname: datum.shortname,
|
||||||
category: datum.category,
|
category: datum.category,
|
||||||
emoji_order: datum.emoji_order,
|
emoji_order: datum.emoji_order,
|
||||||
};
|
};
|
||||||
},
|
if (datum.aliases_ascii.length > 0) {
|
||||||
|
newDatum.aliases_ascii = datum.aliases_ascii;
|
||||||
|
}
|
||||||
|
return newDatum;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Write to a file in src. Changes should be checked into git. This file is copied by
|
// Write to a file in src. Changes should be checked into git. This file is copied by
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import AutocompleteProvider from './AutocompleteProvider';
|
import AutocompleteProvider from './AutocompleteProvider';
|
||||||
import {emojioneList, shortnameToImage, shortnameToUnicode} from 'emojione';
|
import {emojioneList, shortnameToImage, shortnameToUnicode, asciiRegexp} from 'emojione';
|
||||||
import FuzzyMatcher from './FuzzyMatcher';
|
import FuzzyMatcher from './FuzzyMatcher';
|
||||||
import sdk from '../index';
|
import sdk from '../index';
|
||||||
import {PillCompletion} from './Components';
|
import {PillCompletion} from './Components';
|
||||||
|
@ -40,7 +40,8 @@ const CATEGORY_ORDER = [
|
||||||
'modifier',
|
'modifier',
|
||||||
];
|
];
|
||||||
|
|
||||||
const EMOJI_REGEX = /:\w*:?/g;
|
// Match for ":wink:" or ascii-style ";-)" provided by emojione
|
||||||
|
const EMOJI_REGEX = new RegExp('(:\\w*:?|' + asciiRegexp + ')', 'g');
|
||||||
const EMOJI_SHORTNAMES = Object.keys(EmojiData).map((key) => EmojiData[key]).sort(
|
const EMOJI_SHORTNAMES = Object.keys(EmojiData).map((key) => EmojiData[key]).sort(
|
||||||
(a, b) => {
|
(a, b) => {
|
||||||
if (a.category === b.category) {
|
if (a.category === b.category) {
|
||||||
|
@ -52,6 +53,7 @@ const EMOJI_SHORTNAMES = Object.keys(EmojiData).map((key) => EmojiData[key]).sor
|
||||||
return {
|
return {
|
||||||
name: a.name,
|
name: a.name,
|
||||||
shortname: a.shortname,
|
shortname: a.shortname,
|
||||||
|
aliases_ascii: a.aliases_ascii ? a.aliases_ascii.join(' ') : '',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -61,7 +63,9 @@ export default class EmojiProvider extends AutocompleteProvider {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(EMOJI_REGEX);
|
super(EMOJI_REGEX);
|
||||||
this.matcher = new FuzzyMatcher(EMOJI_SHORTNAMES, {
|
this.matcher = new FuzzyMatcher(EMOJI_SHORTNAMES, {
|
||||||
keys: ['shortname', 'name'],
|
keys: ['aliases_ascii', 'shortname', 'name'],
|
||||||
|
// For matching against ascii equivalents
|
||||||
|
shouldMatchWordsOnly: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,12 @@ export default class QueryMatcher {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.keys = options.keys;
|
this.keys = options.keys;
|
||||||
this.setObjects(objects);
|
this.setObjects(objects);
|
||||||
|
|
||||||
|
// By default, we remove any non-alphanumeric characters ([^A-Za-z0-9_]) from the
|
||||||
|
// query and the value being queried before matching
|
||||||
|
if (this.options.shouldMatchWordsOnly === undefined) {
|
||||||
|
this.options.shouldMatchWordsOnly = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setObjects(objects: Array<Object>) {
|
setObjects(objects: Array<Object>) {
|
||||||
|
@ -70,9 +76,16 @@ export default class QueryMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
match(query: String): Array<Object> {
|
match(query: String): Array<Object> {
|
||||||
query = query.toLowerCase().replace(/[^\w]/g, '');
|
query = query.toLowerCase();
|
||||||
|
if (this.options.shouldMatchWordsOnly) {
|
||||||
|
query = query.replace(/[^\w]/g, '');
|
||||||
|
}
|
||||||
const results = _sortedUniq(_sortBy(_flatMap(this.keyMap.keys, (key) => {
|
const results = _sortedUniq(_sortBy(_flatMap(this.keyMap.keys, (key) => {
|
||||||
return key.toLowerCase().replace(/[^\w]/g, '').indexOf(query) >= 0 ? this.keyMap.objectMap[key] : [];
|
let resultKey = key.toLowerCase();
|
||||||
|
if (this.options.shouldMatchWordsOnly) {
|
||||||
|
resultKey = resultKey.replace(/[^\w]/g, '');
|
||||||
|
}
|
||||||
|
return resultKey.indexOf(query) !== -1 ? this.keyMap.objectMap[key] : [];
|
||||||
}), (candidate) => this.keyMap.priorityMap.get(candidate)));
|
}), (candidate) => this.keyMap.priorityMap.get(candidate)));
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue