mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-07-05 10:38:30 +00:00
4.0.0-rc18.2
More performance! * Changed: Push the chat scroll to bottom into a new animation frame to avoid costly recalculations as much as possible. * Fixed: Runaway performance issue when using FontAwesome icons for in-line chat actions due to an overabundance of CSS. * Fixed: Emitting updated events for settings that haven't changed, resulting in frequent re-rendering of all chat lines.
This commit is contained in:
parent
918a5fbb13
commit
8bc25b8d5f
7 changed files with 182 additions and 15 deletions
|
@ -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: '-rc18.1',
|
||||
major: 4, minor: 0, revision: 0, extra: '-rc18.2',
|
||||
commit: __git_commit__,
|
||||
build: __webpack_hash__,
|
||||
toString: () =>
|
||||
|
|
|
@ -300,6 +300,7 @@ export default class Chat extends Module {
|
|||
|
||||
this.settings.add('chat.filtering.highlight-basic-users--color-regex', {
|
||||
requires: ['chat.filtering.highlight-basic-users'],
|
||||
equals: 'requirements',
|
||||
process(ctx) {
|
||||
const val = ctx.get('chat.filtering.highlight-basic-users');
|
||||
if ( ! val || ! val.length )
|
||||
|
@ -358,7 +359,8 @@ export default class Chat extends Module {
|
|||
|
||||
|
||||
this.settings.add('chat.filtering.highlight-basic-users-blocked--regex', {
|
||||
requires: ['chat.filtering.highlight-basic-blocked'],
|
||||
requires: ['chat.filtering.highlight-basic-users-blocked'],
|
||||
equals: 'requirements',
|
||||
process(ctx) {
|
||||
const val = ctx.get('chat.filtering.highlight-basic-users-blocked');
|
||||
if ( ! val || ! val.length )
|
||||
|
@ -407,6 +409,7 @@ export default class Chat extends Module {
|
|||
|
||||
this.settings.add('chat.filtering.highlight-basic-badges--colors', {
|
||||
requires: ['chat.filtering.highlight-basic-badges'],
|
||||
equals: 'requirements',
|
||||
process(ctx) {
|
||||
const val = ctx.get('chat.filtering.highlight-basic-badges');
|
||||
if ( ! val || ! val.length )
|
||||
|
@ -440,6 +443,7 @@ export default class Chat extends Module {
|
|||
|
||||
this.settings.add('chat.filtering.highlight-basic-badges-blocked--list', {
|
||||
requires: ['chat.filtering.highlight-basic-badges-blocked'],
|
||||
equals: 'requirements',
|
||||
process(ctx) {
|
||||
const val = ctx.get('chat.filtering.highlight-basic-badges-blocked');
|
||||
if ( ! val || ! val.length )
|
||||
|
@ -471,6 +475,7 @@ export default class Chat extends Module {
|
|||
|
||||
this.settings.add('chat.filtering.highlight-basic-terms--color-regex', {
|
||||
requires: ['chat.filtering.highlight-basic-terms'],
|
||||
equals: 'requirements',
|
||||
process(ctx) {
|
||||
const val = ctx.get('chat.filtering.highlight-basic-terms');
|
||||
if ( ! val || ! val.length )
|
||||
|
@ -537,6 +542,7 @@ export default class Chat extends Module {
|
|||
|
||||
this.settings.add('chat.filtering.highlight-basic-blocked--regex', {
|
||||
requires: ['chat.filtering.highlight-basic-blocked'],
|
||||
equals: 'requirements',
|
||||
process(ctx) {
|
||||
const val = ctx.get('chat.filtering.highlight-basic-blocked');
|
||||
if ( ! val || ! val.length )
|
||||
|
|
|
@ -5,10 +5,47 @@
|
|||
// ============================================================================
|
||||
|
||||
import {EventEmitter} from 'utilities/events';
|
||||
import {has, get as getter, array_equals} from 'utilities/object';
|
||||
import {has, get as getter, array_equals, set_equals, map_equals, deep_copy} from 'utilities/object';
|
||||
|
||||
import * as DEFINITIONS from './types';
|
||||
|
||||
/**
|
||||
* Perform a basic check of a setting's requirements to see if they changed.
|
||||
* @param {Object} definition
|
||||
* @param {Map} cache
|
||||
* @param {Map} old_cache
|
||||
* @returns Whether or not they changed.
|
||||
*/
|
||||
function compare_requirements(definition, cache, old_cache) {
|
||||
if ( ! definition || ! Array.isArray(definition.requires) )
|
||||
return false;
|
||||
|
||||
for(const req of definition.requires) {
|
||||
const old_value = old_cache.get(req),
|
||||
new_value = cache.get(req);
|
||||
|
||||
if ( typeof old_value !== typeof new_value )
|
||||
return true;
|
||||
|
||||
if ( Array.isArray(old_value) && Array.isArray(new_value) ) {
|
||||
if ( ! array_equals(new_value, old_value) )
|
||||
return true;
|
||||
|
||||
} else if ( new_value instanceof Set && old_value instanceof Set ) {
|
||||
if ( ! set_equals(new_value, old_value) )
|
||||
return true;
|
||||
|
||||
} else if( new_value instanceof Map && old_value instanceof Map ) {
|
||||
if ( ! map_equals(new_value, old_value) )
|
||||
return true;
|
||||
|
||||
} else if ( new_value !== old_value )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The SettingsContext class provides a context through which to read
|
||||
|
@ -34,6 +71,10 @@ export default class SettingsContext extends EventEmitter {
|
|||
this.manager.__contexts.push(this);
|
||||
this._context = context || {};
|
||||
|
||||
/*this._context_objects = new Set;
|
||||
if ( context )
|
||||
this._updateContext(context, undefined, undefined, new Set);*/
|
||||
|
||||
this.__cache = new Map;
|
||||
this.__meta = new Map;
|
||||
this.__profiles = [];
|
||||
|
@ -125,7 +166,29 @@ export default class SettingsContext extends EventEmitter {
|
|||
new_uses = new_m ? new_m.uses : null,
|
||||
old_uses = old_m ? old_m.uses : null;
|
||||
|
||||
if ( new_value !== old_value ) {
|
||||
const definition = this.manager.definitions.get(key);
|
||||
let changed = false;
|
||||
|
||||
if ( definition && definition.equals ) {
|
||||
if ( definition.equals === 'requirements' )
|
||||
changed = compare_requirements(definition, this.__cache, old_cache);
|
||||
else if ( typeof definition.equals === 'function' )
|
||||
changed = ! definition.equals(new_value, old_value, this.__cache, old_cache);
|
||||
}
|
||||
|
||||
else if ( Array.isArray(new_value) && Array.isArray(old_value) )
|
||||
changed = ! array_equals(new_value, old_value);
|
||||
|
||||
else if ( new_value instanceof Set && old_value instanceof Set )
|
||||
changed = ! set_equals(new_value, old_value);
|
||||
|
||||
else if ( new_value instanceof Map && old_value instanceof Map )
|
||||
changed = ! map_equals(new_value, old_value);
|
||||
|
||||
else if ( new_value !== old_value )
|
||||
changed = true;
|
||||
|
||||
if ( changed ) {
|
||||
this.emit('changed', key, new_value, old_value);
|
||||
this.emit(`changed:${key}`, new_value, old_value);
|
||||
}
|
||||
|
@ -161,9 +224,68 @@ export default class SettingsContext extends EventEmitter {
|
|||
}
|
||||
|
||||
|
||||
/*_updateContext(context, prefix, keys, changed) {
|
||||
if ( ! context || typeof context !== 'object' )
|
||||
return;
|
||||
|
||||
if ( ! keys )
|
||||
keys = Object.keys(context);
|
||||
|
||||
if ( prefix && this._context_objects.has(prefix) ) {
|
||||
for(const key of Object.keys(this._context) )
|
||||
if ( key.startsWith(prefix) ) {
|
||||
const partial_key = key.substr(prefix.length);
|
||||
if ( ! keys.includes(partial_key) )
|
||||
keys.push(partial_key);
|
||||
}
|
||||
}
|
||||
|
||||
if ( prefix )
|
||||
this._context_objects.add(prefix);
|
||||
|
||||
for(const key of keys) {
|
||||
const full_key = prefix ? `${prefix}${key}` : key,
|
||||
pref = `${full_key}.`,
|
||||
old_value = this._context[full_key],
|
||||
val = context[key];
|
||||
|
||||
const keys = val && (typeof val === 'object') && Object.keys(val);
|
||||
if ( keys && keys.length ) {
|
||||
this._updateContext(val, pref, keys, changed);
|
||||
|
||||
} else if ( this._context_objects.has(pref) ) {
|
||||
this._updateContext({}, pref, [], changed);
|
||||
this._context_objects.delete(pref);
|
||||
|
||||
if ( (val || old_value) && val !== old_value ) {
|
||||
this._context[full_key] = val;
|
||||
changed.add(full_key);
|
||||
}
|
||||
|
||||
} else if ( val !== old_value ) {
|
||||
this._context[full_key] = val;
|
||||
changed.add(full_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
updateContext(context) {
|
||||
if ( ! context || typeof context !== 'object' )
|
||||
return;
|
||||
|
||||
const changed = new Set;
|
||||
this._updateContext(context, undefined, undefined, changed);
|
||||
|
||||
if ( changed.size )
|
||||
this._rebuildContext();
|
||||
}*/
|
||||
|
||||
|
||||
setContext(context) {
|
||||
this._context = context;
|
||||
this._rebuildContext();
|
||||
this._context_objects = new Set;
|
||||
this._context = {};
|
||||
this.updateContext(context);
|
||||
}
|
||||
|
||||
|
||||
|
@ -289,6 +411,7 @@ export default class SettingsContext extends EventEmitter {
|
|||
|
||||
get(key) {
|
||||
if ( key.startsWith('context.') )
|
||||
//return this.__context[key.slice(8)];
|
||||
return getter(key.slice(8), this.__context);
|
||||
|
||||
if ( this.__cache.has(key) )
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import {ColorAdjuster} from 'utilities/color';
|
||||
import {setChildren} from 'utilities/dom';
|
||||
import {has, make_enum, split_chars, shallow_object_equals} from 'utilities/object';
|
||||
import {has, make_enum, split_chars, shallow_object_equals, set_equals} from 'utilities/object';
|
||||
import {FFZEvent} from 'utilities/events';
|
||||
|
||||
import Module from 'utilities/module';
|
||||
|
@ -1454,6 +1454,21 @@ export default class ChatHook extends Module {
|
|||
if ( ! room )
|
||||
return;
|
||||
|
||||
// We have to check that the available cheers haven't changed
|
||||
// to avoid doing too many recalculations.
|
||||
let new_bits = null;
|
||||
if ( config && Array.isArray(config.orderedActions) ) {
|
||||
new_bits = new Set;
|
||||
for(const action of config.orderedActions)
|
||||
if ( action && action.prefix )
|
||||
new_bits.add(action.prefix);
|
||||
}
|
||||
|
||||
if ( (! this._ffz_old_bits && ! new_bits) || set_equals(this._ffz_old_bits, new_bits) )
|
||||
return;
|
||||
|
||||
this._ffz_old_bits = new_bits;
|
||||
|
||||
room.updateBitsConfig(formatBitsConfig(config));
|
||||
this.updateChatLines();
|
||||
}
|
||||
|
|
|
@ -318,14 +318,22 @@ export default class Scroller extends Module {
|
|||
return;
|
||||
|
||||
const t = this;
|
||||
|
||||
this._doScroll = function() {
|
||||
if ( ! t.ffz_freeze_enabled || ! t.state.ffzFrozen ) {
|
||||
if ( t.ffz_smooth_scroll )
|
||||
t.smoothScrollBottom();
|
||||
else
|
||||
t._old_scroll();
|
||||
}
|
||||
}
|
||||
|
||||
this._old_scroll = this.scrollToBottom;
|
||||
this.scrollToBottom = function() {
|
||||
if ( ! this.ffz_freeze_enabled || ! this.state.ffzFrozen ) {
|
||||
if ( this.ffz_smooth_scroll )
|
||||
this.smoothScrollBottom();
|
||||
else
|
||||
this._old_scroll();
|
||||
}
|
||||
if ( this._ffz_animation )
|
||||
cancelAnimationFrame(this._ffz_animation);
|
||||
|
||||
this._ffz_animation = requestAnimationFrame(t._doScroll);
|
||||
}
|
||||
|
||||
this._ffz_handleScroll = this.handleScrollEvent;
|
||||
|
|
|
@ -227,10 +227,13 @@ export const load = () => {
|
|||
if ( loaded )
|
||||
return;
|
||||
|
||||
loaded = true;
|
||||
|
||||
document.head.appendChild(createElement('link', {
|
||||
href: FA_URL,
|
||||
rel: 'stylesheet',
|
||||
type: 'text/css',
|
||||
crossOrigin: 'anonymouse'
|
||||
crossOrigin: 'anonymous'
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -116,6 +116,18 @@ export function shallow_object_equals(a, b) {
|
|||
}
|
||||
|
||||
|
||||
export function map_equals(a, b) {
|
||||
if ( !(a instanceof Map) || !(b instanceof Map) || a.size !== b.size )
|
||||
return false;
|
||||
|
||||
for(const [key, val] of a)
|
||||
if ( ! b.has(key) || b.get(key) !== val )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
export function set_equals(a,b) {
|
||||
if ( !(a instanceof Set) || !(b instanceof Set) || a.size !== b.size )
|
||||
return false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue