mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-03 00:18:31 +00:00
4.17.13
* Changed: Replace a few unnecessary menu components that only display markdown with a generic component. * Changed: Initial work for letting users override display names and user colors in chat. * Changed: The FFZ menu button no longer depends on add-ons being loaded to load itself. * Fixed: Rendering of highlighted messages in Chat on Videos. * Fixed: Featured channels menu not working when a bad channel is in the list.
This commit is contained in:
parent
c91822cdc9
commit
3cbe4ee2fc
19 changed files with 284 additions and 228 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "frankerfacez",
|
||||
"author": "Dan Salvato LLC",
|
||||
"version": "4.17.12",
|
||||
"version": "4.17.13",
|
||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
|
|
|
@ -13,6 +13,7 @@ import {timeout, has, glob_to_regex, escape_regex, split_chars} from 'utilities/
|
|||
import Badges from './badges';
|
||||
import Emotes from './emotes';
|
||||
import Emoji from './emoji';
|
||||
import Overrides from './overrides';
|
||||
|
||||
import Room from './room';
|
||||
import User from './user';
|
||||
|
@ -40,6 +41,7 @@ export default class Chat extends Module {
|
|||
this.inject(Emotes);
|
||||
this.inject(Emoji);
|
||||
this.inject(Actions);
|
||||
this.inject(Overrides);
|
||||
|
||||
this._link_info = {};
|
||||
|
||||
|
|
133
src/modules/chat/overrides.js
Normal file
133
src/modules/chat/overrides.js
Normal file
|
@ -0,0 +1,133 @@
|
|||
'use strict';
|
||||
|
||||
// ============================================================================
|
||||
// Name and Color Overrides
|
||||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
|
||||
|
||||
export default class Overrides extends Module {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
this.inject('settings');
|
||||
this.color_cache = null;
|
||||
this.name_cache = null;
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
this.settings.provider.on('changed', this.onProviderChange, this);
|
||||
}
|
||||
|
||||
onProviderChange(key) {
|
||||
if ( key === 'overrides.colors' )
|
||||
this.loadColors();
|
||||
else if ( key === 'overrides.names' )
|
||||
this.loadNames();
|
||||
}
|
||||
|
||||
get colors() {
|
||||
if ( ! this.color_cache )
|
||||
this.loadColors();
|
||||
|
||||
return this.color_cache;
|
||||
}
|
||||
|
||||
get names() {
|
||||
if ( ! this.name_cache )
|
||||
this.loadNames();
|
||||
|
||||
return this.name_cache;
|
||||
}
|
||||
|
||||
loadColors() {
|
||||
let old_keys,
|
||||
loaded = true;
|
||||
if ( ! this.color_cache ) {
|
||||
loaded = false;
|
||||
this.color_cache = {};
|
||||
old_keys = new Set;
|
||||
} else
|
||||
old_keys = new Set(Object.keys(this.color_cache));
|
||||
|
||||
for(const [key, val] of Object.entries(this.settings.provider.get('overrides.colors', {}))) {
|
||||
old_keys.delete(key);
|
||||
if ( this.color_cache[key] !== val ) {
|
||||
this.color_cache[key] = val;
|
||||
if ( loaded )
|
||||
this.emit(':changed', key, 'color', val);
|
||||
}
|
||||
}
|
||||
|
||||
for(const key of old_keys) {
|
||||
this.color_cache[key] = undefined;
|
||||
if ( loaded )
|
||||
this.emit(':changed', key, 'color', undefined);
|
||||
}
|
||||
}
|
||||
|
||||
loadNames() {
|
||||
let old_keys,
|
||||
loaded = true;
|
||||
if ( ! this.name_cache ) {
|
||||
loaded = false;
|
||||
this.name_cache = {};
|
||||
old_keys = new Set;
|
||||
} else
|
||||
old_keys = new Set(Object.keys(this.name_cache));
|
||||
|
||||
for(const [key, val] of Object.entries(this.settings.provider.get('overrides.names', {}))) {
|
||||
old_keys.delete(key);
|
||||
if ( this.name_cache[key] !== val ) {
|
||||
this.name_cache[key] = val;
|
||||
if ( loaded )
|
||||
this.emit(':changed', key, 'name', val);
|
||||
}
|
||||
}
|
||||
|
||||
for(const key of old_keys) {
|
||||
this.name_cache[key] = undefined;
|
||||
if ( loaded )
|
||||
this.emit(':changed', key, 'name', undefined);
|
||||
}
|
||||
}
|
||||
|
||||
getColor(id) {
|
||||
if ( this.colors[id] != null )
|
||||
return this.colors[id];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
getName(id) {
|
||||
if ( this.names[id] != null )
|
||||
return this.names[id];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
setColor(id, color) {
|
||||
if ( this.colors[id] !== color ) {
|
||||
this.colors[id] = color;
|
||||
this.settings.provider.set('overrides.colors', this.colors);
|
||||
this.emit(':changed', id, 'color', color);
|
||||
}
|
||||
}
|
||||
|
||||
setName(id, name) {
|
||||
if ( this.names[id] !== name ) {
|
||||
this.names[id] = name;
|
||||
this.settings.provider.set('overrides.names', this.names);
|
||||
this.emit(':changed', id, 'name', name);
|
||||
}
|
||||
}
|
||||
|
||||
deleteColor(id) {
|
||||
this.setColor(id, undefined);
|
||||
}
|
||||
|
||||
deleteName(id) {
|
||||
this.setName(id, undefined);
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
<template lang="html">
|
||||
<div class="ffz--home tw-border-t tw-pd-y-1">
|
||||
<markdown :source="t('home.faq', md)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import FAQ_MD from '../faq.md';
|
||||
|
||||
export default {
|
||||
props: ['item', 'context'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
md: FAQ_MD
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,20 +0,0 @@
|
|||
<template lang="html">
|
||||
<div class="ffz--home tw-border-t tw-pd-y-1">
|
||||
<markdown :source="t('home.feedback', md)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import FEEDBACK_MD from '../feedback.md';
|
||||
|
||||
export default {
|
||||
props: ['item', 'context'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
md: FEEDBACK_MD
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,20 +0,0 @@
|
|||
<template lang="html">
|
||||
<div class="ffz--home tw-border-t tw-pd-y-1">
|
||||
<markdown :source="md" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import LEGAL_MD from '../legal.md';
|
||||
|
||||
export default {
|
||||
props: ['item', 'context'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
md: LEGAL_MD
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
36
src/modules/main_menu/components/md-page.vue
Normal file
36
src/modules/main_menu/components/md-page.vue
Normal file
|
@ -0,0 +1,36 @@
|
|||
<template lang="html">
|
||||
<div class="ffz--home tw-border-t tw-pd-y-1">
|
||||
<div v-if="loading" class="tw-align-center tw-pd-1">
|
||||
<h1 class="tw-mg-5 ffz-i-zreknarf loading" />
|
||||
</div>
|
||||
<markdown v-else :source="t(`home.${key}`, md)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: ['item', 'context'],
|
||||
|
||||
data() {
|
||||
const key = this.item.key;
|
||||
|
||||
return {
|
||||
key,
|
||||
loading: true,
|
||||
md: null
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.load();
|
||||
},
|
||||
|
||||
methods: {
|
||||
async load() {
|
||||
this.md = (await import(/* webpackChunkName: 'menu-md' */ `../${this.key}.md`)).default;
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -64,12 +64,21 @@ export default class MainMenu extends Module {
|
|||
|
||||
this.settings.addUI('faq', {
|
||||
path: 'Home > FAQ @{"profile_warning": false}',
|
||||
component: 'faq-page'
|
||||
component: 'md-page',
|
||||
key: 'faq'
|
||||
});
|
||||
|
||||
/*this.settings.addUI('privacy', {
|
||||
path: 'Home > Privacy @{"profile_warning": false}',
|
||||
component: 'md-page',
|
||||
key: 'privacy',
|
||||
force_seen: true
|
||||
});*/
|
||||
|
||||
this.settings.addUI('feedback', {
|
||||
path: 'Home > Feedback @{"profile_warning": false}',
|
||||
component: 'feedback-page'
|
||||
component: 'md-page',
|
||||
key: 'feedback'
|
||||
});
|
||||
|
||||
this.settings.addUI('feedback.log', {
|
||||
|
@ -96,7 +105,8 @@ export default class MainMenu extends Module {
|
|||
|
||||
this.settings.addUI('legal', {
|
||||
path: 'Home > Legal @{"sort": 1000}',
|
||||
component: 'legal-page',
|
||||
component: 'md-page',
|
||||
key: 'legal',
|
||||
force_seen: true
|
||||
});
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ export default class ChatHook extends Module {
|
|||
|
||||
this.GiftBanner = this.fine.define(
|
||||
'gift-banner',
|
||||
n => n.getBannerText && n.handleCountdownEnd && n.getRemainingTime,
|
||||
n => n.getBannerText && n.onGiftMoreClick,
|
||||
Twilight.CHAT_ROUTES
|
||||
);
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ export default class ChatLine extends Module {
|
|||
this.inject(RichContent);
|
||||
|
||||
this.inject('chat.actions');
|
||||
this.inject('chat.overrides');
|
||||
|
||||
this.ChatLine = this.fine.define(
|
||||
'chat-line',
|
||||
|
@ -46,18 +47,6 @@ export default class ChatLine extends Module {
|
|||
Twilight.CHAT_ROUTES
|
||||
);
|
||||
|
||||
/*this.ChatRoomLine = this.fine.define(
|
||||
'chat-room-line',
|
||||
n => n.renderMessageBody && n.props && ! n.onExtensionNameClick && has(n.props, 'hasModPermissions'),
|
||||
Twilight.CHAT_ROUTES
|
||||
);*/
|
||||
|
||||
/*this.ChatRoomContainer = this.fine.define(
|
||||
'chat-room-container',
|
||||
n => n.renderPlaceholders && n.sendRoomMessage && n.props && n.props.channel,
|
||||
Twilight.CHAT_ROUTES
|
||||
);*/
|
||||
|
||||
this.WhisperLine = this.fine.define(
|
||||
'whisper-line',
|
||||
n => n.props && n.props.message && n.props.reportOutgoingWhisperRendered
|
||||
|
@ -65,6 +54,8 @@ export default class ChatLine extends Module {
|
|||
}
|
||||
|
||||
async onEnable() {
|
||||
this.on('chat.overrides:changed', id => this.updateLinesByUser(id), this);
|
||||
|
||||
this.chat.context.on('changed:chat.emoji.style', this.updateLines, this);
|
||||
this.chat.context.on('changed:chat.bits.stack', this.updateLines, this);
|
||||
this.chat.context.on('changed:chat.badges.style', this.updateLines, this);
|
||||
|
@ -99,121 +90,6 @@ export default class ChatLine extends Module {
|
|||
FFZRichContent = this.rich_content && this.rich_content.RichContent;
|
||||
|
||||
|
||||
/*this.ChatRoomLine.ready(cls => {
|
||||
const old_render = cls.prototype.render;
|
||||
|
||||
cls.prototype.render = function() { try {
|
||||
this._ffz_no_scan = true;
|
||||
|
||||
const msg = t.chat.standardizeMessage(this.props.message),
|
||||
is_action = msg.is_action,
|
||||
|
||||
user = msg.user,
|
||||
color = t.parent.colors.process(user.color),
|
||||
show_deleted = t.chat.context.get('chat.filtering.show-deleted');
|
||||
|
||||
let show, show_class;
|
||||
|
||||
if ( show_deleted ) {
|
||||
show = true;
|
||||
show_class = msg.deleted;
|
||||
} else {
|
||||
show = this.state && this.state.shouldShowDeletedBody || ! msg.deleted;
|
||||
show_class = false;
|
||||
}
|
||||
|
||||
const u = t.site.getUser(),
|
||||
r = {id: null, login: null};
|
||||
|
||||
if ( u ) {
|
||||
u.moderator = this.props.hasModPermissions;
|
||||
}
|
||||
|
||||
// Find the parent element.
|
||||
const parent = this._ffz_parent = this._ffz_parent || t.fine.searchParent(this,
|
||||
n => (n.props && n.props.banStatusData && n.props.channelID) ||
|
||||
(n.renderPlaceholders && n.sendRoomMessage && n.props && n.props.channel), 50);
|
||||
|
||||
if ( parent != null ) {
|
||||
r.id = parent.props.channelID;
|
||||
r.login = parent.props.channelLogin;
|
||||
}
|
||||
|
||||
const tokens = msg.ffz_tokens = msg.ffz_tokens || t.chat.tokenizeMessage(msg, u, r),
|
||||
rich_content = FFZRichContent && t.chat.pluckRichContent(tokens, msg),
|
||||
bg_css = msg.mentioned && msg.mention_color ? t.parent.inverse_colors.process(msg.mention_color) : null;
|
||||
|
||||
if ( ! this.ffz_user_click_handler )
|
||||
this.ffz_user_click_handler = this.props.onUsernameClick;
|
||||
|
||||
const cls = `chat-line__message${show_class ? ' ffz--deleted-message' : ''}`,
|
||||
out = (tokens.length || ! msg.ffz_type) ? [
|
||||
this.props.showTimestamps && e('span', {
|
||||
className: 'chat-line__timestamp'
|
||||
}, t.chat.formatTime(msg.timestamp)),
|
||||
this.renderModerationIcons(),
|
||||
//t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
|
||||
e('span', {
|
||||
className: 'chat-line__message--badges'
|
||||
}, t.chat.badges.render(msg, e)),
|
||||
e('span', {
|
||||
className: 'chat-line__username notranslate',
|
||||
role: 'button',
|
||||
style: { color },
|
||||
onClick: this.ffz_user_click_handler
|
||||
}, [
|
||||
e('span', {
|
||||
className: 'chat-author__display-name'
|
||||
}, user.displayName),
|
||||
user.isIntl && e('span', {
|
||||
className: 'chat-author__intl-login'
|
||||
}, ` (${user.login})`)
|
||||
]),
|
||||
e('span', null, is_action ? ' ' : ': '),
|
||||
show ?
|
||||
e('span', {
|
||||
className: 'message',
|
||||
style: is_action ? { color } : null
|
||||
}, t.chat.renderTokens(tokens, e))
|
||||
:
|
||||
e('span', {
|
||||
className: 'chat-line__message--deleted'
|
||||
}, e('a', {
|
||||
href: '',
|
||||
onClick: this.showDeleted
|
||||
}, t.i18n.t('chat.message-deleted', '<message deleted>'))),
|
||||
|
||||
show && rich_content && e(FFZRichContent, rich_content)
|
||||
] : null;
|
||||
|
||||
if ( ! out )
|
||||
return null;
|
||||
|
||||
return e('div', {
|
||||
className: `${cls}${msg.mentioned ? ' ffz-mentioned' : ''}${bg_css ? ' ffz-custom-color' : ''}`,
|
||||
style: {backgroundColor: bg_css},
|
||||
'data-room-id': r.id,
|
||||
'data-room': r.login,
|
||||
'data-user-id': user.id,
|
||||
'data-user': user.login && user.login.toLowerCase()
|
||||
}, out);
|
||||
|
||||
} catch(err) {
|
||||
t.log.capture(err, {
|
||||
extra: {
|
||||
props: this.props
|
||||
}
|
||||
});
|
||||
|
||||
return old_render.call(this);
|
||||
} };
|
||||
|
||||
// Do this after a short delay to hopefully reduce the chance of React
|
||||
// freaking out on us.
|
||||
setTimeout(() => this.ChatRoomLine.forceUpdate());
|
||||
});*/
|
||||
|
||||
|
||||
this.WhisperLine.ready(cls => {
|
||||
const old_render = cls.prototype.render;
|
||||
|
||||
|
@ -227,19 +103,22 @@ export default class ChatLine extends Module {
|
|||
|
||||
is_action = msg.is_action,
|
||||
user = msg.user,
|
||||
color = t.parent.colors.process(user.color),
|
||||
raw_color = t.overrides.getColor(user.id) || user.color,
|
||||
color = t.parent.colors.process(raw_color),
|
||||
|
||||
tokens = msg.ffz_tokens = msg.ffz_tokens || t.chat.tokenizeMessage(msg, null, null),
|
||||
contents = t.chat.renderTokens(tokens, e);
|
||||
contents = t.chat.renderTokens(tokens, e),
|
||||
|
||||
override_name = t.overrides.getName(user.id);
|
||||
|
||||
return e('div', {className: 'thread-message__message'},
|
||||
e('div', {className: 'tw-pd-x-1 tw-pd-y-05'}, [
|
||||
e('span', {
|
||||
className: 'thread-message__message--user-name notranslate',
|
||||
className: `thread-message__message--user-name notranslate${override_name ? ' ffz--name-override' : ''}`,
|
||||
style: {
|
||||
color
|
||||
}
|
||||
}, user.displayName),
|
||||
}, override_name || user.displayName),
|
||||
e('span', null, is_action ? ' ' : ': '),
|
||||
e('span', {
|
||||
className: 'message',
|
||||
|
@ -290,7 +169,9 @@ export default class ChatLine extends Module {
|
|||
is_action = msg.messageType === types.Action,
|
||||
|
||||
user = msg.user,
|
||||
color = t.parent.colors.process(user.color);
|
||||
raw_color = t.overrides.getColor(user.id) || user.color,
|
||||
|
||||
color = t.parent.colors.process(raw_color);
|
||||
|
||||
let mod_mode = this.props.deletedMessageDisplay;
|
||||
let show, show_class, mod_action = null;
|
||||
|
@ -422,6 +303,19 @@ other {# messages were deleted by a moderator.}
|
|||
this.ffz_user_click_handler = this.openViewerCard || this.usernameClickHandler; //event => event.ctrlKey ? this.usernameClickHandler(event) : t.viewer_cards.openCard(r, user, event);
|
||||
}
|
||||
|
||||
|
||||
const user_block = [
|
||||
e('span', {
|
||||
className: 'chat-author__display-name'
|
||||
}, user.displayName),
|
||||
user.isIntl && e('span', {
|
||||
className: 'chat-author__intl-login'
|
||||
}, ` (${user.login})`)
|
||||
];
|
||||
|
||||
const override_name = t.overrides.getName(user.id);
|
||||
|
||||
|
||||
let cls = `chat-line__message${show_class ? ' ffz--deleted-message' : ''}`,
|
||||
out = (tokens.length || ! msg.ffz_type) ? [
|
||||
this.props.showTimestamps && e('span', {
|
||||
|
@ -432,19 +326,19 @@ other {# messages were deleted by a moderator.}
|
|||
className: 'chat-line__message--badges'
|
||||
}, t.chat.badges.render(msg, e)),
|
||||
e('span', {
|
||||
className: 'chat-line__username notranslate',
|
||||
className: `chat-line__username notranslate${override_name ? ' ffz--name-override tw-relative tw-tooltip-wrapper' : ''}`,
|
||||
role: 'button',
|
||||
style: { color },
|
||||
onClick: this.ffz_user_click_handler,
|
||||
onContextMenu: t.actions.handleUserContext
|
||||
}, [
|
||||
}, override_name ? [
|
||||
e('span', {
|
||||
className: 'chat-author__display-name'
|
||||
}, user.displayName),
|
||||
user.isIntl && e('span', {
|
||||
className: 'chat-author__intl-login'
|
||||
}, ` (${user.login})`)
|
||||
]),
|
||||
className: 'chat-author__display_name'
|
||||
}, override_name),
|
||||
e('div', {
|
||||
className: 'tw-tooltip tw-tooltip--down tw-tooltip--align-center'
|
||||
}, user_block)
|
||||
] : user_block),
|
||||
e('span', null, is_action ? ' ' : ': '),
|
||||
show ?
|
||||
e('span', {
|
||||
|
@ -859,6 +753,23 @@ other {# messages were deleted by a moderator.}
|
|||
}
|
||||
|
||||
|
||||
updateLinesByUser(id, login) {
|
||||
for(const inst of this.ChatLine.instances) {
|
||||
const msg = inst.props.message,
|
||||
user = msg?.user;
|
||||
if ( user && (id && id == user.id) || (login && login == user.login) )
|
||||
inst.forceUpdate();
|
||||
}
|
||||
|
||||
for(const inst of this.WhisperLine.instances) {
|
||||
const msg = inst.props.message?._ffz_message,
|
||||
user = msg?.user;
|
||||
if ( user && (id && id == user.id) || (login && login == user.login) )
|
||||
inst.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
maybeUpdateLines() {
|
||||
if ( this.chat.context.get('chat.rich.all-links') )
|
||||
this.updateLines();
|
||||
|
@ -881,14 +792,6 @@ other {# messages were deleted by a moderator.}
|
|||
}
|
||||
}
|
||||
|
||||
/*for(const inst of this.ChatRoomLine.instances) {
|
||||
const msg = inst.props.message;
|
||||
if ( msg ) {
|
||||
msg.ffz_tokens = null;
|
||||
msg.mentioned = msg.mention_color = null;
|
||||
}
|
||||
}*/
|
||||
|
||||
for(const inst of this.WhisperLine.instances) {
|
||||
const msg = inst.props.message;
|
||||
if ( msg && msg._ffz_message )
|
||||
|
@ -897,7 +800,6 @@ other {# messages were deleted by a moderator.}
|
|||
|
||||
this.ChatLine.forceUpdate();
|
||||
this.ExtensionLine.forceUpdate();
|
||||
//this.ChatRoomLine.forceUpdate();
|
||||
this.WhisperLine.forceUpdate();
|
||||
|
||||
this.emit('chat:updated-lines');
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.video-chat__message-list-wrapper li:nth-child(2n+0) .ffz--points-highlight,
|
||||
.ffz--points-highlight:nth-child(2n+0) {
|
||||
background-color: var(--ffz-channel-color-30);
|
||||
}
|
|
@ -109,7 +109,7 @@ export default class FeaturedFollow extends Module {
|
|||
follows = {};
|
||||
|
||||
for (const user of ap_data.data.users) {
|
||||
if ( ! user.id )
|
||||
if ( ! user || ! user.id )
|
||||
continue;
|
||||
|
||||
follows[user.id] = {
|
||||
|
|
|
@ -18,7 +18,7 @@ export default class MenuButton extends SiteModule {
|
|||
this.inject('i18n');
|
||||
this.inject('settings');
|
||||
this.inject('site.fine');
|
||||
this.inject('addons');
|
||||
//this.inject('addons');
|
||||
|
||||
this.should_enable = true;
|
||||
this._pill_content = null;
|
||||
|
@ -158,13 +158,15 @@ export default class MenuButton extends SiteModule {
|
|||
if ( this.has_strings )
|
||||
return this.i18n.formatNumber(this.i18n.new_strings + this.i18n.changed_strings);
|
||||
|
||||
if ( DEBUG && this.addons.has_dev )
|
||||
const addons = this.resolve('addons');
|
||||
|
||||
if ( DEBUG && addons.has_dev )
|
||||
return this.i18n.t('site.menu_button.dev', 'dev');
|
||||
|
||||
if ( DEBUG && ! this.addons.has_dev )
|
||||
if ( DEBUG && ! addons.has_dev )
|
||||
return this.i18n.t('site.menu_button.main-dev', 'm-dev');
|
||||
|
||||
if ( ! DEBUG && this.addons.has_dev )
|
||||
if ( ! DEBUG && addons.has_dev )
|
||||
return this.i18n.t('site.menu_button.addon-dev', 'a-dev');
|
||||
|
||||
return null;
|
||||
|
@ -263,7 +265,8 @@ export default class MenuButton extends SiteModule {
|
|||
if ( el )
|
||||
el.remove();
|
||||
|
||||
const pill = this.formatPill(),
|
||||
const addons = this.resolve('addons'),
|
||||
pill = this.formatPill(),
|
||||
extra_pill = this.formatExtraPill();
|
||||
|
||||
el = (<div
|
||||
|
@ -315,7 +318,7 @@ export default class MenuButton extends SiteModule {
|
|||
{DEBUG && (<div class="tw-mg-t-1">
|
||||
{this.i18n.t('site.menu_button.main-dev-desc', 'You are running a developer build of FrankerFaceZ.')}
|
||||
</div>)}
|
||||
{this.addons.has_dev && (<div class="tw-mg-t-1">
|
||||
{addons.has_dev && (<div class="tw-mg-t-1">
|
||||
{this.i18n.t('site.menu_button.addon-dev-desc', 'You have loaded add-on data from a local development server.')}
|
||||
</div>)}
|
||||
</div>)}
|
||||
|
|
|
@ -283,13 +283,13 @@ export default class VideoChatHook extends Module {
|
|||
|
||||
return (<div
|
||||
data-test-selector="message-layout"
|
||||
class={`tw-align-items-start tw-flex tw-flex-nowrap tw-full-width tw-pd-l-05 tw-pd-y-05 vod-message${msg.mentioned ? ' ffz-mentioned' : ''}${bg_css ? ' ffz-custom-color' : ''}`}
|
||||
class={`tw-align-items-start tw-flex tw-flex-nowrap tw-full-width tw-pd-l-05 tw-pd-y-05 vod-message${msg.highlight ? ' ffz-notice-line ffz--points-line ffz--points-highlight ffz-custom-color' : ''}${msg.mentioned ? ' ffz-mentioned' : ''}${bg_css ? ' ffz-custom-color' : ''}`}
|
||||
style={{backgroundColor: bg_css}}
|
||||
>
|
||||
{this.props.hideTimestamp || (<div data-test-selector="message-timestamp" class="tw-align-right tw-flex tw-flex-shrink-0 vod-message__header">
|
||||
<div class="tw-mg-r-05">
|
||||
<div class="tw-inline-flex tw-relative tw-tooltip-wrapper">
|
||||
<button class="tw-block tw-full-width tw-interactable tw-interactable--inverted" onClick={this.onTimestampClickHandler}>
|
||||
<button class="tw-block tw-full-width tw-interactable tw-interactable--hover-enabled tw-interactable--inverted tw-interactive" onClick={this.onTimestampClickHandler}>
|
||||
<div class="tw-pd-x-05">
|
||||
<p class="tw-font-size-7">{print_duration(context.comment.contentOffset)}</p>
|
||||
</div>
|
||||
|
@ -377,7 +377,8 @@ export default class VideoChatHook extends Module {
|
|||
messageParts: comment.message.tokens,
|
||||
is_action: comment.message.isAction,
|
||||
more_replies: comment.moreReplies,
|
||||
timestamp: comment.createdAt
|
||||
timestamp: comment.createdAt,
|
||||
highlight: comment.message.userNoticeParams?.['msg-id'] === 'highlighted-message'
|
||||
};
|
||||
|
||||
this.chat.detokenizeMessage(out);
|
||||
|
|
|
@ -16,6 +16,9 @@ export const State = {
|
|||
}
|
||||
|
||||
|
||||
const ANONYMOUS_ID = '683b45e4-f853-4c45-bf96-7d799cc93e34';
|
||||
|
||||
|
||||
export default class SocketClient extends Module {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
@ -62,7 +65,7 @@ export default class SocketClient extends Module {
|
|||
|
||||
this.settings.on(':changed:socket.use-cluster', () => {
|
||||
this._host = null;
|
||||
if ( this.disconnected)
|
||||
if ( this.disconnected )
|
||||
this.connect();
|
||||
else
|
||||
this.reconnect();
|
||||
|
@ -252,14 +255,18 @@ export default class SocketClient extends Module {
|
|||
this._ping_time = performance.now();
|
||||
this._send(
|
||||
'hello',
|
||||
[`ffz_${window.FrankerFaceZ.version_info}`, this.settings.provider.get('client-id')],
|
||||
[`ffz_${window.FrankerFaceZ.version_info}`, ANONYMOUS_ID],
|
||||
(success, data) => {
|
||||
if ( ! success )
|
||||
return this.log.warn('Error Saying Hello', data);
|
||||
|
||||
this._on_pong(false, success, data[1]);
|
||||
this.settings.provider.set('client-id', data[0]);
|
||||
this.log.info('Client ID:', data[0]);
|
||||
/*if ( data[0] === ANONYMOUS_ID )
|
||||
this.log.info('Client ID: <Anonymous>');
|
||||
else {
|
||||
this.settings.provider.set('client-id', data[0]);
|
||||
this.log.info('Client ID:', data[0]);
|
||||
}*/
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ query FFZ_FetchPoll($id: ID!) {
|
|||
login
|
||||
displayName
|
||||
}
|
||||
durationSeconds
|
||||
endedAt
|
||||
startedAt
|
||||
totalVoters
|
||||
|
|
|
@ -5,7 +5,9 @@ query FFZ_FetchUser($id: ID, $login: String) {
|
|||
displayName
|
||||
profileImageURL(width: 50)
|
||||
roles {
|
||||
isAffiliate
|
||||
isPartner
|
||||
isStaff
|
||||
}
|
||||
}
|
||||
}
|
9
src/utilities/data/user-self.gql
Normal file
9
src/utilities/data/user-self.gql
Normal file
|
@ -0,0 +1,9 @@
|
|||
query FFZ_UserSelf($id: ID, $login: String) {
|
||||
user(id: $id, login: $login) {
|
||||
id
|
||||
self {
|
||||
isEditor
|
||||
isModerator
|
||||
}
|
||||
}
|
||||
}
|
|
@ -194,6 +194,15 @@ export default class TwitchData extends Module {
|
|||
return get('data.user', data);
|
||||
}
|
||||
|
||||
async getUserSelf(id, login) {
|
||||
const data = await this.queryApollo(
|
||||
await import(/* webpackChunkName: 'queries' */ './data/user-self.gql'),
|
||||
{ id, login }
|
||||
);
|
||||
|
||||
return get('data.user.self', data);
|
||||
}
|
||||
|
||||
async getLastBroadcast(id, login) {
|
||||
const data = await this.queryApollo(
|
||||
await import(/* webpackChunkName: 'queries' */ './data/last-broadcast.gql'),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue