1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-02 07:58:31 +00:00

Fixes and improves tab-completion hook (#613)

* Fixes tab-completion for emotes added by FFZ

* Implement tab-completion of emotes without the need of the colon

If enabled this will prevent username tab-completion without the @ in-front of the name, but will allow emotes to be tab-completed without the need of the colon in-front

* Implement result limit of 25 with setting
This commit is contained in:
Lordmau5 2019-06-28 04:54:58 +02:00 committed by Mike
parent f1c527b721
commit 3120d586d2

View file

@ -42,12 +42,31 @@ export default class Input extends Module {
}
});
this.settings.add('chat.tab-complete.emotes-without-colon', {
default: false,
ui: {
path: 'Chat > Input >> Tab Completion',
title: 'Allow tab-completion of emotes without typing a colon. (:)',
description: 'This will prevent the tab-completion of usernames without the @ prefix.',
component: 'setting-check-box'
}
});
this.settings.add('chat.tab-complete.limit-results', {
default: true,
ui: {
path: 'Chat > Input >> Tab Completion',
title: 'Limit tab-completion results to 25.',
component: 'setting-check-box'
}
});
// Components
this.ChatInput = this.fine.define(
'chat-input',
n => n && n.setChatInputRef && n.setAutocompleteInputRef,
n => n && n.setChatInputRef && n.setLocalAutocompleteInputRef,
Twilight.CHAT_ROUTES
);
@ -57,10 +76,24 @@ export default class Input extends Module {
n => n && n.getMatchedEmotes,
Twilight.CHAT_ROUTES
);
this.MentionSuggestions = this.fine.define(
'tab-mention-suggestions',
n => n && n.getMentions && n.renderMention,
Twilight.CHAT_ROUTES
);
}
async onEnable() {
this.chat.context.on('changed:chat.actions.room', () => this.ChatInput.forceUpdate());
this.chat.context.on('changed:chat.tab-complete.emotes-without-colon', enabled => {
for (const inst of this.EmoteSuggestions.instances)
inst.canBeTriggeredByTab = enabled;
for (const inst of this.MentionSuggestions.instances)
inst.canBeTriggeredByTab = !enabled;
});
const React = await this.web_munch.findModule('react'),
createElement = React && React.createElement;
@ -119,8 +152,14 @@ export default class Input extends Module {
this.overrideEmoteMatcher(inst);
});
this.MentionSuggestions.ready((cls, instances) => {
for(const inst of instances)
this.overrideMentionMatcher(inst);
});
this.ChatInput.on('update', this.updateEmoteCompletion, this);
this.EmoteSuggestions.on('mount', this.overrideEmoteMatcher, this);
this.MentionSuggestions.on('mount', this.overrideMentionMatcher, this);
}
@ -136,12 +175,28 @@ export default class Input extends Module {
}
// eslint-disable-next-line class-methods-use-this
overrideMentionMatcher(inst) {
if ( inst._ffz_override )
return;
inst.canBeTriggeredByTab = !this.chat.context.get('chat.tab-complete.emotes-without-colon');
}
overrideEmoteMatcher(inst) {
if ( inst._ffz_override )
return;
const t = this,
old_get_matched = inst.getMatchedEmotes;
const t = this;
inst.canBeTriggeredByTab = this.chat.context.get('chat.tab-complete.emotes-without-colon');
inst.getMatches = function(input, pressedTab) {
return pressedTab
? input.length < 2 ? null : inst.getMatchedEmotes(input)
: input.startsWith(':') ? input.length < 3 ? null : inst.getMatchedEmotes(input) : null;
}
inst.doesEmoteMatchTerm = function(emote, term) {
const emote_name = emote.name || emote.token,
@ -157,7 +212,9 @@ export default class Input extends Module {
}
inst.getMatchedEmotes = function(input) {
let results = old_get_matched.call(this, input);
const limitResults = t.chat.context.get('chat.tab-complete.limit-results');
let results = t.getTwitchEmoteSuggestions(input, this);
if ( t.chat.context.get('chat.tab-complete.ffz-emotes') ) {
const ffz_emotes = t.getEmoteSuggestions(input, this);
@ -166,13 +223,13 @@ export default class Input extends Module {
}
if ( ! t.chat.context.get('chat.tab-complete.emoji') )
return results;
return limitResults && results.length > 25 ? results.slice(0, 25) : results;
const emoji = t.getEmojiSuggestions(input, this);
if ( Array.isArray(emoji) && emoji.length )
results = Array.isArray(results) ? results.concat(emoji) : emoji;
return results;
return limitResults && results.length > 25 ? results.slice(0, 25) : results;
}
const React = this.web_munch.getModule('react'),
@ -194,8 +251,38 @@ export default class Input extends Module {
}
}
// eslint-disable-next-line class-methods-use-this
getTwitchEmoteSuggestions(input, inst) {
const hydratedEmotes = inst.hydrateEmotes(inst.props.emotes);
if (!Array.isArray(hydratedEmotes)) {
return [];
}
const results = [];
const search = input.startsWith(':') ? input.slice(1) : input;
for (const set of hydratedEmotes) {
if (set && Array.isArray(set.emotes)) {
for (const emote of set.emotes) {
if (inst.doesEmoteMatchTerm(emote, search)) {
results.push({
current: input,
replacement: emote.token,
element: inst.renderEmoteSuggestion(emote)
});
}
}
}
}
return results;
}
getEmojiSuggestions(input, inst) {
if (!input.startsWith(':')) {
return [];
}
let search = input.slice(1).toLowerCase();
const style = this.chat.context.get('chat.emoji.style'),
tone = this.settings.provider.get('emoji-tone', null),
@ -242,7 +329,7 @@ export default class Input extends Module {
return [];
}
const search = input.slice(1),
const search = input.startsWith(':') ? input.slice(1) : input,
results = [],
emotes = this.emotes.getEmotes(
user && user.id,