2018-04-07 19:09:32 -04:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
// RichContent Component
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
import Module from 'utilities/module';
|
|
|
|
import Twilight from 'site';
|
|
|
|
|
2019-05-07 15:04:12 -04:00
|
|
|
export default class Input extends Module {
|
2018-04-07 19:09:32 -04:00
|
|
|
constructor(...args) {
|
|
|
|
super(...args);
|
|
|
|
|
|
|
|
this.inject('chat');
|
2019-05-07 15:04:12 -04:00
|
|
|
this.inject('chat.actions');
|
2018-04-07 19:09:32 -04:00
|
|
|
this.inject('chat.emotes');
|
2018-04-12 20:30:00 -04:00
|
|
|
this.inject('chat.emoji');
|
2018-04-07 19:09:32 -04:00
|
|
|
this.inject('i18n');
|
|
|
|
this.inject('settings');
|
|
|
|
|
|
|
|
this.inject('site.fine');
|
|
|
|
this.inject('site.web_munch');
|
|
|
|
|
|
|
|
|
|
|
|
// Settings
|
|
|
|
|
2019-07-31 17:13:56 -04:00
|
|
|
this.settings.add('chat.mru.enabled', {
|
|
|
|
default: true,
|
|
|
|
ui: {
|
|
|
|
path: 'Chat > Input >> Recent Messages',
|
|
|
|
title: 'Allow pressing up and down to recall previously sent chat messages.',
|
|
|
|
component: 'setting-check-box'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-04-07 19:09:32 -04:00
|
|
|
this.settings.add('chat.tab-complete.ffz-emotes', {
|
|
|
|
default: true,
|
|
|
|
ui: {
|
|
|
|
path: 'Chat > Input >> Tab Completion',
|
|
|
|
title: 'Allow tab-completion of FrankerFaceZ emotes.',
|
|
|
|
component: 'setting-check-box'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-04-12 20:30:00 -04:00
|
|
|
this.settings.add('chat.tab-complete.emoji', {
|
|
|
|
default: true,
|
|
|
|
ui: {
|
|
|
|
path: 'Chat > Input >> Tab Completion',
|
|
|
|
title: 'Allow tab-completion of emoji.',
|
|
|
|
component: 'setting-check-box'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-06-28 04:54:58 +02:00
|
|
|
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'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2019-07-31 22:25:21 +02:00
|
|
|
this.settings.add('chat.tab-complete.prioritize-favorites', {
|
|
|
|
default: false,
|
|
|
|
ui: {
|
|
|
|
path: 'Chat > Input >> Tab Completion',
|
|
|
|
title: 'Prioritize favorite emotes at the top.',
|
|
|
|
component: 'setting-check-box'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-04-07 19:09:32 -04:00
|
|
|
|
|
|
|
// Components
|
|
|
|
|
|
|
|
this.ChatInput = this.fine.define(
|
|
|
|
'chat-input',
|
2019-06-28 04:54:58 +02:00
|
|
|
n => n && n.setChatInputRef && n.setLocalAutocompleteInputRef,
|
2018-04-07 19:09:32 -04:00
|
|
|
Twilight.CHAT_ROUTES
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
this.EmoteSuggestions = this.fine.define(
|
|
|
|
'tab-emote-suggestions',
|
|
|
|
n => n && n.getMatchedEmotes,
|
|
|
|
Twilight.CHAT_ROUTES
|
|
|
|
);
|
2019-06-28 04:54:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
this.MentionSuggestions = this.fine.define(
|
|
|
|
'tab-mention-suggestions',
|
|
|
|
n => n && n.getMentions && n.renderMention,
|
|
|
|
Twilight.CHAT_ROUTES
|
|
|
|
);
|
2019-07-31 22:25:21 +02:00
|
|
|
|
|
|
|
// Implement Twitch's unfinished emote usage object for prioritizing sorting
|
|
|
|
this.EmoteUsageCount = {
|
|
|
|
TriHard: 196568036,
|
|
|
|
Kappa: 192158118,
|
|
|
|
'4Head': 155758710,
|
|
|
|
PogChamp: 151485090,
|
|
|
|
cmonBruh: 146352878,
|
|
|
|
BibleThump: 56472964,
|
|
|
|
WutFace: 45069031,
|
|
|
|
Kreygasm: 41387580,
|
|
|
|
DansGame: 38097659,
|
|
|
|
SMOrc: 34734484,
|
|
|
|
KappaPride: 34262839,
|
|
|
|
VoHiYo: 27886434,
|
|
|
|
SwiftRage: 24561900,
|
|
|
|
ResidentSleeper: 24438298,
|
|
|
|
EleGiggle: 19891526,
|
|
|
|
FailFish: 19118343,
|
|
|
|
NotLikeThis: 18802905,
|
|
|
|
Keepo: 18351415,
|
|
|
|
BabyRage: 18220906,
|
|
|
|
MingLee: 18026207,
|
|
|
|
HeyGuys: 14851569,
|
|
|
|
ANELE: 14648986,
|
|
|
|
PJSalt: 14438861
|
|
|
|
};
|
2018-04-07 19:09:32 -04:00
|
|
|
}
|
|
|
|
|
2018-05-18 17:48:10 -04:00
|
|
|
async onEnable() {
|
2019-05-07 15:04:12 -04:00
|
|
|
this.chat.context.on('changed:chat.actions.room', () => this.ChatInput.forceUpdate());
|
2019-06-28 04:54:58 +02:00
|
|
|
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;
|
|
|
|
});
|
2019-05-07 15:04:12 -04:00
|
|
|
|
2018-05-18 17:48:10 -04:00
|
|
|
const React = await this.web_munch.findModule('react'),
|
2018-04-07 19:09:32 -04:00
|
|
|
createElement = React && React.createElement;
|
|
|
|
|
|
|
|
if ( ! createElement )
|
|
|
|
return this.log.warn('Unable to get React.');
|
|
|
|
|
2019-05-07 15:04:12 -04:00
|
|
|
const t = this;
|
|
|
|
|
2018-04-07 19:09:32 -04:00
|
|
|
this.ChatInput.ready((cls, instances) => {
|
2019-05-07 15:04:12 -04:00
|
|
|
const old_render = cls.prototype.render;
|
|
|
|
|
|
|
|
cls.prototype.render = function() {
|
|
|
|
const out = old_render.call(this);
|
|
|
|
try {
|
|
|
|
if ( ! out || ! out.props || ! Array.isArray(out.props.children) )
|
|
|
|
return out;
|
|
|
|
|
|
|
|
const props = this.props;
|
|
|
|
if ( ! props || ! props.channelID )
|
|
|
|
return out;
|
|
|
|
|
|
|
|
const u = props.sessionUser ? {
|
|
|
|
id: props.sessionUser.id,
|
|
|
|
login: props.sessionUser.login,
|
|
|
|
displayName: props.sessionUser.displayName,
|
|
|
|
mod: props.isCurrentUserModerator,
|
|
|
|
staff: props.isStaff
|
|
|
|
} : null,
|
|
|
|
r = {
|
|
|
|
id: props.channelID,
|
|
|
|
login: props.channelLogin,
|
|
|
|
displayName: props.channelDisplayName
|
|
|
|
}
|
|
|
|
|
|
|
|
const actions = t.actions.renderRoom(t.chat.context.get('context.chat.showModIcons'), u, r, createElement);
|
|
|
|
if ( actions )
|
|
|
|
out.props.children.unshift(actions);
|
|
|
|
|
|
|
|
} catch(err) {
|
|
|
|
t.log.error(err);
|
|
|
|
t.log.capture(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(const inst of instances) {
|
|
|
|
inst.forceUpdate();
|
2018-04-07 19:09:32 -04:00
|
|
|
this.updateEmoteCompletion(inst);
|
2019-07-31 22:26:27 +02:00
|
|
|
this.overrideChatInput(inst);
|
2019-05-07 15:04:12 -04:00
|
|
|
}
|
2018-04-07 19:09:32 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
this.EmoteSuggestions.ready((cls, instances) => {
|
|
|
|
for(const inst of instances)
|
|
|
|
this.overrideEmoteMatcher(inst);
|
|
|
|
});
|
|
|
|
|
2019-06-28 04:54:58 +02:00
|
|
|
this.MentionSuggestions.ready((cls, instances) => {
|
|
|
|
for(const inst of instances)
|
|
|
|
this.overrideMentionMatcher(inst);
|
|
|
|
});
|
|
|
|
|
2018-04-07 19:09:32 -04:00
|
|
|
this.ChatInput.on('update', this.updateEmoteCompletion, this);
|
2019-07-31 22:26:27 +02:00
|
|
|
this.ChatInput.on('mount', this.overrideChatInput, this);
|
2018-04-07 19:09:32 -04:00
|
|
|
this.EmoteSuggestions.on('mount', this.overrideEmoteMatcher, this);
|
2019-06-28 04:54:58 +02:00
|
|
|
this.MentionSuggestions.on('mount', this.overrideMentionMatcher, this);
|
2018-04-07 19:09:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
updateEmoteCompletion(inst, child) {
|
|
|
|
if ( ! child )
|
2019-03-26 17:37:00 -04:00
|
|
|
child = this.fine.searchTree(inst, 'tab-emote-suggestions', 50);
|
2018-04-07 19:09:32 -04:00
|
|
|
if ( ! child )
|
|
|
|
return;
|
|
|
|
|
|
|
|
child._ffz_user = inst.props.sessionUser;
|
|
|
|
child._ffz_channel_id = inst.props.channelID;
|
|
|
|
child._ffz_channel_login = inst.props.channelLogin;
|
|
|
|
}
|
2019-07-31 22:26:27 +02:00
|
|
|
|
|
|
|
overrideChatInput(inst) {
|
|
|
|
if ( inst._ffz_override )
|
|
|
|
return;
|
2019-07-31 17:13:56 -04:00
|
|
|
|
2019-07-31 22:26:27 +02:00
|
|
|
const t = this;
|
|
|
|
|
|
|
|
const originalOnKeyDown = inst.onKeyDown,
|
|
|
|
originalOnMessageSend = inst.onMessageSend;
|
|
|
|
|
2019-07-31 17:13:56 -04:00
|
|
|
inst.messageHistory = [];
|
|
|
|
inst.tempInput = '';
|
|
|
|
inst.messageHistoryPos = -1;
|
|
|
|
|
2019-07-31 22:26:27 +02:00
|
|
|
inst.onKeyDown = function(event) {
|
2019-07-31 17:13:56 -04:00
|
|
|
try {
|
|
|
|
if ( inst.autocompleteInputRef && t.chat.context.get('chat.mru.enabled') && ! event.shiftKey && ! event.ctrlKey && ! event.altKey ) {
|
|
|
|
const code = event.charCode || event.keyCode;
|
|
|
|
|
|
|
|
// Arrow Up
|
|
|
|
if ( code === 38 && inst.chatInputRef.selectionStart === 0 ) {
|
|
|
|
if ( ! inst.messageHistory.length )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( inst.chatInputRef.value && inst.messageHistoryPos === -1 )
|
|
|
|
inst.tempInput = inst.chatInputRef.value;
|
|
|
|
|
|
|
|
if ( inst.messageHistoryPos < inst.messageHistory.length - 1 ) {
|
|
|
|
inst.messageHistoryPos++;
|
|
|
|
inst.autocompleteInputRef.setValue(inst.messageHistory[inst.messageHistoryPos]);
|
|
|
|
}
|
2019-07-31 22:26:27 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
|
2019-07-31 17:13:56 -04:00
|
|
|
// Arrow Down
|
|
|
|
} else if ( code === 40 && inst.chatInputRef.selectionStart == inst.chatInputRef.value.length ) {
|
|
|
|
if ( ! inst.messageHistory.length )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( inst.messageHistoryPos > 0 ) {
|
|
|
|
inst.messageHistoryPos--;
|
|
|
|
inst.autocompleteInputRef.setValue(inst.messageHistory[inst.messageHistoryPos]);
|
|
|
|
|
|
|
|
} else if ( inst.messageHistoryPos === 0 ) {
|
|
|
|
inst.autocompleteInputRef.setValue(inst.tempInput);
|
|
|
|
inst.messageHistoryPos = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
2019-07-31 22:26:27 +02:00
|
|
|
}
|
|
|
|
}
|
2019-07-31 17:13:56 -04:00
|
|
|
|
|
|
|
} catch(err) {
|
|
|
|
t.log.capture(err);
|
|
|
|
t.log.error(err);
|
2019-07-31 22:26:27 +02:00
|
|
|
}
|
2019-07-31 17:13:56 -04:00
|
|
|
|
|
|
|
originalOnKeyDown.call(this, event);
|
2019-07-31 22:26:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inst.onMessageSend = function(event) {
|
2019-07-31 17:13:56 -04:00
|
|
|
try {
|
|
|
|
if ( t.chat.context.get('chat.mru.enabled') ) {
|
|
|
|
if (! inst.messageHistory.length || inst.messageHistory[0] !== inst.chatInputRef.value) {
|
|
|
|
inst.messageHistory.unshift(inst.chatInputRef.value);
|
|
|
|
inst.messageHistory = inst.messageHistory.slice(0, 20);
|
|
|
|
}
|
|
|
|
inst.messageHistoryPos = -1;
|
|
|
|
inst.tempInput = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch(err) {
|
|
|
|
t.log.capture(err);
|
|
|
|
t.log.error(err);
|
2019-07-31 22:26:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
originalOnMessageSend.call(this, event);
|
|
|
|
}
|
|
|
|
}
|
2018-04-07 19:09:32 -04:00
|
|
|
|
|
|
|
|
2019-06-28 04:54:58 +02:00
|
|
|
overrideMentionMatcher(inst) {
|
|
|
|
if ( inst._ffz_override )
|
|
|
|
return;
|
|
|
|
|
|
|
|
inst.canBeTriggeredByTab = !this.chat.context.get('chat.tab-complete.emotes-without-colon');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-07 19:09:32 -04:00
|
|
|
overrideEmoteMatcher(inst) {
|
|
|
|
if ( inst._ffz_override )
|
|
|
|
return;
|
|
|
|
|
2019-06-28 04:54:58 +02:00
|
|
|
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;
|
|
|
|
}
|
2018-04-07 19:09:32 -04:00
|
|
|
|
|
|
|
inst.doesEmoteMatchTerm = function(emote, term) {
|
|
|
|
const emote_name = emote.name || emote.token,
|
|
|
|
emote_lower = emote_name.toLowerCase(),
|
|
|
|
term_lower = term.toLowerCase();
|
|
|
|
|
|
|
|
if (emote_lower.startsWith(term_lower))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const idx = emote_name.indexOf(term.charAt(0).toUpperCase());
|
|
|
|
if (idx !== -1)
|
|
|
|
return emote_lower.slice(idx + 1).startsWith(term_lower.slice(1));
|
|
|
|
}
|
|
|
|
|
|
|
|
inst.getMatchedEmotes = function(input) {
|
2019-06-28 04:54:58 +02:00
|
|
|
const limitResults = t.chat.context.get('chat.tab-complete.limit-results');
|
|
|
|
let results = t.getTwitchEmoteSuggestions(input, this);
|
2019-06-30 15:05:05 -04:00
|
|
|
if ( limitResults && results.length >= 25 )
|
2019-07-31 22:25:21 +02:00
|
|
|
return t.sortFavorites(results).slice(0, 25);
|
2018-04-12 20:30:00 -04:00
|
|
|
|
2019-02-12 17:39:54 -05:00
|
|
|
if ( t.chat.context.get('chat.tab-complete.ffz-emotes') ) {
|
|
|
|
const ffz_emotes = t.getEmoteSuggestions(input, this);
|
|
|
|
if ( Array.isArray(ffz_emotes) && ffz_emotes.length )
|
2019-06-30 15:05:05 -04:00
|
|
|
results = results.concat(ffz_emotes);
|
2019-02-12 17:39:54 -05:00
|
|
|
}
|
2018-04-12 20:30:00 -04:00
|
|
|
|
2019-06-30 15:05:05 -04:00
|
|
|
if ( limitResults && results.length >= 25 )
|
2019-07-31 22:25:21 +02:00
|
|
|
return t.sortFavorites(results).slice(0, 25);
|
2019-06-30 15:05:05 -04:00
|
|
|
|
2018-04-12 20:30:00 -04:00
|
|
|
if ( ! t.chat.context.get('chat.tab-complete.emoji') )
|
2019-06-30 15:05:05 -04:00
|
|
|
return results;
|
2018-04-07 19:09:32 -04:00
|
|
|
|
2019-02-12 17:39:54 -05:00
|
|
|
const emoji = t.getEmojiSuggestions(input, this);
|
|
|
|
if ( Array.isArray(emoji) && emoji.length )
|
|
|
|
results = Array.isArray(results) ? results.concat(emoji) : emoji;
|
|
|
|
|
2019-07-31 22:25:21 +02:00
|
|
|
results = t.sortFavorites(results);
|
2019-06-28 04:54:58 +02:00
|
|
|
return limitResults && results.length > 25 ? results.slice(0, 25) : results;
|
2018-04-12 20:30:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
const React = this.web_munch.getModule('react'),
|
|
|
|
createElement = React && React.createElement;
|
|
|
|
|
|
|
|
inst.renderFFZEmojiSuggestion = function(data) {
|
2019-02-12 17:39:54 -05:00
|
|
|
return (<React.Fragment>
|
2019-08-05 23:12:50 +02:00
|
|
|
<div class="tw-relative tw-flex-shrink-0 tw-pd-05" title={data.token} favorite={data.favorite}>
|
2018-04-12 20:30:00 -04:00
|
|
|
<img
|
|
|
|
class="emote-autocomplete-provider__image ffz-emoji"
|
|
|
|
src={data.src}
|
|
|
|
srcSet={data.srcset}
|
|
|
|
/>
|
2019-07-31 22:25:21 +02:00
|
|
|
{data.favorite && <figure class="ffz--favorite ffz-i-star" />}
|
2019-02-12 17:39:54 -05:00
|
|
|
</div>
|
2019-07-31 22:25:21 +02:00
|
|
|
<div class="tw-ellipsis" title={data.token}>
|
2018-04-12 20:30:00 -04:00
|
|
|
{data.token}
|
|
|
|
</div>
|
2019-02-12 17:39:54 -05:00
|
|
|
</React.Fragment>);
|
2018-04-07 19:09:32 -04:00
|
|
|
}
|
2019-07-31 22:25:21 +02:00
|
|
|
|
|
|
|
inst.renderEmoteSuggestion = function(emote) {
|
|
|
|
return (<React.Fragment>
|
2019-08-05 23:12:50 +02:00
|
|
|
<div class="tw-relative tw-flex-shrink-0 tw-pd-05" title={emote.token} favorite={emote.favorite}>
|
2019-07-31 22:25:21 +02:00
|
|
|
<img
|
|
|
|
class="emote-autocomplete-provider__image"
|
|
|
|
srcSet={emote.srcSet}
|
|
|
|
/>
|
|
|
|
{emote.favorite && <figure class="ffz--favorite ffz-i-star" />}
|
|
|
|
</div>
|
|
|
|
<div class="tw-ellipsis" title={emote.token}>
|
|
|
|
{emote.token}
|
|
|
|
</div>
|
|
|
|
</React.Fragment>);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// eslint-disable-next-line class-methods-use-this
|
|
|
|
sortFavorites(results) {
|
|
|
|
if (!this.chat.context.get('chat.tab-complete.prioritize-favorites')) {
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
return results.sort((a, b) => {
|
|
|
|
const a_fav = a.favorite;
|
|
|
|
const b_fav = b.favorite;
|
|
|
|
if (a_fav) {
|
|
|
|
return b_fav ? a.replacement.localeCompare(b.replacement) : -1;
|
|
|
|
}
|
|
|
|
else if (b_fav) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a.replacement.localeCompare(b.replacement)
|
|
|
|
}
|
|
|
|
});
|
2018-04-07 19:09:32 -04:00
|
|
|
}
|
|
|
|
|
2019-06-27 23:19:05 -04:00
|
|
|
|
2019-06-28 04:54:58 +02:00
|
|
|
// eslint-disable-next-line class-methods-use-this
|
|
|
|
getTwitchEmoteSuggestions(input, inst) {
|
|
|
|
const hydratedEmotes = inst.hydrateEmotes(inst.props.emotes);
|
|
|
|
if (!Array.isArray(hydratedEmotes)) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2019-07-31 22:25:21 +02:00
|
|
|
const usageResults = [],
|
|
|
|
startingResults = [],
|
|
|
|
otherResults = [],
|
|
|
|
favorites = this.emotes.getFavorites('twitch'),
|
|
|
|
search = input.startsWith(':') ? input.slice(1) : input;
|
|
|
|
|
2019-06-28 04:54:58 +02:00
|
|
|
for (const set of hydratedEmotes) {
|
|
|
|
if (set && Array.isArray(set.emotes)) {
|
|
|
|
for (const emote of set.emotes) {
|
|
|
|
if (inst.doesEmoteMatchTerm(emote, search)) {
|
2019-07-31 22:25:21 +02:00
|
|
|
const favorite = favorites.includes(parseInt(emote.id, 10));
|
2019-06-30 20:55:53 +02:00
|
|
|
const element = {
|
2019-06-28 04:54:58 +02:00
|
|
|
current: input,
|
|
|
|
replacement: emote.token,
|
2019-07-31 22:25:21 +02:00
|
|
|
element: inst.renderEmoteSuggestion({
|
|
|
|
...emote,
|
|
|
|
favorite
|
|
|
|
}),
|
|
|
|
favorite
|
2019-06-30 20:55:53 +02:00
|
|
|
};
|
|
|
|
|
2019-07-31 22:25:21 +02:00
|
|
|
if (this.EmoteUsageCount[emote.token]) {
|
|
|
|
usageResults.push(element);
|
|
|
|
}
|
|
|
|
else if (emote.token.toLowerCase().startsWith(search)) {
|
2019-06-30 20:55:53 +02:00
|
|
|
startingResults.push(element);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
otherResults.push(element);
|
|
|
|
}
|
2019-06-28 04:54:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-06-30 20:55:53 +02:00
|
|
|
|
2019-07-31 22:25:21 +02:00
|
|
|
usageResults.sort((a, b) => this.EmoteUsageCount[b.replacement] - this.EmoteUsageCount[a.replacement]);
|
|
|
|
startingResults.sort((a, b) => a.replacement.localeCompare(b.replacement));
|
|
|
|
otherResults.sort((a, b) => a.replacement.localeCompare(b.replacement));
|
2019-06-30 20:55:53 +02:00
|
|
|
|
2019-07-31 22:25:21 +02:00
|
|
|
return usageResults.concat(startingResults).concat(otherResults);
|
2019-06-28 04:54:58 +02:00
|
|
|
}
|
|
|
|
|
2018-04-07 19:09:32 -04:00
|
|
|
|
2018-04-12 20:30:00 -04:00
|
|
|
getEmojiSuggestions(input, inst) {
|
2019-06-28 04:54:58 +02:00
|
|
|
if (!input.startsWith(':')) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2018-04-13 00:16:58 -04:00
|
|
|
let search = input.slice(1).toLowerCase();
|
|
|
|
const style = this.chat.context.get('chat.emoji.style'),
|
2018-07-26 19:40:53 -04:00
|
|
|
tone = this.settings.provider.get('emoji-tone', null),
|
2019-07-31 22:25:21 +02:00
|
|
|
favorites = this.emotes.getFavorites('emoji'),
|
2018-04-15 17:19:22 -04:00
|
|
|
results = [],
|
|
|
|
has_colon = search.endsWith(':');
|
2018-04-12 20:30:00 -04:00
|
|
|
|
2018-04-15 17:19:22 -04:00
|
|
|
if ( has_colon )
|
|
|
|
search = search.slice(0,-1);
|
2018-04-13 00:16:58 -04:00
|
|
|
|
2018-04-12 20:30:00 -04:00
|
|
|
for(const name in this.emoji.names)
|
2018-04-15 17:19:22 -04:00
|
|
|
if ( has_colon ? name === search : name.startsWith(search) ) {
|
2018-07-26 19:40:53 -04:00
|
|
|
const emoji = this.emoji.emoji[this.emoji.names[name]],
|
|
|
|
toned = emoji.variants && emoji.variants[tone],
|
|
|
|
source = toned || emoji;
|
|
|
|
|
2019-07-31 22:25:21 +02:00
|
|
|
if ( emoji && (style === 0 || source.has[style]) ) {
|
|
|
|
const favorite = favorites.includes(emoji.code);
|
2018-04-12 20:30:00 -04:00
|
|
|
results.push({
|
|
|
|
current: input,
|
2018-07-26 19:40:53 -04:00
|
|
|
replacement: source.raw,
|
2018-04-12 20:30:00 -04:00
|
|
|
element: inst.renderFFZEmojiSuggestion({
|
|
|
|
token: `:${name}:`,
|
|
|
|
id: `emoji-${emoji.code}`,
|
2018-07-26 19:40:53 -04:00
|
|
|
src: this.emoji.getFullImage(source.image, style),
|
2019-07-31 22:25:21 +02:00
|
|
|
srcSet: this.emoji.getFullImageSet(source.image, style),
|
|
|
|
favorite
|
|
|
|
}),
|
|
|
|
favorite
|
2018-04-12 20:30:00 -04:00
|
|
|
});
|
2019-07-31 22:25:21 +02:00
|
|
|
}
|
2018-04-12 20:30:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-07 19:09:32 -04:00
|
|
|
getEmoteSuggestions(input, inst) {
|
|
|
|
const user = inst._ffz_user,
|
|
|
|
channel_id = inst._ffz_channel_id,
|
|
|
|
channel_login = inst._ffz_channel_login;
|
|
|
|
|
|
|
|
if ( ! channel_login ) {
|
2019-03-26 17:37:00 -04:00
|
|
|
const parent = this.fine.searchParent(inst, 'chat-input', 50);
|
2018-04-07 19:09:32 -04:00
|
|
|
if ( parent )
|
|
|
|
this.updateEmoteCompletion(parent, inst);
|
|
|
|
|
|
|
|
if ( ! channel_login )
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2019-06-28 04:54:58 +02:00
|
|
|
const search = input.startsWith(':') ? input.slice(1) : input,
|
2018-04-07 19:09:32 -04:00
|
|
|
results = [],
|
|
|
|
emotes = this.emotes.getEmotes(
|
|
|
|
user && user.id,
|
|
|
|
user && user.login,
|
|
|
|
channel_id,
|
|
|
|
channel_login
|
|
|
|
);
|
|
|
|
|
|
|
|
for(const emote of Object.values(emotes))
|
2019-07-31 22:25:21 +02:00
|
|
|
if ( inst.doesEmoteMatchTerm(emote, search) ) {
|
|
|
|
const favorite = this.emotes.isFavorite(emote.token.provider, emote.id);
|
2018-04-07 19:09:32 -04:00
|
|
|
results.push({
|
|
|
|
current: input,
|
|
|
|
replacement: emote.name,
|
|
|
|
element: inst.renderEmoteSuggestion({
|
|
|
|
token: emote.name,
|
|
|
|
id: `${emote.token.provider}-${emote.id}`,
|
2019-07-31 22:25:21 +02:00
|
|
|
srcSet: emote.srcSet,
|
|
|
|
favorite
|
|
|
|
}),
|
|
|
|
favorite
|
2018-04-07 19:09:32 -04:00
|
|
|
});
|
2019-07-31 22:25:21 +02:00
|
|
|
}
|
2018-04-07 19:09:32 -04:00
|
|
|
|
|
|
|
return results;
|
|
|
|
}
|
2019-06-27 23:19:05 -04:00
|
|
|
|
|
|
|
pasteMessage(room, message) {
|
|
|
|
for(const inst of this.ChatInput.instances) {
|
|
|
|
if ( inst?.props?.channelLogin !== room )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ( ! inst.autocompleteInputRef || ! inst.state )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( inst.state.value )
|
|
|
|
message = `${inst.state.value} ${message}`;
|
|
|
|
|
|
|
|
inst.autocompleteInputRef.setValue(message);
|
|
|
|
inst.autocompleteInputRef.componentRef?.focus?.();
|
|
|
|
}
|
|
|
|
}
|
2018-04-07 19:09:32 -04:00
|
|
|
}
|