mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-10-11 13:41:57 +00:00
4.13.3
* Changed: Shift-Click the FFZ Control Center icon in the top navigation to open the Control Center in a new window. * Fixed: Unnecessary localization calls for add-ons. * Fixed: Show an in-page notification rather than an alert box if the FFZ Control Center fails to load. * Fixed: Adding an event to an EventListener while the event firing potentially leading to an infinite loop. * Fixed: Pluralization rules for Ukrainian.
This commit is contained in:
parent
8c7e03119f
commit
02efd61f00
7 changed files with 180 additions and 118 deletions
|
@ -25,6 +25,7 @@ String.prototype.toSnakeCase = function() {
|
|||
export class EventEmitter {
|
||||
constructor() {
|
||||
this.__listeners = {};
|
||||
this.__running = new Set;
|
||||
this.__dead_events = 0;
|
||||
}
|
||||
|
||||
|
@ -93,6 +94,9 @@ export class EventEmitter {
|
|||
}
|
||||
|
||||
off(event, fn, ctx) {
|
||||
if ( this.__running.has(event) )
|
||||
throw new Error(`concurrent modification: tried removing event listener while event is running`);
|
||||
|
||||
let list = this.__listeners[event];
|
||||
if ( ! list )
|
||||
return;
|
||||
|
@ -121,14 +125,23 @@ export class EventEmitter {
|
|||
}
|
||||
|
||||
emitUnsafe(event, ...args) {
|
||||
const list = this.__listeners[event];
|
||||
let list = this.__listeners[event];
|
||||
if ( ! list )
|
||||
return;
|
||||
|
||||
if ( this.__running.has(event) )
|
||||
throw new Error(`concurrent access: tried to emit event while event is running`);
|
||||
|
||||
// Track removals separately to make iteration over the event list
|
||||
// much, much simpler.
|
||||
const removed = new Set;
|
||||
|
||||
// Set the current list of listeners to null because we don't want
|
||||
// to enter some kind of loop if a new listener is added as the result
|
||||
// of an existing listener.
|
||||
this.__listeners[event] = null;
|
||||
this.__running.add(event);
|
||||
|
||||
for(const item of list) {
|
||||
const [fn, ctx, ttl] = item,
|
||||
ret = fn.apply(ctx, args);
|
||||
|
@ -146,33 +159,50 @@ export class EventEmitter {
|
|||
break;
|
||||
}
|
||||
|
||||
// Remove any dead listeners from the list.
|
||||
if ( removed.size ) {
|
||||
// Re-grab the list to make sure it wasn't removed mid-iteration.
|
||||
const new_list = this.__listeners[event];
|
||||
if ( new_list ) {
|
||||
for(const item of removed) {
|
||||
const idx = new_list.indexOf(item);
|
||||
if ( idx !== -1 )
|
||||
new_list.splice(idx, 1);
|
||||
}
|
||||
|
||||
if ( ! list.length ) {
|
||||
this.__listeners[event] = null;
|
||||
this.__dead_events++;
|
||||
}
|
||||
for(const item of removed) {
|
||||
const idx = list.indexOf(item);
|
||||
if ( idx !== -1 )
|
||||
list.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Were more listeners added while we were running? Just combine
|
||||
// the two lists if so.
|
||||
if ( this.__listeners[event] )
|
||||
list = list.concat(this.__listeners[event]);
|
||||
|
||||
// If we have items, store the list back. Otherwise, mark that we
|
||||
// have a dead listener.
|
||||
if ( list.length )
|
||||
this.__listeners[event] = list;
|
||||
else {
|
||||
this.__listeners[event] = null;
|
||||
this.__dead_events++;
|
||||
}
|
||||
|
||||
this.__running.delete(event);
|
||||
}
|
||||
|
||||
emit(event, ...args) {
|
||||
const list = this.__listeners[event];
|
||||
let list = this.__listeners[event];
|
||||
if ( ! list )
|
||||
return;
|
||||
|
||||
if ( this.__running.has(event) )
|
||||
throw new Error(`concurrent access: tried to emit event while event is running`);
|
||||
|
||||
// Track removals separately to make iteration over the event list
|
||||
// much, much simpler.
|
||||
const removed = new Set;
|
||||
|
||||
// Set the current list of listeners to null because we don't want
|
||||
// to enter some kind of loop if a new listener is added as the result
|
||||
// of an existing listener.
|
||||
this.__listeners[event] = null;
|
||||
this.__running.add(event);
|
||||
|
||||
for(const item of list) {
|
||||
const [fn, ctx, ttl] = item;
|
||||
let ret;
|
||||
|
@ -196,34 +226,51 @@ export class EventEmitter {
|
|||
break;
|
||||
}
|
||||
|
||||
// Remove any dead listeners from the list.
|
||||
if ( removed.size ) {
|
||||
// Re-grab the list to make sure it wasn't removed mid-iteration.
|
||||
const new_list = this.__listeners[event];
|
||||
if ( new_list ) {
|
||||
for(const item of removed) {
|
||||
const idx = new_list.indexOf(item);
|
||||
if ( idx !== -1 )
|
||||
new_list.splice(idx, 1);
|
||||
}
|
||||
|
||||
if ( ! list.length ) {
|
||||
this.__listeners[event] = null;
|
||||
this.__dead_events++;
|
||||
}
|
||||
for(const item of removed) {
|
||||
const idx = list.indexOf(item);
|
||||
if ( idx !== -1 )
|
||||
list.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Were more listeners added while we were running? Just combine
|
||||
// the two lists if so.
|
||||
if ( this.__listeners[event] )
|
||||
list = list.concat(this.__listeners[event]);
|
||||
|
||||
// If we have items, store the list back. Otherwise, mark that we
|
||||
// have a dead listener.
|
||||
if ( list.length )
|
||||
this.__listeners[event] = list;
|
||||
else {
|
||||
this.__listeners[event] = null;
|
||||
this.__dead_events++;
|
||||
}
|
||||
|
||||
this.__running.delete(event);
|
||||
}
|
||||
|
||||
async emitAsync(event, ...args) {
|
||||
const list = this.__listeners[event];
|
||||
let list = this.__listeners[event];
|
||||
if ( ! list )
|
||||
return [];
|
||||
|
||||
if ( this.__running.has(event) )
|
||||
throw new Error(`concurrent access: tried to emit event while event is running`);
|
||||
|
||||
// Track removals separately to make iteration over the event list
|
||||
// much, much simpler.
|
||||
const removed = new Set,
|
||||
promises = [];
|
||||
|
||||
// Set the current list of listeners to null because we don't want
|
||||
// to enter some kind of loop if a new listener is added as the result
|
||||
// of an existing listener.
|
||||
this.__listeners[event] = null;
|
||||
this.__running.add(event);
|
||||
|
||||
for(const item of list) {
|
||||
const [fn, ctx] = item;
|
||||
let ret;
|
||||
|
@ -260,23 +307,31 @@ export class EventEmitter {
|
|||
|
||||
const out = await Promise.all(promises);
|
||||
|
||||
// Remove any dead listeners from the list.
|
||||
if ( removed.size ) {
|
||||
// Re-grab the list to make sure it wasn't removed mid-iteration.
|
||||
const new_list = this.__listeners[event];
|
||||
if ( new_list ) {
|
||||
for(const item of removed) {
|
||||
const idx = new_list.indexOf(item);
|
||||
if ( idx !== -1 )
|
||||
new_list.splice(idx, 1);
|
||||
}
|
||||
|
||||
if ( ! list.length ) {
|
||||
this.__listeners[event] = null;
|
||||
this.__dead_events++;
|
||||
}
|
||||
for(const item of removed) {
|
||||
const idx = list.indexOf(item);
|
||||
if ( idx !== -1 )
|
||||
list.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Were more listeners added while we were running? Just combine
|
||||
// the two lists if so.
|
||||
if ( this.__listeners[event] )
|
||||
list = list.concat(this.__listeners[event]);
|
||||
|
||||
// If we have items, store the list back. Otherwise, mark that we
|
||||
// have a dead listener.
|
||||
if ( list.length )
|
||||
this.__listeners[event] = list;
|
||||
else {
|
||||
this.__listeners[event] = null;
|
||||
this.__dead_events++;
|
||||
}
|
||||
|
||||
this.__running.delete(event);
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -488,7 +488,7 @@ const CARDINAL_TO_LANG = {
|
|||
hebrew: ['he'],
|
||||
persian: ['fa'],
|
||||
french: ['fr', 'pt'],
|
||||
russian: ['ru']
|
||||
russian: ['ru','uk']
|
||||
}
|
||||
|
||||
const CARDINAL_TYPES = {
|
||||
|
@ -536,7 +536,8 @@ const ORDINAL_TO_LANG = {
|
|||
hungarian: ['hu'],
|
||||
italian: ['it'],
|
||||
one: ['fr', 'lo', 'ms'],
|
||||
swedish: ['sv']
|
||||
swedish: ['sv'],
|
||||
ukranian: ['uk']
|
||||
};
|
||||
|
||||
const ORDINAL_TYPES = {
|
||||
|
@ -551,6 +552,12 @@ const ORDINAL_TYPES = {
|
|||
return 5;
|
||||
},
|
||||
|
||||
ukranian(n) {
|
||||
const n1 = n % 10, n2 = n % 100;
|
||||
if ( n1 === 3 && n2 !== 13 ) return 3;
|
||||
return 5;
|
||||
},
|
||||
|
||||
hungarian: n => (n === 1 || n === 5) ? 1 : 5,
|
||||
italian: n => (n === 11 || n === 8 || n === 80 || n === 800) ? 4 : 5,
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue