diff --git a/src/main.js b/src/main.js index 6f5fec4d..0fcc7485 100644 --- a/src/main.js +++ b/src/main.js @@ -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: () => diff --git a/src/modules/chat/components/chat-automod-blocked.vue b/src/modules/chat/components/chat-automod-blocked.vue new file mode 100644 index 00000000..2b625d98 --- /dev/null +++ b/src/modules/chat/components/chat-automod-blocked.vue @@ -0,0 +1,10 @@ + + + ××× + + \ No newline at end of file diff --git a/src/modules/chat/emotes.js b/src/modules/chat/emotes.js index b0e45b16..cfc6e554 100644 --- a/src/modules/chat/emotes.js +++ b/src/modules/chat/emotes.js @@ -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; + } } diff --git a/src/modules/chat/index.js b/src/modules/chat/index.js index 15a6cfbb..f41dd127 100644 --- a/src/modules/chat/index.js +++ b/src/modules/chat/index.js @@ -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; diff --git a/src/modules/chat/tokenizers.jsx b/src/modules/chat/tokenizers.jsx index 2d86e5d1..7cb50c39 100644 --- a/src/modules/chat/tokenizers.jsx +++ b/src/modules/chat/tokenizers.jsx @@ -382,6 +382,7 @@ export const BlockedTerms = { data-text={token.text} data-tooltip-type="blocked" class="ffz-tooltip ffz--blocked" + onClick={this.clickToReveal} > ××× ); @@ -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 ( + ××× + ); + }, + + 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 [ + (