mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-04 11:44:00 +00:00
4.0.0-rc20
* Added: Room Actions for Chat. Easily send canned messages or open relevant links. * Changed: Refactor how action data is passed to in-line chat actions. Should perform better now, and also allow using the message text in actions. * Changed: Blacklist a few errors from automatic error reporting. * Fixed: Include the Squad Bar when calculating the player height for Portrait Mode. * Fixed: Issue with rich content embeds breaking chat rendering when an error occurs loading their data. * Fixed: Duplicate icon keys in chat action editor.
This commit is contained in:
parent
c920b43e01
commit
5500b6eef3
14 changed files with 312 additions and 67 deletions
|
@ -149,7 +149,7 @@ ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}`
|
||||||
FrankerFaceZ.Logger = Logger;
|
FrankerFaceZ.Logger = Logger;
|
||||||
|
|
||||||
const VER = FrankerFaceZ.version_info = {
|
const VER = FrankerFaceZ.version_info = {
|
||||||
major: 4, minor: 0, revision: 0, extra: '-rc19.4',
|
major: 4, minor: 0, revision: 0, extra: '-rc20',
|
||||||
commit: __git_commit__,
|
commit: __git_commit__,
|
||||||
build: __webpack_hash__,
|
build: __webpack_hash__,
|
||||||
toString: () =>
|
toString: () =>
|
||||||
|
|
|
@ -94,8 +94,6 @@ const FFZ_ICONS = [
|
||||||
'lock',
|
'lock',
|
||||||
'lock-open',
|
'lock-open',
|
||||||
'arrows-cw',
|
'arrows-cw',
|
||||||
'pin',
|
|
||||||
'pin-outline',
|
|
||||||
'gift',
|
'gift',
|
||||||
'eyedropper',
|
'eyedropper',
|
||||||
'github',
|
'github',
|
||||||
|
|
|
@ -90,6 +90,35 @@ export default class Actions extends Module {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.settings.add('chat.actions.room', {
|
||||||
|
// Filter out actions
|
||||||
|
process: (ctx, val) =>
|
||||||
|
val.filter(x => x.type || (x.appearance &&
|
||||||
|
this.renderers[x.appearance.type] &&
|
||||||
|
(! this.renderers[x.appearance.type].load || this.renderers[x.appearance.type].load(x.appearance)) &&
|
||||||
|
(! x.action || this.actions[x.action])
|
||||||
|
)),
|
||||||
|
|
||||||
|
default: [],
|
||||||
|
type: 'array_merge',
|
||||||
|
ui: {
|
||||||
|
path: 'Chat > Actions > Room @{"description": "Here, you can define custom actions that will appear above the chat input box."}',
|
||||||
|
component: 'chat-actions',
|
||||||
|
context: ['room'],
|
||||||
|
inline: true,
|
||||||
|
|
||||||
|
data: () => {
|
||||||
|
const chat = this.resolve('site.chat');
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: val => chat && chat.colors ? chat.colors.process(val) : val,
|
||||||
|
actions: deep_copy(this.actions),
|
||||||
|
renderers: deep_copy(this.renderers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.settings.add('chat.actions.rules-as-reasons', {
|
this.settings.add('chat.actions.rules-as-reasons', {
|
||||||
default: true,
|
default: true,
|
||||||
ui: {
|
ui: {
|
||||||
|
@ -346,6 +375,56 @@ export default class Actions extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
renderRoom(mod_icons, current_user, current_room, createElement) {
|
||||||
|
const actions = [],
|
||||||
|
chat = this.resolve('site.chat');
|
||||||
|
|
||||||
|
for(const data of this.parent.context.get('chat.actions.room')) {
|
||||||
|
if ( ! data || ! data.action || ! data.appearance )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const ap = data.appearance || {},
|
||||||
|
disp = data.display || {},
|
||||||
|
|
||||||
|
def = this.renderers[ap.type];
|
||||||
|
|
||||||
|
if ( ! def || disp.disabled ||
|
||||||
|
(disp.mod_icons != null && disp.mod_icons !== !!mod_icons) ||
|
||||||
|
(disp.mod != null && disp.mod !== (current_user ? !!current_user.mod : false)) ||
|
||||||
|
(disp.staff != null && disp.staff !== (current_user ? !!current_user.staff : false)) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const has_color = def.colored && ap.color,
|
||||||
|
color = has_color && (chat && chat.colors ? chat.colors.process(ap.color) : ap.color),
|
||||||
|
contents = def.render.call(this, ap, createElement, color);
|
||||||
|
|
||||||
|
actions.push(<button
|
||||||
|
class={`ffz-tooltip ffz-mod-icon mod-icon tw-c-text-alt-2${has_color ? ' colored' : ''}`}
|
||||||
|
data-tooltip-type="action"
|
||||||
|
data-action={data.action}
|
||||||
|
data-options={data.options ? JSON.stringify(data.options) : null}
|
||||||
|
data-tip={ap.tooltip}
|
||||||
|
onClick={this.handleClick}
|
||||||
|
onContextMenu={this.handleContext}
|
||||||
|
>
|
||||||
|
{contents}
|
||||||
|
</button>);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! actions.length )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
const room = current_room && JSON.stringify(current_room);
|
||||||
|
|
||||||
|
return (<div
|
||||||
|
class="ffz--room-actions ffz-action-data tw-pd-y-05 tw-border-t"
|
||||||
|
data-room={room}
|
||||||
|
>
|
||||||
|
{actions}
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
renderInline(msg, mod_icons, current_user, current_room, createElement) {
|
renderInline(msg, mod_icons, current_user, current_room, createElement) {
|
||||||
const actions = [];
|
const actions = [];
|
||||||
|
|
||||||
|
@ -393,19 +472,17 @@ export default class Actions extends Module {
|
||||||
if ( ! actions.length )
|
if ( ! actions.length )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
const room = current_room && JSON.stringify(current_room),
|
/*const room = current_room && JSON.stringify(current_room),
|
||||||
user = msg.user && JSON.stringify({
|
user = msg.user && JSON.stringify({
|
||||||
login: msg.user.login,
|
login: msg.user.login,
|
||||||
displayName: msg.user.displayName,
|
displayName: msg.user.displayName,
|
||||||
id: msg.user.id,
|
id: msg.user.id,
|
||||||
type: msg.user.type
|
type: msg.user.type
|
||||||
});
|
});*/
|
||||||
|
|
||||||
return (<div
|
return (<div
|
||||||
class="ffz--inline-actions ffz-action-data tw-inline-block tw-mg-r-05"
|
class="ffz--inline-actions ffz-action-data tw-inline-block tw-mg-r-05"
|
||||||
data-msg-id={msg.id}
|
data-source="line"
|
||||||
data-user={user}
|
|
||||||
data-room={room}
|
|
||||||
>
|
>
|
||||||
{actions}
|
{actions}
|
||||||
</div>);
|
</div>);
|
||||||
|
@ -422,18 +499,55 @@ export default class Actions extends Module {
|
||||||
if ( ! definition )
|
if ( ! definition )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
const user = pds && pds.user ? JSON.parse(pds.user) : null,
|
let user, room, message, loaded = false;
|
||||||
room = pds && pds.room ? JSON.parse(pds.room) : null,
|
|
||||||
message_id = pds && pds.msgId,
|
|
||||||
|
|
||||||
data = {
|
if ( pds ) {
|
||||||
|
if ( pds.source === 'line' ) {
|
||||||
|
const fine = this.resolve('site.fine'),
|
||||||
|
react = fine && fine.getParent(parent.parentElement),
|
||||||
|
line = react && react.stateNode;
|
||||||
|
|
||||||
|
if ( line && line.props && line.props.message ) {
|
||||||
|
loaded = true;
|
||||||
|
|
||||||
|
const msg = line.props.message;
|
||||||
|
|
||||||
|
user = msg.user ? {
|
||||||
|
color: msg.user.color,
|
||||||
|
id: msg.user.id,
|
||||||
|
login: msg.user.login,
|
||||||
|
displayName: msg.user.displayName,
|
||||||
|
type: msg.user.type
|
||||||
|
} : null;
|
||||||
|
|
||||||
|
room = {
|
||||||
|
login: line.props.channelLogin,
|
||||||
|
id: line.props.channelID
|
||||||
|
}
|
||||||
|
|
||||||
|
message = {
|
||||||
|
id: msg.id,
|
||||||
|
text: msg.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! loaded ) {
|
||||||
|
user = pds.user ? JSON.parse(pds.user) : null;
|
||||||
|
room = pds.room ? JSON.parse(pds.room) : null;
|
||||||
|
message = pds.message ? JSON.parse(pds.message) : pds.msgId ? {id: pds.msgId} : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
action,
|
action,
|
||||||
definition,
|
definition,
|
||||||
tip: ds.tip,
|
tip: ds.tip,
|
||||||
options: ds.options ? JSON.parse(ds.options) : null,
|
options: ds.options ? JSON.parse(ds.options) : null,
|
||||||
user,
|
user,
|
||||||
room,
|
room,
|
||||||
message_id
|
message,
|
||||||
|
message_id: message ? message.id : null
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( definition.defaults )
|
if ( definition.defaults )
|
||||||
|
|
|
@ -41,7 +41,7 @@ export const Links = {
|
||||||
return {
|
return {
|
||||||
url: token.url,
|
url: token.url,
|
||||||
title: this.i18n.t('card.error', 'An error occurred.'),
|
title: this.i18n.t('card.error', 'An error occurred.'),
|
||||||
desc_1: err
|
desc_1: String(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tw-flex tw-align-items-center">
|
<div v-if="has_message" class="tw-flex tw-align-items-center">
|
||||||
<label for="vis_deleted">
|
<label for="vis_deleted">
|
||||||
{{ t('setting.actions.edit-visible.deleted', 'Message Deleted') }}
|
{{ t('setting.actions.edit-visible.deleted', 'Message Deleted') }}
|
||||||
</label>
|
</label>
|
||||||
|
@ -215,7 +215,7 @@
|
||||||
import {has, maybe_call, deep_copy} from 'utilities/object';
|
import {has, maybe_call, deep_copy} from 'utilities/object';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['action', 'data', 'inline'],
|
props: ['action', 'data', 'inline', 'context'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -233,14 +233,30 @@ export default {
|
||||||
return this.action.v;
|
return this.action.v;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
has_message() {
|
||||||
|
return this.context && this.context.includes('message')
|
||||||
|
},
|
||||||
|
|
||||||
vars() {
|
vars() {
|
||||||
const out = ['user.login', 'user.displayName', 'user.id', 'user.type'];
|
const out = [],
|
||||||
|
ctx = this.context || [];
|
||||||
|
|
||||||
out.push('room.login')
|
if ( ctx.includes('user') ) {
|
||||||
|
out.push('user.login');
|
||||||
|
out.push('user.displayName');
|
||||||
|
out.push('user.id');
|
||||||
|
out.push('user.type');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ctx.includes('room') ) {
|
||||||
|
out.push('room.login');
|
||||||
out.push('room.id');
|
out.push('room.id');
|
||||||
|
}
|
||||||
|
|
||||||
if ( this.inline )
|
if ( ctx.includes('message') ) {
|
||||||
out.push('message_id');
|
out.push('message.id');
|
||||||
|
out.push('message.text');
|
||||||
|
}
|
||||||
|
|
||||||
return out.map(x => `{{${x}}}`).join(', ');
|
return out.map(x => `{{${x}}}`).join(', ');
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="item.inline" class="tw-pd-x-1 tw-checkbox">
|
<div v-if="item.inline && has_msg" class="tw-pd-x-1 tw-checkbox">
|
||||||
<input
|
<input
|
||||||
id="is_deleted"
|
id="is_deleted"
|
||||||
ref="is_deleted"
|
ref="is_deleted"
|
||||||
|
@ -76,6 +76,7 @@
|
||||||
<div
|
<div
|
||||||
:data-user="JSON.stringify(sample_user)"
|
:data-user="JSON.stringify(sample_user)"
|
||||||
:data-room="JSON.stringify(sample_room)"
|
:data-room="JSON.stringify(sample_room)"
|
||||||
|
:data-message="JSON.stringify(sample_message)"
|
||||||
class="ffz-action-data tw-pd-t-1"
|
class="ffz-action-data tw-pd-t-1"
|
||||||
data-msg-id="1234-5678"
|
data-msg-id="1234-5678"
|
||||||
>
|
>
|
||||||
|
@ -169,7 +170,7 @@
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="! val.length"
|
v-if="! val.length && has_default"
|
||||||
class="tw-mg-l-1 tw-button tw-button--text tw-tooltip-wrapper"
|
class="tw-mg-l-1 tw-button tw-button--text tw-tooltip-wrapper"
|
||||||
@click="populate"
|
@click="populate"
|
||||||
>
|
>
|
||||||
|
@ -191,6 +192,7 @@
|
||||||
:action="act"
|
:action="act"
|
||||||
:data="data"
|
:data="data"
|
||||||
:inline="item.inline"
|
:inline="item.inline"
|
||||||
|
:context="item.context"
|
||||||
@remove="remove(act)"
|
@remove="remove(act)"
|
||||||
@save="save(act, $event)"
|
@save="save(act, $event)"
|
||||||
/>
|
/>
|
||||||
|
@ -222,18 +224,6 @@ export default {
|
||||||
show_all: false,
|
show_all: false,
|
||||||
|
|
||||||
add_open: false,
|
add_open: false,
|
||||||
|
|
||||||
sample_user: {
|
|
||||||
displayName: 'SirStendec',
|
|
||||||
login: 'sirstendec',
|
|
||||||
id: 49399878
|
|
||||||
},
|
|
||||||
|
|
||||||
sample_room: {
|
|
||||||
displayName: 'FrankerFaceZ',
|
|
||||||
login: 'frankerfacez',
|
|
||||||
id: 46622312
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -244,6 +234,46 @@ export default {
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
sample_user() {
|
||||||
|
return this.has_user ? {
|
||||||
|
displayName: 'SirStendec',
|
||||||
|
login: 'sirstendec',
|
||||||
|
id: 49399878,
|
||||||
|
color: '#008000'
|
||||||
|
} : null
|
||||||
|
},
|
||||||
|
|
||||||
|
sample_room() {
|
||||||
|
return this.has_room ? {
|
||||||
|
displayName: 'FrankerFaceZ',
|
||||||
|
login: 'frankerfacez',
|
||||||
|
id: 46622312
|
||||||
|
} : null
|
||||||
|
},
|
||||||
|
|
||||||
|
sample_message() {
|
||||||
|
return this.has_msg ? {
|
||||||
|
id: '46a473ee-a3c4-4556-a5ca-c0f1eac93ec0',
|
||||||
|
text: 'sirstendec: Please do not do that.'
|
||||||
|
} : null
|
||||||
|
},
|
||||||
|
|
||||||
|
has_default() {
|
||||||
|
return this.default_value && this.default_value.length
|
||||||
|
},
|
||||||
|
|
||||||
|
has_user() {
|
||||||
|
return this.item.context && this.item.context.includes('user')
|
||||||
|
},
|
||||||
|
|
||||||
|
has_room() {
|
||||||
|
return this.item.context && this.item.context.includes('room')
|
||||||
|
},
|
||||||
|
|
||||||
|
has_msg() {
|
||||||
|
return this.item.context && this.item.context.includes('message')
|
||||||
|
},
|
||||||
|
|
||||||
presets() {
|
presets() {
|
||||||
const out = [],
|
const out = [],
|
||||||
contexts = this.item.context || [];
|
contexts = this.item.context || [];
|
||||||
|
|
|
@ -138,7 +138,9 @@ export default class RavenLogger extends Module {
|
||||||
'InvalidAccessError',
|
'InvalidAccessError',
|
||||||
'out of memory',
|
'out of memory',
|
||||||
'Access is denied.',
|
'Access is denied.',
|
||||||
'Zugriff verweigert'
|
'Zugriff verweigert',
|
||||||
|
'freed script',
|
||||||
|
'ffzenhancing'
|
||||||
],
|
],
|
||||||
sanitizeKeys: [
|
sanitizeKeys: [
|
||||||
/Token$/
|
/Token$/
|
||||||
|
|
|
@ -212,6 +212,36 @@ export class LocalStorageProvider extends SettingsProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class IndexedDBProvider extends SettingsProvider {
|
||||||
|
constructor(manager) {
|
||||||
|
super(manager);
|
||||||
|
|
||||||
|
this._cached = new Map;
|
||||||
|
this.ready = false;
|
||||||
|
this._ready_wait = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.disable();
|
||||||
|
this._cached.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
disable() {
|
||||||
|
this.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
awaitReady() {
|
||||||
|
if ( this.ready )
|
||||||
|
return Promise.resolve();
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const waiters = this._ready_wait = this._ready_wait || [];
|
||||||
|
waiters.push([resolve, reject]);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class CloudStorageProvider extends SettingsProvider {
|
export class CloudStorageProvider extends SettingsProvider {
|
||||||
constructor(manager) {
|
constructor(manager) {
|
||||||
super(manager);
|
super(manager);
|
||||||
|
|
|
@ -112,7 +112,8 @@ export default class Twilight extends BaseSite {
|
||||||
this.settings.updateContext({
|
this.settings.updateContext({
|
||||||
location: history && history.location,
|
location: history && history.location,
|
||||||
ui: state && state.ui,
|
ui: state && state.ui,
|
||||||
session: state && state.session
|
session: state && state.session,
|
||||||
|
chat: state && state.chat
|
||||||
});
|
});
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
this.log.error('Error updating context.', err);
|
this.log.error('Error updating context.', err);
|
||||||
|
|
|
@ -17,7 +17,7 @@ import Scroller from './scroller';
|
||||||
import ChatLine from './line';
|
import ChatLine from './line';
|
||||||
import SettingsMenu from './settings_menu';
|
import SettingsMenu from './settings_menu';
|
||||||
import EmoteMenu from './emote_menu';
|
import EmoteMenu from './emote_menu';
|
||||||
import TabCompletion from './tab_completion';
|
import Input from './input';
|
||||||
|
|
||||||
|
|
||||||
const REGEX_EMOTES = {
|
const REGEX_EMOTES = {
|
||||||
|
@ -150,7 +150,7 @@ export default class ChatHook extends Module {
|
||||||
this.inject(ChatLine);
|
this.inject(ChatLine);
|
||||||
this.inject(SettingsMenu);
|
this.inject(SettingsMenu);
|
||||||
this.inject(EmoteMenu);
|
this.inject(EmoteMenu);
|
||||||
this.inject(TabCompletion);
|
this.inject(Input);
|
||||||
|
|
||||||
this.ChatService = this.fine.define(
|
this.ChatService = this.fine.define(
|
||||||
'chat-service',
|
'chat-service',
|
||||||
|
@ -560,25 +560,12 @@ export default class ChatHook extends Module {
|
||||||
|
|
||||||
this.ChatContainer.on('mount', this.containerMounted, this);
|
this.ChatContainer.on('mount', this.containerMounted, this);
|
||||||
this.ChatContainer.on('unmount', this.removeRoom, this);
|
this.ChatContainer.on('unmount', this.removeRoom, this);
|
||||||
this.ChatContainer.on('receive-props', this.containerUpdated, this);
|
this.ChatContainer.on('update', this.containerUpdated, this);
|
||||||
|
|
||||||
this.ChatContainer.ready((cls, instances) => {
|
this.ChatContainer.ready((cls, instances) => {
|
||||||
const t = this,
|
const t = this,
|
||||||
old_render = cls.prototype.render,
|
|
||||||
old_catch = cls.prototype.componentDidCatch;
|
old_catch = cls.prototype.componentDidCatch;
|
||||||
|
|
||||||
// This is so stupid. I hate React. Why won't the events just fire
|
|
||||||
// like they should.
|
|
||||||
cls.prototype.render = function() {
|
|
||||||
try {
|
|
||||||
t.containerUpdated(this, this.props);
|
|
||||||
} catch(err) {
|
|
||||||
t.log.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return old_render.call(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try catching errors. With any luck, maybe we can
|
// Try catching errors. With any luck, maybe we can
|
||||||
// recover from the error when we re-build?
|
// recover from the error when we re-build?
|
||||||
cls.prototype.componentDidCatch = function(err, info) {
|
cls.prototype.componentDidCatch = function(err, info) {
|
||||||
|
@ -685,7 +672,7 @@ export default class ChatHook extends Module {
|
||||||
if ( event.defaultPrevented || m.ffz_removed )
|
if ( event.defaultPrevented || m.ffz_removed )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else if ( msg.type === types.ModerationAction ) {
|
} else if ( msg.type === types.ModerationAction && inst.markUserEventDeleted && inst.unsetModeratedUser ) {
|
||||||
//t.log.info('Moderation Action', msg);
|
//t.log.info('Moderation Action', msg);
|
||||||
if ( ! inst.props.isCurrentUserModerator )
|
if ( ! inst.props.isCurrentUserModerator )
|
||||||
return;
|
return;
|
||||||
|
@ -724,7 +711,7 @@ export default class ChatHook extends Module {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if ( msg.type === types.Moderation ) {
|
} else if ( msg.type === types.Moderation && inst.markUserEventDeleted && inst.unsetModeratedUser ) {
|
||||||
//t.log.info('Moderation', msg);
|
//t.log.info('Moderation', msg);
|
||||||
if ( inst.props.isCurrentUserModerator )
|
if ( inst.props.isCurrentUserModerator )
|
||||||
return;
|
return;
|
||||||
|
@ -1540,6 +1527,8 @@ export default class ChatHook extends Module {
|
||||||
|
|
||||||
|
|
||||||
containerUpdated(cont, props) {
|
containerUpdated(cont, props) {
|
||||||
|
// If we don't have a room, or if the room ID doesn't match our ID
|
||||||
|
// then we need to just create a new Room because the chat room changed.
|
||||||
if ( ! cont._ffz_room || props.channelID != cont._ffz_room.id ) {
|
if ( ! cont._ffz_room || props.channelID != cont._ffz_room.id ) {
|
||||||
this.removeRoom(cont);
|
this.removeRoom(cont);
|
||||||
if ( cont._ffz_mounted )
|
if ( cont._ffz_mounted )
|
||||||
|
|
|
@ -7,11 +7,12 @@
|
||||||
import Module from 'utilities/module';
|
import Module from 'utilities/module';
|
||||||
import Twilight from 'site';
|
import Twilight from 'site';
|
||||||
|
|
||||||
export default class TabCompletion extends Module {
|
export default class Input extends Module {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
this.inject('chat');
|
this.inject('chat');
|
||||||
|
this.inject('chat.actions');
|
||||||
this.inject('chat.emotes');
|
this.inject('chat.emotes');
|
||||||
this.inject('chat.emoji');
|
this.inject('chat.emoji');
|
||||||
this.inject('i18n');
|
this.inject('i18n');
|
||||||
|
@ -59,15 +60,58 @@ export default class TabCompletion extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
async onEnable() {
|
async onEnable() {
|
||||||
|
this.chat.context.on('changed:chat.actions.room', () => this.ChatInput.forceUpdate());
|
||||||
|
|
||||||
const React = await this.web_munch.findModule('react'),
|
const React = await this.web_munch.findModule('react'),
|
||||||
createElement = React && React.createElement;
|
createElement = React && React.createElement;
|
||||||
|
|
||||||
if ( ! createElement )
|
if ( ! createElement )
|
||||||
return this.log.warn('Unable to get React.');
|
return this.log.warn('Unable to get React.');
|
||||||
|
|
||||||
|
const t = this;
|
||||||
|
|
||||||
this.ChatInput.ready((cls, instances) => {
|
this.ChatInput.ready((cls, instances) => {
|
||||||
for(const inst of instances)
|
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();
|
||||||
this.updateEmoteCompletion(inst);
|
this.updateEmoteCompletion(inst);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.EmoteSuggestions.ready((cls, instances) => {
|
this.EmoteSuggestions.ready((cls, instances) => {
|
|
@ -92,7 +92,7 @@ export default class Layout extends Module {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.settings.add('layout.portrait-extra-height', {
|
this.settings.add('layout.portrait-extra-height', {
|
||||||
requires: ['context.new_channel', 'context.hosting', 'context.ui.theatreModeEnabled', 'player.theatre.no-whispers', 'whispers.show', 'layout.minimal-navigation'],
|
requires: ['context.new_channel', 'context.squad_bar', 'context.hosting', 'context.ui.theatreModeEnabled', 'player.theatre.no-whispers', 'whispers.show', 'layout.minimal-navigation'],
|
||||||
process(ctx) {
|
process(ctx) {
|
||||||
let height = 0;
|
let height = 0;
|
||||||
if ( ctx.get('context.ui.theatreModeEnabled') ) {
|
if ( ctx.get('context.ui.theatreModeEnabled') ) {
|
||||||
|
@ -107,6 +107,9 @@ export default class Layout extends Module {
|
||||||
if ( ctx.get('whispers.show') )
|
if ( ctx.get('whispers.show') )
|
||||||
height += 4;
|
height += 4;
|
||||||
|
|
||||||
|
if ( ctx.get('context.squad_bar') )
|
||||||
|
height += 6;
|
||||||
|
|
||||||
height += ctx.get('context.new_channel') ? 1 : 5;
|
height += ctx.get('context.new_channel') ? 1 : 5;
|
||||||
|
|
||||||
if ( ctx.get('context.hosting') )
|
if ( ctx.get('context.hosting') )
|
||||||
|
|
|
@ -402,7 +402,12 @@ export default class Player extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.SquadStreamBar.forceUpdate();
|
this.SquadStreamBar.forceUpdate();
|
||||||
})
|
this.updateSquadContext();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.SquadStreamBar.on('mount', this.updateSquadContext, this);
|
||||||
|
this.SquadStreamBar.on('update', this.updateSquadContext, this);
|
||||||
|
this.SquadStreamBar.on('unmount', this.updateSquadContext, this);
|
||||||
|
|
||||||
this.Player.on('mount', this.onMount, this);
|
this.Player.on('mount', this.onMount, this);
|
||||||
this.Player.on('unmount', this.onUnmount, this);
|
this.Player.on('unmount', this.onUnmount, this);
|
||||||
|
@ -437,6 +442,19 @@ export default class Player extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updateSquadContext() {
|
||||||
|
this.settings.updateContext({
|
||||||
|
squad_bar: this.hasSquadBar()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
hasSquadBar() {
|
||||||
|
const inst = this.SquadStreamBar.first;
|
||||||
|
return inst ? inst.shouldRenderSquadBanner(inst.props) : false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
overrideInitialize(inst) {
|
overrideInitialize(inst) {
|
||||||
const t = this,
|
const t = this,
|
||||||
old_init = inst.initializePlayer;
|
old_init = inst.initializePlayer;
|
||||||
|
|
|
@ -140,7 +140,7 @@ export default class SocketClient extends Module {
|
||||||
_reconnect() {
|
_reconnect() {
|
||||||
if ( ! this._reconnect_timer ) {
|
if ( ! this._reconnect_timer ) {
|
||||||
if ( this._delay < 60000 )
|
if ( this._delay < 60000 )
|
||||||
this._delay += (Math.floor(Math.random() * 10) + 5) * 1000;
|
this._delay += (Math.floor(Math.random() * 15) + 5) * 1000;
|
||||||
else
|
else
|
||||||
this._delay = (Math.floor(Math.random() * 60) + 30) * 1000;
|
this._delay = (Math.floor(Math.random() * 60) + 30) * 1000;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue