1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-09-17 10:16:57 +00:00
* Changed: Metadata now uses the global FFZ tool-tip handler when rendering tool-tips.
* Fixed: Metadata pop-ups not appearing when an element is open fullscreen.
* API Added: Callback for changing popper options before opening a tool-tip.
* API Added: Timing for module loading. WIP.
This commit is contained in:
SirStendec 2020-07-23 02:33:20 -04:00
parent 1c2bf202fc
commit 3d88836a0e
9 changed files with 172 additions and 17 deletions

View file

@ -16,6 +16,7 @@ import {TranslationManager} from './i18n';
import SocketClient from './socket';
import Site from 'site';
import Vue from 'utilities/vue';
//import Timing from 'utilities/timing';
class FrankerFaceZ extends Module {
constructor() {
@ -29,6 +30,10 @@ class FrankerFaceZ extends Module {
this.__state = 0;
this.__modules.core = this;
// Timing
//this.inject('timing', Timing);
this.__time('instance');
// ========================================================================
// Error Reporting and Logging
// ========================================================================

View file

@ -18,6 +18,7 @@ export default class Metadata extends Module {
this.inject('settings');
this.inject('i18n');
this.inject('tooltips');
this.should_enable = true;
this.definitions = {};
@ -413,6 +414,43 @@ export default class Metadata extends Module {
}
}
onEnable() {
const md = this.tooltips.types.metadata = target => {
let el = target;
if ( el._ffz_stat )
el = el._ffz_stat;
else if ( ! el.classList.contains('ffz-stat') ) {
el = target.closest('.ffz-stat');
target._ffz_stat = el;
}
if ( ! el )
return;
const key = el.dataset.key,
def = this.definitions[key];
return maybe_call(def.tooltip, this, el._ffz_data)
};
md.onShow = (target, tip) => {
const el = target._ffz_stat || target;
el.tip = tip;
};
md.onHide = target => {
const el = target._ffz_stat || target;
el.tip = null;
el.tip_content = null;
}
md.popperConfig = (target, tip, opts) => {
opts.placement = 'bottom';
opts.modifiers.flip = {behavior: ['bottom','top']};
return opts;
}
}
get keys() {
return Object.keys(this.definitions);
@ -518,7 +556,8 @@ export default class Metadata extends Module {
tip_content={null}
>
{btn = (<button
class={`tw-align-items-center tw-align-middle tw-border-bottom-left-radius-medium tw-border-top-left-radius-medium tw-core-button tw-core-button--padded tw-core-button--text ${inherit ? 'ffz-c-text-inherit' : 'tw-c-text-base'} tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative ${border ? 'tw-border-l tw-border-t tw-border-b' : 'tw-font-size-5 tw-regular'}`}
class={`tw-align-items-center tw-align-middle tw-border-bottom-left-radius-medium tw-border-top-left-radius-medium tw-core-button tw-core-button--padded tw-core-button--text ${inherit ? 'ffz-c-text-inherit' : 'tw-c-text-base'} tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative ${border ? 'tw-border-l tw-border-t tw-border-b' : 'tw-font-size-5 tw-regular'}${def.tooltip ? ' ffz-tooltip ffz-tooltip--no-mouse' : ''}`}
data-tooltip-type="metadata"
>
<div class="tw-align-items-center tw-flex tw-flex-grow-0 tw-justify-center tw-pd-x-1">
{icon}
@ -526,7 +565,8 @@ export default class Metadata extends Module {
</div>
</button>)}
{popup = (<button
class={`tw-align-items-center tw-align-middle tw-border-bottom-right-radius-medium tw-border-top-right-radius-medium tw-core-button tw-core-button--text ${inherit ? 'ffz-c-text-inherit' : 'tw-c-text-base'} tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative ${border ? 'tw-border' : 'tw-font-size-5 tw-regular'}`}
class={`tw-align-items-center tw-align-middle tw-border-bottom-right-radius-medium tw-border-top-right-radius-medium tw-core-button tw-core-button--text ${inherit ? 'ffz-c-text-inherit' : 'tw-c-text-base'} tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative ${border ? 'tw-border' : 'tw-font-size-5 tw-regular'}${def.tooltip ? ' ffz-tooltip ffz-tooltip--no-mouse' : ''}`}
data-tooltip-type="metadata"
>
<div class="tw-align-items-center tw-flex tw-flex-grow-0 tw-justify-center">
<span>
@ -538,7 +578,8 @@ export default class Metadata extends Module {
} else
btn = popup = el = (<button
class={`ffz-stat tw-align-items-center tw-align-middle tw-border-bottom-left-radius-medium tw-border-top-left-radius-medium tw-border-bottom-right-radius-medium tw-border-top-right-radius-medium tw-core-button tw-core-button--text ${inherit ? 'ffz-c-text-inherit' : 'tw-c-text-base'} tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative tw-pd-x-05 ffz-stat--fix-padding ${border ? 'tw-border tw-mg-r-1' : 'tw-font-size-5 tw-regular tw-mg-r-05 ffz-mg-l--05'}`}
class={`ffz-stat tw-align-items-center tw-align-middle tw-border-bottom-left-radius-medium tw-border-top-left-radius-medium tw-border-bottom-right-radius-medium tw-border-top-right-radius-medium tw-core-button tw-core-button--text ${inherit ? 'ffz-c-text-inherit' : 'tw-c-text-base'} tw-inline-flex tw-interactive tw-justify-content-center tw-overflow-hidden tw-relative tw-pd-x-05 ffz-stat--fix-padding ${border ? 'tw-border tw-mg-r-1' : 'tw-font-size-5 tw-regular tw-mg-r-05 ffz-mg-l--05'}${def.tooltip ? ' ffz-tooltip ffz-tooltip--no-mouse' : ''}`}
data-tooltip-type="metadata"
data-key={key}
tip_content={null}
>
@ -596,7 +637,7 @@ export default class Metadata extends Module {
el._ffz_destroy = el._ffz_outside = null;
};
const parent = document.body.querySelector('#root>div') || document.body,
const parent = document.fullscreenElement || document.body.querySelector('#root>div') || document.body,
tt = el._ffz_popup = new Tooltip(parent, el, {
logger: this.log,
i18n: this.i18n,
@ -637,7 +678,8 @@ export default class Metadata extends Module {
icon = (<span class="tw-stat__icon"><figure class={icon} /></span>);
el = (<div
class="tw-align-items-center tw-inline-flex tw-relative tw-tooltip-wrapper ffz-stat tw-stat tw-mg-r-1"
class={`tw-align-items-center tw-inline-flex tw-relative tw-tooltip-wrapper ffz-stat tw-stat tw-mg-r-1${def.tooltip ? ' ffz-tooltip ffz-tooltip--no-mouse' : ''}`}
data-tooltip-type="metadata"
data-key={key}
tip_content={null}
>
@ -668,7 +710,7 @@ export default class Metadata extends Module {
subcontainer.appendChild(el);
if ( def.tooltip ) {
/*if ( def.tooltip ) {
const parent = document.body.querySelector('#root>div') || document.body;
el.tooltip = new Tooltip(parent, el, {
logger: this.log,
@ -692,7 +734,7 @@ export default class Metadata extends Module {
}
}
});
}
}*/
} else {
stat = el.querySelector('.ffz-stat-text');

View file

@ -93,6 +93,7 @@ export default class TooltipProvider extends Module {
onShow: this.delegateOnShow.bind(this),
onHide: this.delegateOnHide.bind(this),
popperConfig: this.delegatePopperConfig.bind(this),
popper: {
placement: 'top',
modifiers: {
@ -131,6 +132,16 @@ export default class TooltipProvider extends Module {
this.tips.cleanup();
}
delegatePopperConfig(target, tip, pop_opts) {
const type = target.dataset.tooltipType,
handler = this.types[type];
if ( handler && handler.popperConfig )
return handler.popperConfig(target, tip, pop_opts);
return pop_opts;
}
delegateOnShow(target, tip) {
const type = target.dataset.tooltipType,
handler = this.types[type];

View file

@ -163,7 +163,7 @@ export default class Channel extends Module {
}
_updateBar(el) {
if ( el._ffz_cont && ! el.contains(el._ffz_cont) ) {
if ( el._ffz_cont && ! document.contains(el._ffz_cont) ) {
el._ffz_cont.classList.remove('ffz--meta-tray');
el._ffz_cont = null;
}
@ -227,7 +227,7 @@ export default class Channel extends Module {
react = this.fine.getReactInstance(el),
props = react?.memoizedProps?.children?.props;
if ( ! cont || ! el.contains(cont) || ! props || ! props.channelID )
if ( ! cont || ! document.contains(cont) || ! props || ! props.channelID )
return;
if ( ! keys )

View file

@ -47,6 +47,7 @@ export class Module extends EventEmitter {
this.__state = this.onLoad || this.onEnable ?
State.DISABLED : State.ENABLED;
this.__time('instance');
this.emit(':registered');
}
@ -76,6 +77,20 @@ export class Module extends EventEmitter {
}
// ========================================================================
// Timing
// ========================================================================
__time(event) {
if ( this.root.timing ) {
if ( typeof event !== 'object' )
event = {event};
event.module = this.__path || 'core';
this.root.timing.addEvent(event);
}
}
// ========================================================================
// State! Glorious State
// ========================================================================
@ -115,6 +130,7 @@ export class Module extends EventEmitter {
chain.push(this);
this.__time('load-start');
this.__load_state = State.LOADING;
return this.__load_promise = (async () => {
if ( this.load_requires ) {
@ -130,17 +146,21 @@ export class Module extends EventEmitter {
await Promise.all(promises);
}
if ( this.onLoad )
if ( this.onLoad ) {
this.__time('load-self');
return this.onLoad(...args);
}
})().then(ret => {
this.__load_state = State.LOADED;
this.__load_promise = null;
this.__time('load-end');
this.emit(':loaded', this);
return ret;
}).catch(err => {
this.__load_state = State.UNLOADED;
this.__load_promise = null;
this.__time('load-end');
throw err;
});
}
@ -166,7 +186,7 @@ export class Module extends EventEmitter {
return Promise.reject(new CyclicDependencyError(`cyclic load requirements when unloading ${initial}`, chain));
chain.push(this);
this.__time('unload-start');
this.__load_state = State.UNLOADING;
return this.__load_promise = (async () => {
if ( this.__state !== State.DISABLED )
@ -185,16 +205,19 @@ export class Module extends EventEmitter {
await Promise.all(promises);
}
this.__time('unload-self');
return this.onUnload(...args);
})().then(ret => {
this.__load_state = State.UNLOADED;
this.__load_promise = null;
this.__time('unload-end');
this.emit(':unloaded', this);
return ret;
}).catch(err => {
this.__load_state = State.LOADED;
this.__load_promise = null;
this.__time('unload-end');
throw err;
});
}
@ -217,7 +240,7 @@ export class Module extends EventEmitter {
return Promise.reject(new CyclicDependencyError(`cyclic requirements when enabling ${initial}`, chain));
chain.push(this);
this.__time('enable-start');
this.__state = State.ENABLING;
return this.__state_promise = (async () => {
const promises = [],
@ -242,18 +265,22 @@ export class Module extends EventEmitter {
}
await Promise.all(promises);
if ( this.onEnable )
if ( this.onEnable ) {
this.__time('enable-self');
return this.onEnable(...args);
}
})().then(ret => {
this.__state = State.ENABLED;
this.__state_promise = null;
this.__time('enable-end');
this.emit(':enabled', this);
return ret;
}).catch(err => {
this.__state = State.DISABLED;
this.__state_promise = null;
this.__time('enable-end');
throw err;
});
}
@ -279,7 +306,7 @@ export class Module extends EventEmitter {
return Promise.reject(new CyclicDependencyError(`cyclic requirements when disabling ${initial}`, chain));
chain.push(this);
this.__time('disable-start');
this.__state = State.DISABLING;
return this.__state_promise = (async () => {
if ( this.__load_state !== State.LOADED )
@ -300,17 +327,20 @@ export class Module extends EventEmitter {
await Promise.all(promises);
}
this.__time('disable-self');
return this.onDisable(...args);
})().then(ret => {
this.__state = State.DISABLED;
this.__state_promise = null;
this.__time('disable-end');
this.emit(':disabled', this);
return ret;
}).catch(err => {
this.__state = State.ENABLED;
this.__state_promise = null;
this.__time('disable-end');
throw err;
});
}

24
src/utilities/timing.js Normal file
View file

@ -0,0 +1,24 @@
'use strict';
// ============================================================================
// Timing Tracker
// For figuring out FFZ loading
// ============================================================================
import Module from 'utilities/module';
export default class Timing extends Module {
constructor(...args) {
super(...args);
this.events = [];
}
__time() { /* no-op */ } // eslint-disable-line class-methods-use-this
addEvent(event) {
event.ts = performance.now();
this.events.push(event);
}
}

View file

@ -291,7 +291,7 @@ export class Tooltip {
const use_html = maybe_call(opts.html, null, target, tip),
setter = use_html ? 'innerHTML' : 'textContent';
const pop_opts = Object.assign({
let pop_opts = Object.assign({
modifiers: {
flip: {
behavior: ['top', 'bottom', 'left', 'right']
@ -300,6 +300,9 @@ export class Tooltip {
arrowElement: arrow
}, opts.popper);
if ( opts.popperConfig )
pop_opts = opts.popperConfig(target, tip, pop_opts) ?? pop_opts;
pop_opts.onUpdate = tip._on_update = debounce(() => {
if ( ! opts.no_auto_remove && ! document.contains(tip.target) )
this.hide(tip);