1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-07-03 01:28:30 +00:00

Refactor chat line rendering to support lines with system messages, making it possible to customize the rendering of re-sub messages and eventually other types, like purchases. Fix the emote data structure being all screwed up in self-sent /me commands.

This commit is contained in:
SirStendec 2017-11-23 02:49:23 -05:00
parent 6c4966166a
commit 2e5fe7f177
7 changed files with 173 additions and 73 deletions

View file

@ -1,3 +1,9 @@
<div class="list-header">4.0.0-beta1.3<span>@7493d51cfb8e1b4448f0</span> <time datetime="2017-11-23">(2017-11-23)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Emoticons not appearing for yourself when you send a message with <code>/me</code></li>
<li>Changed: Transform re-sub notices into a standard chat message so that we can override the rendering. This fixes colors, emotes, etc.</li>
</ul>
<div class="list-header">4.0.0-beta1.3<span>@da5b35d5323e5151e3ea</span> <time datetime="2017-11-22">(2017-11-22)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Add a touch scroll event handler for chat scrolling, as Twitch left that out for some reason.</li>

View file

@ -5,21 +5,15 @@
// ============================================================================
import {sanitize, createElement as e} from 'utilities/dom';
import {has} from 'utilities/object';
import {has, split_chars} from 'utilities/object';
const EMOTE_CLASS = 'chat-line__message--emote',
LINK_REGEX = /([^\w@#%\-+=:~])?((?:(https?:\/\/)?(?:[\w@#%\-+=:~]+\.)+[a-z]{2,6}(?:\/[\w.\/@#%&()\-+=:?~]*)?))([^\w.\/@#%&()\-+=:?~]|\s|$)/g,
MENTION_REGEX = /([^\w@#%\-+=:~])?(@([^\u0000-\u007F]+|\w+)+)([^\w.\/@#%&()\-+=:?~]|\s|$)/g,
SPLIT_REGEX = /[^\uD800-\uDFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDFFF]/g,
TWITCH_BASE = '//static-cdn.jtvnw.net/emoticons/v1/';
function split_chars(str) {
return str.match(SPLIT_REGEX);
}
// ============================================================================
// Links
// ============================================================================

View file

@ -6,7 +6,7 @@
import {ColorAdjuster} from 'utilities/color';
import {setChildren} from 'utilities/dom';
import {has} from 'utilities/object';
import {has, split_chars} from 'utilities/object';
import Module from 'utilities/module';
@ -70,7 +70,8 @@ const EVENTS = [
'onBanEvent',
'onModerationEvent',
'onSubscriptionEvent',
'onResubscriptionEvent',
//'onResubscriptionEvent',
'onSubscriptionGiftEvent',
'onRoomStateEvent',
'onSlowModeEvent',
'onFollowerOnlyModeEvent',
@ -408,6 +409,24 @@ export default class ChatHook extends Module {
}
}
const old_resub = this.onResubscriptionEvent;
this.onResubscriptionEvent = function(e) {
try {
const out = i.convertMessage({message: e});
out.ffz_type = 'resub';
out.sub_months = e.months;
out.sub_plan = e.methods;
i._wrapped = e;
const ret = i.postMessage(out);
i._wrapped = null;
return ret;
} catch(err) {
return old_resub.call(i, e);
}
}
this.postMessage = function(e) {
const original = this._wrapped;
if ( original ) {
@ -420,13 +439,20 @@ export default class ChatHook extends Module {
e.roomLogin = c.charAt(0) === '#' ? c.slice(1) : c;
if ( original.message ) {
if ( original.action )
e.message = original.action;
else
e.message = original.message.body;
const u = original.message.user;
if ( u )
e.emotes = u.emotes;
if ( original.message.user )
e.emotes = original.message.user.emotes;
if ( original.action ) {
e.message = original.action;
// Twitch doesn't generate a proper emote tag for echoed back
// actions, so we have to regenerate it. Fun. :D
if ( u && u.username === i.userLogin )
e.emotes = findEmotes(e.message, i.selfEmotes);
} else
e.message = original.message.body;
}
//e.original = original;
@ -671,6 +697,30 @@ export function formatBitsConfig(config) {
}
export function findEmotes(msg, emotes) {
const out = {};
let idx = 0;
for(const part of msg.split(' ')) {
const len = split_chars(part).length;
if ( has(emotes, part) ) {
const em = emotes[part],
matches = out[em.id] = out[em.id] || [];
matches.push({
startIndex: idx,
endIndex: idx + len - 1
});
}
idx += len + 1;
}
return out;
}
function extractCheerPrefix(parts) {
for(const part of parts) {
if ( part.type !== 3 || ! part.content.cheerAmount )

View file

@ -7,6 +7,12 @@
import Module from 'utilities/module';
//import {Color} from 'utilities/color';
const SUB_TIERS = {
1000: '$4.99',
2000: '$9.99',
3000: '$24.99'
};
export default class ChatLine extends Module {
constructor(...args) {
super(...args);
@ -72,16 +78,8 @@ export default class ChatLine extends Module {
const tokens = t.chat.tokenizeMessage(msg, {login: this.props.currentUserLogin, display: this.props.currentUserDisplayName}),
fragment = t.chat.renderTokens(tokens, e);
const out = e('div', {
className: `chat-line__message ${msg.mentioned ? 'ffz-mentioned' : ''}`,
//style: { backgroundColor: bg_css },
'data-room-id': this.props.channelID,
'data-room': room,
'data-user-id': user.userID,
'data-user': user.userLogin && user.userLogin.toLowerCase(),
//onClick: () => this.setState({renderDebug: ((this.state.renderDebug||0) + 1) % 3})
}, [
let cls = 'chat-line__message',
out = fragment.length ? [
this.props.showTimestamps && e('span', {
className: 'chat-line__timestamp'
}, t.chat.formatTime(msg.timestamp)),
@ -125,9 +123,50 @@ export default class ChatLine extends Module {
lineHeight: '1.1em'
}
}, JSON.stringify([tokens, msg.emotes], null, 2))*/
]);
] : null;
return out;
if ( msg.ffz_type === 'resub' ) {
const plan = msg.sub_plan || {},
months = msg.sub_months || 1,
tier = SUB_TIERS[plan.plan] || '$4.99';
cls = 'chat-line__subscribe';
out = [
e('span', null, [
t.i18n.t('chat.sub.main', '%{user} just subscribed with %{plan}!', {
user: user.userDisplayName,
plan: plan.prime ?
t.i18n.t('chat.sub.twitch-prime', 'Twitch Prime') :
t.i18n.t('chat.sub.plan', 'a %{tier} sub', {tier})
}),
months > 1 ?
` ${t.i18n.t(
'chat.sub.months',
'%{user} subscribed for %{count} months in a row!',
{
user: user.userDisplayName,
count: months
})}` : null
]),
out && e('div', {
className: 'chat-line__subscribe--message',
'data-room-id': this.props.channelID,
'data-room': room,
'data-user-id': user.userID,
'data-user': user.userLogin && user.userLogin.toLowerCase(),
}, out)
];
} else if ( ! out )
return null;
return e('div', {
className: `${cls}${msg.mentioned ? 'ffz-mentioned' : ''}`,
'data-room-id': this.props.channelID,
'data-room': room,
'data-user-id': user.userID,
'data-user': user.userLogin && user.userLogin.toLowerCase(),
}, out);
}
for(const inst of instances)

View file

@ -1,5 +1,6 @@
.chat-line__message.ffz-mentioned {
&:nth-child(2n+0) {
.chat-line__message,
.chat-line__subscribe {
&.ffz-mentioned:nth-child(2n+0) {
background-color: rgba(255,127,127,.4);
.theme--dark & {

View file

@ -1,7 +1,10 @@
.chat-line__message.ffz-mentioned {
.chat-line__message,
.chat-line__subscribe {
&.ffz-mentioned {
background-color: rgba(255,127,127,.2);
.theme--dark & {
background-color: rgba(255,0,0,.2);
}
}
}

View file

@ -167,6 +167,13 @@ export function maybe_call(fn, ctx, ...args) {
}
const SPLIT_REGEX = /[^\uD800-\uDFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDFFF]/g;
export function split_chars(str) {
return str.match(SPLIT_REGEX);
}
export class SourcedSet {
constructor() {
this._cache = [];