mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-09-16 01:56:55 +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:
parent
f1c527b721
commit
3120d586d2
1 changed files with 94 additions and 7 deletions
|
@ -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
|
// Components
|
||||||
|
|
||||||
this.ChatInput = this.fine.define(
|
this.ChatInput = this.fine.define(
|
||||||
'chat-input',
|
'chat-input',
|
||||||
n => n && n.setChatInputRef && n.setAutocompleteInputRef,
|
n => n && n.setChatInputRef && n.setLocalAutocompleteInputRef,
|
||||||
Twilight.CHAT_ROUTES
|
Twilight.CHAT_ROUTES
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -57,10 +76,24 @@ export default class Input extends Module {
|
||||||
n => n && n.getMatchedEmotes,
|
n => n && n.getMatchedEmotes,
|
||||||
Twilight.CHAT_ROUTES
|
Twilight.CHAT_ROUTES
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
this.MentionSuggestions = this.fine.define(
|
||||||
|
'tab-mention-suggestions',
|
||||||
|
n => n && n.getMentions && n.renderMention,
|
||||||
|
Twilight.CHAT_ROUTES
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onEnable() {
|
async onEnable() {
|
||||||
this.chat.context.on('changed:chat.actions.room', () => this.ChatInput.forceUpdate());
|
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'),
|
const React = await this.web_munch.findModule('react'),
|
||||||
createElement = React && React.createElement;
|
createElement = React && React.createElement;
|
||||||
|
@ -119,8 +152,14 @@ export default class Input extends Module {
|
||||||
this.overrideEmoteMatcher(inst);
|
this.overrideEmoteMatcher(inst);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.MentionSuggestions.ready((cls, instances) => {
|
||||||
|
for(const inst of instances)
|
||||||
|
this.overrideMentionMatcher(inst);
|
||||||
|
});
|
||||||
|
|
||||||
this.ChatInput.on('update', this.updateEmoteCompletion, this);
|
this.ChatInput.on('update', this.updateEmoteCompletion, this);
|
||||||
this.EmoteSuggestions.on('mount', this.overrideEmoteMatcher, 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) {
|
overrideEmoteMatcher(inst) {
|
||||||
if ( inst._ffz_override )
|
if ( inst._ffz_override )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const t = this,
|
const t = this;
|
||||||
old_get_matched = inst.getMatchedEmotes;
|
|
||||||
|
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) {
|
inst.doesEmoteMatchTerm = function(emote, term) {
|
||||||
const emote_name = emote.name || emote.token,
|
const emote_name = emote.name || emote.token,
|
||||||
|
@ -157,7 +212,9 @@ export default class Input extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
inst.getMatchedEmotes = function(input) {
|
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') ) {
|
if ( t.chat.context.get('chat.tab-complete.ffz-emotes') ) {
|
||||||
const ffz_emotes = t.getEmoteSuggestions(input, this);
|
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') )
|
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);
|
const emoji = t.getEmojiSuggestions(input, this);
|
||||||
if ( Array.isArray(emoji) && emoji.length )
|
if ( Array.isArray(emoji) && emoji.length )
|
||||||
results = Array.isArray(results) ? results.concat(emoji) : emoji;
|
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'),
|
const React = this.web_munch.getModule('react'),
|
||||||
|
@ -195,7 +252,37 @@ 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) {
|
getEmojiSuggestions(input, inst) {
|
||||||
|
if (!input.startsWith(':')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
let search = input.slice(1).toLowerCase();
|
let search = input.slice(1).toLowerCase();
|
||||||
const style = this.chat.context.get('chat.emoji.style'),
|
const style = this.chat.context.get('chat.emoji.style'),
|
||||||
tone = this.settings.provider.get('emoji-tone', null),
|
tone = this.settings.provider.get('emoji-tone', null),
|
||||||
|
@ -242,7 +329,7 @@ export default class Input extends Module {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const search = input.slice(1),
|
const search = input.startsWith(':') ? input.slice(1) : input,
|
||||||
results = [],
|
results = [],
|
||||||
emotes = this.emotes.getEmotes(
|
emotes = this.emotes.getEmotes(
|
||||||
user && user.id,
|
user && user.id,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue