1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-28 15:27:43 +00:00

4.0.0-rc13.22

* Added: Support for clicking Twitch emotes to open information cards.
* Added: Option to allow clicking blocked terms in chat to reveal the term.
* Fixed: Twitch Experiments not being detected properly.
This commit is contained in:
SirStendec 2019-01-18 19:07:57 -05:00
parent 360d19e4bf
commit 9b95efb459
7 changed files with 265 additions and 21 deletions

View file

@ -149,7 +149,7 @@ ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}`
FrankerFaceZ.Logger = Logger;
const VER = FrankerFaceZ.version_info = {
major: 4, minor: 0, revision: 0, extra: '-rc13.21',
major: 4, minor: 0, revision: 0, extra: '-rc13.22',
commit: __git_commit__,
build: __webpack_hash__,
toString: () =>

View file

@ -0,0 +1,10 @@
<template functional>
<strong
:data-text="props.token.text"
:data-categories="JSON.stringify(props.token.categories)"
data-tooltip-type="amterm"
class="ffz-tooltip ffz--blocked"
>
&times;&times;&times;
</strong>
</template>

View file

@ -93,6 +93,33 @@ export default class Emotes extends Module {
}
});
this.settings.add('chat.click-emotes', {
default: true,
ui: {
path: 'Chat > Behavior >> General',
title: 'Open emote information pages by Shift-Clicking them.',
component: 'setting-check-box'
}
});
this.settings.add('chat.sub-emotes', {
default: true,
ui: {
path: 'Chat > Behavior >> General',
title: 'Open Twitch subscription pages by Shift-Clicking emotes when relevant.',
component: 'setting-check-box'
}
});
this.settings.add('chat.emote-dialogs', {
default: true,
ui: {
path: 'Chat > Behavior >> General',
title: 'Open emote information cards for Twitch emotes by clicking them.',
component: 'setting-check-box'
}
});
// Because this may be used elsewhere.
this.handleClick = this.handleClick.bind(this);
@ -303,6 +330,29 @@ export default class Emotes extends Module {
return true;
}
if ( provider === 'twitch' && this.parent.context.get('chat.emote-dialogs') ) {
const fine = this.resolve('site.fine');
if ( ! fine )
return;
const chat = fine.searchParent(target, n => n.props && n.props.onEmoteClick);
if ( ! chat || ! chat.props || ! chat.props.message )
return;
const props = chat.props;
props.onEmoteClick({
channelID: props.channelID || '',
channelLogin: props.channelLogin || '',
emoteID: ds.id,
emoteCode: target.alt,
sourceID: 'chat',
referrerID: '',
initialTopOffset: target.getBoundingClientRect().bottom
});
return true;
}
}

View file

@ -43,6 +43,9 @@ export default class Chat extends Module {
this._link_info = {};
// Bind for JSX stuff
this.clickToReveal = this.clickToReveal.bind(this);
this.style = new ManagedStyle;
this.context = this.settings.context({});
@ -169,6 +172,15 @@ export default class Chat extends Module {
}
});
this.settings.add('chat.filtering.click-to-reveal', {
default: false,
ui: {
path: 'Chat > Filtering >> Behavior',
title: 'Click to reveal deleted terms.',
component: 'setting-check-box'
}
});
this.settings.add('chat.filtering.show-deleted', {
default: false,
ui: {
@ -540,25 +552,6 @@ export default class Chat extends Module {
}
});
this.settings.add('chat.click-emotes', {
default: true,
ui: {
path: 'Chat > Behavior >> General',
title: 'Open emote information pages by Shift-Clicking them.',
component: 'setting-check-box'
}
});
this.settings.add('chat.sub-emotes', {
default: true,
ui: {
path: 'Chat > Behavior >> General',
title: 'Open Twitch subscription pages by Shift-Clicking emotes when relevant.',
component: 'setting-check-box'
}
});
const ts = new Date(0).toLocaleTimeString().toUpperCase(),
default_24 = ts.lastIndexOf('PM') === -1 && ts.lastIndexOf('AM') === -1;
@ -758,6 +751,21 @@ export default class Chat extends Module {
}
clickToReveal(event) {
const target = event.target;
if ( target ) {
if ( target._ffz_visible )
target.textContent = '×××';
else if ( ! this.context.get('chat.filtering.click-to-reveal') )
return;
else if ( target.dataset )
target.textContent = target.dataset.text;
target._ffz_visible = ! target._ffz_visible;
}
}
standardizeWhisper(msg) { // eslint-disable-line class-methods-use-this
if ( ! msg )
return msg;

View file

@ -382,6 +382,7 @@ export const BlockedTerms = {
data-text={token.text}
data-tooltip-type="blocked"
class="ffz-tooltip ffz--blocked"
onClick={this.clickToReveal}
>
&times;&times;&times;
</strong>);
@ -419,6 +420,172 @@ export const BlockedTerms = {
}
// ============================================================================
// AutoMod Filtering
// ============================================================================
const AM_DESCRIPTIONS = {
A: 'Hostility',
I: 'Discrimination',
P: 'Profanity',
S: 'Sexually Explicit Language'
};
export const AutomoddedTerms = {
type: 'amterm',
priority: 99,
component: () => import(/* webpackChunkName: 'vue-chat' */ './components/chat-automod-blocked.vue'),
render(token, createElement) {
return (<strong
data-text={token.text}
data-categories={JSON.stringify(token.categories)}
data-tooltip-type="amterm"
class="ffz-tooltip ffz--blocked"
onClick={this.clickToReveal}
>
&times;&times;&times;
</strong>);
},
tooltip(target) {
const ds = target.dataset,
flags = [];
let cats;
try {
cats = JSON.parse(ds.categories);
for(const key in cats) {
if ( cats[key] && AM_DESCRIPTIONS[key] )
flags.push(this.i18n.t(`chat.filtering.automod.${key}`, AM_DESCRIPTIONS[key]))
}
} catch(err) {
flags.push('Parse Error');
}
return [
(<div class="tw-border-b tw-mg-b-05">{ // eslint-disable-line react/jsx-key
this.i18n.t('chat.filtering.automod-term', 'AutoMod Blocked Term')
}</div>),
this.i18n.t('chat.filtering.automod-why', 'This was flagged as: '),
flags.join(', ')
];
},
process(tokens, msg) {
if ( ! tokens || ! tokens.length || ! msg.flags || ! Array.isArray(msg.flags.list) )
return tokens;
const cats = msg.flags.preferences,
flagged = msg.flags.list.filter(x => {
if ( ! x || x.startIndex == null || x.endIndex == null )
return false;
const y = x.categories;
if ( ! y )
return false;
for(const key in y) {
if ( y[key] && cats[key] )
return true;
}
}),
f_length = flagged.length;
if ( ! f_length )
return tokens;
const out = [];
let idx = 0,
fix = 0;
for(const token of tokens) {
const length = token.length || (token.text && split_chars(token.text).length) || 0,
t_start = idx,
t_end = idx + length;
if ( token.type !== 'text' ) {
out.push(token);
idx = t_end;
continue;
}
const text = split_chars(token.text);
while ( fix < f_length ) {
const flag = flagged[fix],
f_start = flag.startIndex,
f_end = flag.endIndex + 1;
// Did this flagged term already end? Skip it!
if ( f_end < t_start ) {
fix++;
continue;
}
// Does this flagged term start after this token?
if ( f_start > t_end ) {
// Just dump this token and move on.
out.push(token);
idx = t_end;
break;
}
// If there's text at the beginning of the token that isn't part of
// this flagged term, output it.
if ( f_start > idx )
out.push({
type: 'text',
text: text.slice(idx - t_start, f_start - t_start).join('')
});
// Clamp the start of the filtered term to the start of this token.
let fs = f_start - t_start;
if ( fs < 0 )
fs = 0;
// Add the token.
out.push({
type: 'amterm',
categories: flag.categories,
text: text.slice(fs, f_end - t_start).join('')
});
// Does this flagged term extend past the end of this token?
if ( f_end > t_end ) {
// Don't go to the next term, just continue processing on the
// next token.
idx = t_end;
break;
}
idx = f_end;
fix++;
}
// We've finished processing terms. If there's any remaining
// text in the token, push it out.
if ( idx < t_end ) {
if ( t_start === idx )
out.push(token);
else
out.push({
type: 'text',
text: text.slice(idx - t_start).join('')
});
idx = t_end;
}
}
return out;
}
}
// ============================================================================
// Cheers

View file

@ -143,6 +143,10 @@ export default class Twilight extends BaseSite {
core = this.web_munch.getModule('core-2');
if ( core )
return this._core = core.p;
core = this.web_munch.getModule('core-3');
if ( core )
return this._core = core.q;
}
}
@ -152,6 +156,7 @@ Twilight.KNOWN_MODULES = {
react: n => n.Component && n.createElement,
'core-1': n => n.o && n.o.experiments,
'core-2': n => n.p && n.p.experiments,
'core-3': n => n.q && n.q.experiments,
cookie: n => n && n.set && n.get && n.getJSON && n.withConverter,
'extension-service': n => n.extensionService,
'chat-types': n => n.b && has(n.b, 'Message') && has(n.b, 'RoomMods'),

View file

@ -954,10 +954,14 @@ export default class ChatHook extends Module {
}
if ( original.message ) {
const user = original.message.user;
const user = original.message.user,
flags = original.message.flags;
if ( user )
message.emotes = user.emotes;
if ( flags && this.getFilterFlagOptions )
message.flags = this.getFilterFlagOptions(flags);
if ( typeof original.action === 'string' )
message.message = original.action;
else