mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-03 16:38:31 +00:00
4.20.37
* Fixed: Chat scrolling after Twitch's update yesterday. * Fixed: In-line actions that depend on holding modifier keys not appearing correctly.
This commit is contained in:
parent
a771f337a4
commit
943e0fdc18
2 changed files with 55 additions and 194 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "frankerfacez",
|
||||
"author": "Dan Salvato LLC",
|
||||
"version": "4.20.36",
|
||||
"version": "4.20.37",
|
||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
|
|
|
@ -41,7 +41,7 @@ export default class Scroller extends Module {
|
|||
description: 'Automatically stop chat from scrolling when moving the mouse over it or holding a key.\n\n**Note:** Scrolling up in chat will always prevent automatic scrolling, regardless of this setting.',
|
||||
component: 'setting-select-box',
|
||||
data: [
|
||||
{value: 0, title: 'Disabled'},
|
||||
{value: 0, title: 'Use Twitch Setting'},
|
||||
{value: 1, title: 'On Hover'},
|
||||
{value: 2, title: 'When Ctrl is Held'},
|
||||
{value: 3, title: 'When Meta is Held'},
|
||||
|
@ -163,19 +163,8 @@ export default class Scroller extends Module {
|
|||
|
||||
this.ChatScroller.ready((cls, instances) => {
|
||||
const old_catch = cls.prototype.componentDidCatch,
|
||||
old_snapshot = cls.prototype.getSnapshotBeforeUpdate,
|
||||
old_render = cls.prototype.render;
|
||||
|
||||
if ( old_snapshot )
|
||||
cls.prototype.getSnapshotBeforeUpdate = function() {
|
||||
const out = old_snapshot.call(this);
|
||||
this._ffz_snapshot = out || (this.lastLine && {
|
||||
lastLine: this.lastLine,
|
||||
offsetTop: this.lastLine.offsetTop
|
||||
}) || null;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Try catching errors. With any luck, maybe we can
|
||||
// recover from the error when we re-build?
|
||||
cls.prototype.componentDidCatch = function(err, info) {
|
||||
|
@ -231,7 +220,7 @@ export default class Scroller extends Module {
|
|||
const children = out?.props?.children?.props?.children,
|
||||
child = children?.[2];
|
||||
|
||||
if ( child?.type?.displayName === 'ChatScrollFooter' )
|
||||
if ( child?.type?.displayName === 'ChatPausedFooter' )
|
||||
children[2] = this.ffzRenderFooter();
|
||||
} catch(err) { /* no-op */ }
|
||||
|
||||
|
@ -246,109 +235,37 @@ export default class Scroller extends Module {
|
|||
this._ffz_installed = true;
|
||||
const inst = this;
|
||||
|
||||
inst.ffz_oldScrollEvent = inst.handleScrollEvent;
|
||||
inst.ffz_oldScroll = inst.scrollToBottom;
|
||||
|
||||
inst.ffz_outside = true;
|
||||
inst._ffz_accessor = `_ffz_contains_${last_id++}`;
|
||||
|
||||
t.on('tooltips:mousemove', this.ffzTooltipHover, this);
|
||||
t.on('tooltips:leave', this.ffzTooltipLeave, this);
|
||||
|
||||
inst.ffz_oldScrollEvent = inst.handleScrollEvent;
|
||||
inst.ffz_oldScroll = inst.scrollToBottom;
|
||||
|
||||
// New Scroll to Bottom
|
||||
inst.ffz_doScroll = function() {
|
||||
inst._ffz_scroll_frame = null;
|
||||
if ( inst.state.isAutoScrolling && ! inst.state.isPaused ) {
|
||||
if ( inst.ffz_smooth_scroll && ! inst._ffz_one_fast_scroll )
|
||||
inst.smoothScrollBottom();
|
||||
else {
|
||||
inst._ffz_one_fast_scroll = false;
|
||||
inst._ffz_snapshot = null;
|
||||
inst.ffz_oldScroll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inst.scrollToBottom = function() {
|
||||
if ( inst._ffz_scroll_request )
|
||||
return;
|
||||
|
||||
inst._ffz_scroll_request = requestAnimationFrame(inst._scrollToBottom);
|
||||
}
|
||||
|
||||
inst._scrollToBottom = function() {
|
||||
inst._ffz_scroll_request = null;
|
||||
|
||||
// WIP: Trying to fix the scroll position changing so that we can
|
||||
// smooth scroll from the previous position.
|
||||
if ( inst.ffz_smooth_scroll && ! inst._ffz_one_fast_scroll && inst._ffz_snapshot ) {
|
||||
const adjustment = inst._ffz_snapshot && inst._ffz_snapshot.lastLine ? inst._ffz_snapshot.lastLine.offsetTop - inst._ffz_snapshot.offsetTop: 0;
|
||||
if ( inst.scroll && inst.scroll.scrollContent && adjustment != 0 )
|
||||
inst.scroll.scrollContent.scrollTop += adjustment;
|
||||
}
|
||||
|
||||
inst._ffz_snapshot = null;
|
||||
if ( inst.state.isAutoScrolling && ! inst.state.isPaused ) {
|
||||
if ( inst.ffz_smooth_scroll && ! inst._ffz_one_fast_scroll )
|
||||
inst.smoothScrollBottom();
|
||||
else {
|
||||
inst._ffz_one_fast_scroll = false;
|
||||
inst.ffz_oldScroll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New Scroll Event Handling
|
||||
inst.handleScrollEvent = function(event) {
|
||||
if ( ! inst.scroll || ! inst.scroll.scrollContent )
|
||||
if ( ! inst.scrollRef?.scrollContent )
|
||||
return;
|
||||
|
||||
// TODO: Check for mousedown?
|
||||
|
||||
if ( !(event.which > 0 || event.type === 'mousewheel' || event.type === 'wheel' || event.type === 'touchmove') )
|
||||
return;
|
||||
|
||||
// How far are we scrolled up?
|
||||
const scroller = inst.scroll.scrollContent,
|
||||
offset = scroller.scrollHeight - scroller.scrollTop - scroller.offsetHeight;
|
||||
const scroller = inst.scrollRef.scrollContent,
|
||||
offset = scroller.scrollHeight - scroller.scrollTop - scroller.offsetHeight,
|
||||
scrolled_up = offset > 10;
|
||||
|
||||
// If we're less than 10 pixels from the bottom and we aren't autoscrolling, resume
|
||||
if ( offset <= 10 && ! inst.state.isAutoScrolling )
|
||||
inst.resume();
|
||||
if ( scrolled_up !== inst.state.ffz_scrolled_up )
|
||||
inst.setState({ffz_scrolled_up: scrolled_up});
|
||||
|
||||
// If we are autoscrolling and we're more than 10 pixels up, then
|
||||
// stop autoscrolling without setting paused.
|
||||
else if ( inst.state.isAutoScrolling && offset > 10 ) {
|
||||
// If we're paused, unpause.
|
||||
if ( inst.state.isPaused ) {
|
||||
inst.setState({
|
||||
isPaused: false
|
||||
}, () => {
|
||||
if ( inst.props.setPaused )
|
||||
inst.props.setPaused(false);
|
||||
});
|
||||
if ( inst.state.isPaused && scrolled_up )
|
||||
inst.setLoadMoreEnabled(true);
|
||||
|
||||
inst.setLoadMoreEnabled(true);
|
||||
}
|
||||
|
||||
inst.setState({
|
||||
isAutoScrolling: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
inst.pause = function() {
|
||||
// If we already aren't scrolling, we don't want to further
|
||||
// pause things.
|
||||
if ( ! inst.state.isAutoScrolling )
|
||||
return;
|
||||
|
||||
inst.setState({
|
||||
isPaused: true
|
||||
}, () => {
|
||||
if ( inst.props.setPaused )
|
||||
inst.props.setPaused(true);
|
||||
});
|
||||
if ( inst.state.isPaused && ! scrolled_up )
|
||||
inst.ffzMaybeUnpause();
|
||||
else if ( ! inst.state.isPaused && scrolled_up )
|
||||
inst.pause();
|
||||
}
|
||||
|
||||
const old_resume = inst.resume;
|
||||
|
@ -359,9 +276,8 @@ export default class Scroller extends Module {
|
|||
}
|
||||
|
||||
inst.resume = function() {
|
||||
clearInterval(inst._ffz_hover_timer);
|
||||
inst._ffz_hover_timer = null;
|
||||
old_resume.call(inst);
|
||||
inst.setState({ffz_scrolled_up: false});
|
||||
old_resume.call(this);
|
||||
}
|
||||
|
||||
// Event Registration
|
||||
|
@ -383,7 +299,7 @@ export default class Scroller extends Module {
|
|||
if ( node )
|
||||
node.addEventListener('mousemove', inst.hoverPause);
|
||||
|
||||
const scroller = this.scroll && this.scroll.scrollContent;
|
||||
const scroller = this.scrollRef?.scrollContent;
|
||||
if ( scroller ) {
|
||||
for(const event of SCROLL_EVENTS) {
|
||||
scroller.removeEventListener(event, inst.ffz_oldScrollEvent);
|
||||
|
@ -424,7 +340,7 @@ export default class Scroller extends Module {
|
|||
|
||||
this.ffzUpdateKeyTags();
|
||||
|
||||
if ( (t.pause_hover && this.ffz_outside) || t.pause < 2 )
|
||||
if ( (t.pause_hover && this.ffz_outside) || this.ffzGetMode() < 2 )
|
||||
return;
|
||||
|
||||
const should_pause = this.ffzShouldBePaused(),
|
||||
|
@ -433,7 +349,8 @@ export default class Scroller extends Module {
|
|||
if ( changed )
|
||||
if ( should_pause ) {
|
||||
this.pause();
|
||||
this.setLoadMoreEnabled(false);
|
||||
if ( ! this.state.ffz_scrolled_up )
|
||||
this.setLoadMoreEnabled(false);
|
||||
} else
|
||||
this.resume();
|
||||
}
|
||||
|
@ -483,7 +400,8 @@ export default class Scroller extends Module {
|
|||
if ( should_pause ) {
|
||||
this.pause();
|
||||
this.ffzInstallHoverTimer();
|
||||
this.setLoadMoreEnabled(false);
|
||||
if ( ! this.state.ffz_scrolled_up )
|
||||
this.setLoadMoreEnabled(false);
|
||||
|
||||
} else
|
||||
this.resume();
|
||||
|
@ -500,7 +418,7 @@ export default class Scroller extends Module {
|
|||
|
||||
cls.prototype.ffzTooltipHover = function(target, tip, event) {
|
||||
if ( target[this._ffz_accessor] == null ) {
|
||||
const scroller = this.scroll && this.scroll.scrollContent;
|
||||
const scroller = this.scrollRef?.scrollContent;
|
||||
target[this._ffz_accessor] = scroller ? scroller.contains(target) : false;
|
||||
}
|
||||
|
||||
|
@ -513,7 +431,7 @@ export default class Scroller extends Module {
|
|||
return;
|
||||
|
||||
if ( target[this._ffz_accessor] == null ) {
|
||||
const scroller = this.scroll && this.scroll.scrollContent;
|
||||
const scroller = this.scrollRef?.scrollContent;
|
||||
target[this._ffz_accessor] = scroller ? scroller.contains(target) : false;
|
||||
}
|
||||
|
||||
|
@ -534,13 +452,13 @@ export default class Scroller extends Module {
|
|||
if ( ! t.use_keys && this.ffz_use_keys === t.use_keys )
|
||||
return;
|
||||
|
||||
if ( ! this.scroll || ! this.scroll.root )
|
||||
if ( ! this.scrollRef?.root )
|
||||
return;
|
||||
|
||||
this.ffz_use_keys = t.use_keys;
|
||||
this.scroll.root.classList.toggle('ffz--keys', t.use_keys);
|
||||
this.scrollRef.root.classList.toggle('ffz--keys', t.use_keys);
|
||||
|
||||
const ds = this.scroll.root.dataset;
|
||||
const ds = this.scrollRef.root.dataset;
|
||||
|
||||
if ( ! t.use_keys ) {
|
||||
delete ds.alt;
|
||||
|
@ -563,17 +481,34 @@ export default class Scroller extends Module {
|
|||
if ( since == null )
|
||||
since = Date.now() - this.ffz_last_move;
|
||||
|
||||
const mode = t.pause,
|
||||
if ( this.state.ffz_scrolled_up )
|
||||
return true;
|
||||
|
||||
const mode = this.ffzGetMode(),
|
||||
require_hover = t.pause_hover;
|
||||
|
||||
return (! require_hover || ! this.ffz_outside) && this.state.isAutoScrolling && (
|
||||
return (! require_hover || ! this.ffz_outside) && (
|
||||
(this.ffz_ctrl && (mode === 2 || mode === 6)) ||
|
||||
(this.ffz_meta && (mode === 3 || mode === 7)) ||
|
||||
(this.ffz_alt && (mode === 4 || mode === 8)) ||
|
||||
(this.ffz_shift && (mode === 5 || mode === 9)) ||
|
||||
(! this.ffz_outside && since < t.pause_delay && (mode === 1 || mode > 5))
|
||||
);
|
||||
}
|
||||
|
||||
cls.prototype.ffzGetMode = function() {
|
||||
let mode = t.pause;
|
||||
if ( mode === 0 && ! this.props.mouseoverPausingDisabled ) {
|
||||
const setting = this.props.pauseSetting;
|
||||
if ( setting === 'MOUSEOVER_ALTKEY' )
|
||||
mode = 8;
|
||||
else if ( setting === 'MOUSEOVER' )
|
||||
mode = 1;
|
||||
else if ( setting === 'ALTKEY' )
|
||||
mode = 4;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
cls.prototype.ffzMaybeUnpause = function() {
|
||||
|
@ -587,8 +522,10 @@ export default class Scroller extends Module {
|
|||
|
||||
cls.prototype.ffzRenderFooter = function() {
|
||||
let msg, cls = '';
|
||||
if ( this.state.isPaused ) {
|
||||
const f = t.pause,
|
||||
if ( this.state.ffz_scrolled_up )
|
||||
msg = t.i18n.t('chat.messages-below', 'Chat Paused Due to Scroll');
|
||||
else if ( this.state.isPaused ) {
|
||||
const f = this.ffzGetMode(),
|
||||
reason = f === 2 ? t.i18n.t('key.ctrl', 'Ctrl Key') :
|
||||
f === 3 ? t.i18n.t('key.meta', 'Meta Key') :
|
||||
f === 4 ? t.i18n.t('key.alt', 'Alt Key') :
|
||||
|
@ -602,12 +539,10 @@ export default class Scroller extends Module {
|
|||
msg = t.i18n.t('chat.paused', 'Chat Paused Due to {reason}', {reason});
|
||||
cls = 'ffz--freeze-indicator';
|
||||
|
||||
} else if ( this.state.isAutoScrolling )
|
||||
} else
|
||||
return createElement('div', {
|
||||
className: `chat-scroll-footer__placeholder tw-flex tw-justify-content-center tw-relative ${cls}`
|
||||
}, null);
|
||||
else
|
||||
msg = t.i18n.t('chat.messages-below', 'Chat Paused Due to Scroll');
|
||||
|
||||
return createElement('div', {
|
||||
className: `chat-scroll-footer__placeholder tw-flex tw-justify-content-center tw-relative ${cls}`
|
||||
|
@ -622,80 +557,6 @@ export default class Scroller extends Module {
|
|||
}, createElement('div', {
|
||||
className: 'tw-flex-grow-0'
|
||||
}, msg)))));
|
||||
|
||||
/*return createElement('div', {
|
||||
className: `chat-list__list-footer tw-absolute tw-align-items-center tw-border-radius-medium tw-bottom-0 tw-flex tw-justify-content-center tw-mg-b-1 tw-pd-x-2 tw-pd-y-05 ${cls}`,
|
||||
onClick: this.ffzFastResume
|
||||
}, createElement('div', null, msg));*/
|
||||
|
||||
/*return createElement('div', {
|
||||
className: `chat-list__list-footer tw-absolute tw-align-items-center tw-border-radius-medium tw-bottom-0 tw-flex tw-full-width tw-justify-content-center tw-pd-05 ${cls}`,
|
||||
onClick: this.ffzFastResume
|
||||
}, createElement('div', null, msg));*/
|
||||
}
|
||||
|
||||
cls.prototype.smoothScrollBottom = function() {
|
||||
if ( this._ffz_smooth_animation )
|
||||
cancelAnimationFrame(this._ffz_smooth_animation);
|
||||
|
||||
this.ffz_is_smooth_scrolling = true;
|
||||
|
||||
// Step setting value is # pixels to scroll per 10ms.
|
||||
// 1 is pretty slow, 2 medium, 3 fast, 4 very fast.
|
||||
let step = this.ffz_smooth_scroll,
|
||||
old_time = Date.now();
|
||||
|
||||
const scroll_content = this.scroll.scrollContent;
|
||||
if ( ! scroll_content )
|
||||
return;
|
||||
|
||||
const target_top = scroll_content.scrollHeight - scroll_content.clientHeight,
|
||||
difference = target_top - scroll_content.scrollTop;
|
||||
|
||||
// If we are falling behind speed us up
|
||||
if ( difference > scroll_content.clientHeight ) {
|
||||
// we are a full scroll away, just jump there
|
||||
step = difference;
|
||||
|
||||
} else if ( difference > 200 ) {
|
||||
// we are starting to fall behind, speed it up a bit
|
||||
step += step * Math.floor(difference / 200);
|
||||
}
|
||||
|
||||
const smoothAnimation = () => {
|
||||
if ( this.state.isPaused || ! this.state.isAutoScrolling )
|
||||
return this.ffz_is_smooth_scrolling = false;
|
||||
|
||||
// See how much time has passed to get a step based off the delta
|
||||
const current_time = Date.now(),
|
||||
delta = current_time - old_time,
|
||||
current_step = step * (delta / 10);
|
||||
|
||||
// we need to move at least one full pixel for scrollTop to do anything in this delta.
|
||||
if ( current_step >= 1 ) {
|
||||
const scroll_top = scroll_content.scrollTop,
|
||||
next_top = scroll_top + current_step,
|
||||
target_top = scroll_content.scrollHeight - scroll_content.clientHeight;
|
||||
|
||||
old_time = current_time;
|
||||
if ( next_top < target_top ) {
|
||||
scroll_content.scrollTop = scroll_top + current_step;
|
||||
this._ffz_smooth_animation = requestAnimationFrame(smoothAnimation);
|
||||
|
||||
} else {
|
||||
// We've reached the bottom.
|
||||
scroll_content.scrollTop = target_top;
|
||||
this.ffz_is_smooth_scrolling = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// The frame happened so quick since last update that we haven't moved a full pixel.
|
||||
// Just wait.
|
||||
this._ffz_smooth_animation = requestAnimationFrame(smoothAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
smoothAnimation();
|
||||
}
|
||||
|
||||
// Do the thing~
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue