1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-10-11 13:41:57 +00:00
* 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:
SirStendec 2019-10-07 03:35:53 -04:00
parent 8c7e03119f
commit 02efd61f00
7 changed files with 180 additions and 118 deletions

View file

@ -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;
}
}

View file

@ -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,