2017-11-14 04:12:10 -05:00
'use strict' ;
// ============================================================================
// Chat Scroller
// ============================================================================
2018-04-01 18:24:08 -04:00
import { createElement } from 'utilities/dom' ;
2018-03-14 13:58:04 -04:00
import Twilight from 'site' ;
2017-11-14 04:12:10 -05:00
import Module from 'utilities/module' ;
2018-07-09 21:35:31 -04:00
import { IS _FIREFOX } from 'utilities/constants' ;
2017-11-14 04:12:10 -05:00
export default class Scroller extends Module {
constructor ( ... args ) {
super ( ... args ) ;
this . inject ( 'settings' ) ;
this . inject ( 'i18n' ) ;
this . inject ( 'chat' ) ;
this . inject ( 'site.fine' ) ;
2018-03-03 16:38:50 -05:00
this . inject ( 'site.web_munch' ) ;
2017-11-14 04:12:10 -05:00
this . ChatScroller = this . fine . define (
'chat-scroller' ,
2018-03-14 13:58:04 -04:00
n => n . saveScrollRef && n . handleScrollEvent ,
Twilight . CHAT _ROUTES
2017-11-14 04:12:10 -05:00
) ;
this . settings . add ( 'chat.scroller.freeze' , {
default : 0 ,
ui : {
2018-07-09 21:35:31 -04:00
path : 'Chat > Behavior >> Scrolling @{"description": "Please note that FrankerFaceZ is dependant on Twitch\'s own scrolling code working correctly. There are bugs with Twitch\'s scrolling code that have existed for more than six months. If you are using Firefox, Edge, or other non-Webkit browsers, expect to have issues."}' ,
2017-11-14 04:12:10 -05:00
title : 'Freeze Chat Scrolling' ,
description : 'Automatically stop chat from scrolling when moving the mouse over it or holding a key.' ,
component : 'setting-select-box' ,
data : [
{ value : 0 , title : 'Disabled' } ,
{ value : 1 , title : 'On Hover' } ,
{ value : 2 , title : 'When Ctrl is Held' } ,
{ value : 3 , title : 'When Meta is Held' } ,
{ value : 4 , title : 'When Alt is Held' } ,
{ value : 5 , title : 'When Shift is Held' } ,
{ value : 6 , title : 'Ctrl or Hover' } ,
{ value : 7 , title : 'Meta or Hover' } ,
{ value : 8 , title : 'Alt or Hover' } ,
{ value : 9 , title : 'Shift or Hover' }
]
}
} ) ;
2018-07-03 18:18:39 -04:00
this . settings . add ( 'chat.scroller.smooth-scroll' , {
default : 0 ,
ui : {
2018-07-09 21:35:31 -04:00
path : 'Chat > Behavior >> Scrolling' ,
2018-07-03 18:18:39 -04:00
title : 'Smooth Scrolling' ,
2018-07-03 18:39:00 -04:00
description : 'Smoothly slide new chat messages into view. Speed will increase as necessary to keep up with chat.' ,
2018-07-03 18:18:39 -04:00
component : 'setting-select-box' ,
data : [
{ value : 0 , title : 'Disabled' } ,
{ value : 1 , title : 'Slow' } ,
{ value : 2 , title : 'Medium' } ,
{ value : 3 , title : 'Fast' } ,
{ value : 4 , title : 'Very Fast' }
]
}
} ) ;
2017-11-14 04:12:10 -05:00
}
2019-05-16 14:46:26 -04:00
updateUseKeys ( ) {
const old _use = this . use _keys ;
this . use _keys = false ;
for ( const act of this . chat . context . get ( 'chat.actions.inline' ) )
if ( act && act . display && act . display . keys )
this . use _keys = true ;
if ( this . use _keys !== old _use ) {
for ( const inst of this . ChatScroller . instances )
inst && inst . ffzUpdateKeys && inst . ffzUpdateKeys ( ) ;
}
}
2017-11-14 04:12:10 -05:00
onEnable ( ) {
2017-11-28 02:03:59 -05:00
this . on ( 'i18n:update' , ( ) => {
2017-11-14 04:12:10 -05:00
for ( const inst of this . ChatScroller . instances )
inst . ffzUpdateText ( ) ;
} ) ;
this . freeze = this . chat . context . get ( 'chat.scroller.freeze' ) ;
this . chat . context . on ( 'changed:chat.scroller.freeze' , val => {
this . freeze = val ;
2017-11-15 14:05:58 -05:00
for ( const inst of this . ChatScroller . instances ) {
inst . ffzDisableFreeze ( ) ;
if ( val !== 0 )
2017-11-14 04:12:10 -05:00
inst . ffzEnableFreeze ( ) ;
2017-11-15 14:05:58 -05:00
}
2017-11-14 04:12:10 -05:00
} ) ;
2019-05-16 14:46:26 -04:00
this . chat . context . on ( 'changed:chat.actions.inline' , this . updateUseKeys , this ) ;
this . updateUseKeys ( ) ;
2018-07-03 18:18:39 -04:00
this . smoothScroll = this . chat . context . get ( 'chat.scroller.smooth-scroll' ) ;
this . chat . context . on ( 'changed:chat.scroller.smooth-scroll' , val => {
this . smoothScroll = val ;
2018-07-03 18:39:00 -04:00
for ( const inst of this . ChatScroller . instances )
2018-07-03 18:18:39 -04:00
inst . ffzSetSmoothScroll ( val ) ;
} ) ;
2017-11-14 04:12:10 -05:00
this . ChatScroller . ready ( ( cls , instances ) => {
2018-03-03 16:38:50 -05:00
const t = this ,
old _catch = cls . prototype . componentDidCatch ,
old _render = cls . prototype . render ;
// Try catching errors. With any luck, maybe we can
// recover from the error when we re-build?
cls . prototype . componentDidCatch = function ( err , info ) {
// Don't log infinitely if stuff gets super screwed up.
const errs = this . state . ffz _errors || 0 ;
if ( errs < 100 ) {
this . setState ( {
ffz _errors : errs + 1 ,
ffz _total _errors : ( this . state . ffz _total _errors || 0 ) + 1
} ) ;
2018-04-11 17:05:31 -04:00
t . log . capture ( err , { extra : info } ) ;
2018-03-03 16:38:50 -05:00
t . log . info ( 'Error within Chat' , err , info , errs ) ;
}
if ( old _catch )
return old _catch . call ( this , err , info ) ;
}
cls . prototype . ffzZeroErrors = function ( ) {
this . setState ( { ffz _errors : 0 } ) ;
}
cls . prototype . render = function ( ) {
if ( this . state . ffz _errors > 0 ) {
let timer ;
const auto = this . state . ffz _total _errors < 10 ,
React = t . web _munch . getModule ( 'react' ) ,
2018-04-01 18:24:08 -04:00
createElement = React && React . createElement ,
2018-03-03 16:38:50 -05:00
handler = ( ) => {
clearTimeout ( timer ) ;
this . ffzZeroErrors ( ) ;
}
if ( auto )
timer = setTimeout ( handler , 250 ) ;
2018-04-01 18:24:08 -04:00
if ( ! createElement )
2018-03-03 16:38:50 -05:00
return null ;
2018-04-01 18:24:08 -04:00
return createElement ( 'div' , {
2018-09-25 18:37:14 -04:00
className : 'tw-border-l tw-c-background-alt-2 tw-c-text-base tw-full-width tw-full-height tw-align-items-center tw-flex tw-flex-column tw-justify-content-center tw-relative'
2018-03-03 16:38:50 -05:00
} , [
2018-04-01 18:24:08 -04:00
createElement ( 'div' , { className : 'tw-mg-b-1' } , 'There was an error displaying chat.' ) ,
! auto && createElement ( 'button' , {
2018-03-03 16:38:50 -05:00
className : 'tw-button' ,
onClick : handler
2018-04-01 18:24:08 -04:00
} , createElement ( 'span' , { className : 'tw-button__text' } , 'Try Again' ) )
2018-03-03 16:38:50 -05:00
] ) ;
} else
return old _render . call ( this ) ;
}
2017-11-14 04:12:10 -05:00
cls . prototype . ffzShouldBeFrozen = function ( since ) {
if ( since === undefined )
since = Date . now ( ) - this . ffz _last _move ;
const f = t . freeze ;
return ! this . ffz _outside && (
( this . ffz _ctrl && ( f === 2 || f === 6 ) ) ||
( this . ffz _meta && ( f === 3 || f === 7 ) ) ||
( this . ffz _alt && ( f === 4 || f === 8 ) ) ||
( this . ffz _shift && ( f === 5 || f === 9 ) ) ||
( since < 750 && ( f === 1 || f > 5 ) )
) ;
}
cls . prototype . ffzMaybeUnfreeze = function ( ) {
if ( this . ffz _frozen )
requestAnimationFrame ( ( ) => {
if ( this . ffz _frozen && ! this . ffzShouldBeFrozen ( ) )
this . ffzUnfreeze ( ) ;
} ) ;
}
cls . prototype . ffzUpdateText = function ( ) {
if ( ! this . _ffz _freeze _indicator )
return ;
const f = t . freeze ,
reason = f === 2 ? t . i18n . t ( 'key.ctrl' , 'Ctrl Key' ) :
f === 3 ? t . i18n . t ( 'key.meta' , 'Meta Key' ) :
2017-11-16 15:54:58 -05:00
f === 4 ? t . i18n . t ( 'key.alt' , 'Alt Key' ) :
f === 5 ? t . i18n . t ( 'key.shift' , 'Shift Key' ) :
f === 6 ? t . i18n . t ( 'key.ctrl_mouse' , 'Ctrl or Mouse' ) :
f === 7 ? t . i18n . t ( 'key.meta_mouse' , 'Meta or Mouse' ) :
f === 8 ? t . i18n . t ( 'key.alt_mouse' , 'Alt or Mouse' ) :
f === 9 ? t . i18n . t ( 'key.shift_mouse' , 'Shift or Mouse' ) :
t . i18n . t ( 'key.mouse' , 'Mouse Movement' ) ;
2017-11-14 04:12:10 -05:00
this . _ffz _freeze _indicator . firstElementChild . textContent = t . i18n . t (
'chat.paused' ,
2019-05-03 19:30:46 -04:00
'(Chat Paused Due to {reason})' ,
2017-11-14 04:12:10 -05:00
{ reason }
) ;
}
cls . prototype . ffzShowFrozen = function ( ) {
2017-11-16 15:54:58 -05:00
this . _ffz _freeze _visible = true ;
2017-11-14 04:12:10 -05:00
let el = this . _ffz _freeze _indicator ;
if ( ! el ) {
2018-02-22 18:38:13 -05:00
const node = t . fine . getChildNode ( this ) ;
2017-11-14 04:12:10 -05:00
if ( ! node )
return ;
2017-12-13 17:35:20 -05:00
node . classList . add ( 'tw-full-height' ) ;
2017-11-14 04:12:10 -05:00
2018-04-01 18:24:08 -04:00
el = this . _ffz _freeze _indicator = createElement ( 'div' , {
2017-12-13 17:35:20 -05:00
className : 'ffz--freeze-indicator chat-list__more-messages-placeholder tw-relative tw-mg-x-2'
2018-04-01 18:24:08 -04:00
} , createElement ( 'div' , {
2017-12-13 17:35:20 -05:00
className : 'chat-list__more-messages tw-bottom-0 tw-full-width tw-align-items-center tw-flex tw-justify-content-center tw-absolute tw-pd-05'
2017-11-14 04:12:10 -05:00
} ) ) ;
this . ffzUpdateText ( ) ;
node . appendChild ( el ) ;
} else
2017-12-13 17:35:20 -05:00
el . classList . remove ( 'tw-hide' ) ;
2017-11-14 04:12:10 -05:00
}
cls . prototype . ffzHideFrozen = function ( ) {
2017-11-16 15:54:58 -05:00
this . _ffz _freeze _visible = false ;
2017-11-14 04:12:10 -05:00
if ( this . _ffz _freeze _indicator )
2017-12-13 17:35:20 -05:00
this . _ffz _freeze _indicator . classList . add ( 'tw-hide' ) ;
2017-11-14 04:12:10 -05:00
}
cls . prototype . ffzFreeze = function ( ) {
if ( ! this . _ffz _interval )
this . _ffz _interval = setInterval ( ( ) => {
if ( ! this . ffzShouldBeFrozen ( ) )
2017-11-15 14:48:57 -05:00
this . ffzMaybeUnfreeze ( ) ;
2017-11-14 04:12:10 -05:00
} , 200 ) ;
this . ffz _frozen = true ;
this . setState ( { ffzFrozen : true } ) ;
2017-11-16 15:54:58 -05:00
//this.ffzShowFrozen();
2017-11-14 04:12:10 -05:00
}
cls . prototype . ffzUnfreeze = function ( ) {
if ( this . _ffz _interval ) {
clearInterval ( this . _ffz _interval ) ;
this . _ffz _interval = null ;
}
this . ffz _frozen = false ;
this . setState ( { ffzFrozen : false } ) ;
if ( this . state . isAutoScrolling )
this . scrollToBottom ( ) ;
2017-11-16 15:54:58 -05:00
//this.ffzHideFrozen();
}
2018-07-03 18:18:39 -04:00
cls . prototype . smoothScrollBottom = function ( ) {
2018-07-03 18:39:00 -04:00
if ( this . _ffz _smooth _animation )
cancelAnimationFrame ( this . _ffz _smooth _animation ) ;
this . ffz _is _smooth _scrolling = true ;
2018-07-03 18:18:39 -04:00
// Step setting value is # pixels to scroll per 10ms.
// 1 is pretty slow, 2 medium, 3 fast, 4 very fast.
2018-07-03 18:39:00 -04:00
let step = this . ffz _smooth _scroll ,
old _time = Date . now ( ) ;
2018-07-13 14:32:12 -04:00
const scroll _content = this . scroll . scrollContent ;
if ( ! scroll _content )
return ;
const target _top = scroll _content . scrollHeight - scroll _content . clientHeight ,
2018-07-03 18:39:00 -04:00
difference = target _top - scroll _content . scrollTop ;
2018-07-03 18:18:39 -04:00
// If we are falling behind speed us up
2018-07-03 18:39:00 -04:00
if ( difference > scroll _content . clientHeight ) {
2018-07-03 18:18:39 -04:00
// we are a full scroll away, just jump there
step = difference ;
2018-07-03 18:39:00 -04:00
} else if ( difference > 200 ) {
2018-07-03 18:18:39 -04:00
// we are starting to fall behind, speed it up a bit
2018-07-03 18:39:00 -04:00
step += step * Math . floor ( difference / 200 ) ;
2018-07-03 18:18:39 -04:00
}
2018-07-03 18:39:00 -04:00
2018-07-03 18:18:39 -04:00
const smoothAnimation = ( ) => {
2018-07-04 14:23:21 -04:00
if ( this . state . ffzFrozen || ! this . state . isAutoScrolling )
2018-07-03 18:39:00 -04:00
return this . ffz _is _smooth _scrolling = false ;
2018-07-03 18:18:39 -04:00
// See how much time has passed to get a step based off the delta
2018-07-03 18:39:00 -04:00
const current _time = Date . now ( ) ,
delta = current _time - old _time ,
current _step = step * ( delta / 10 ) ;
2018-07-03 18:18:39 -04:00
// we need to move at least one full pixel for scrollTop to do anything in this delta.
2018-07-03 18:39:00 -04:00
if ( current _step >= 1 ) {
const scroll _top = scroll _content . scrollTop ,
target _top = scroll _content . scrollHeight - scroll _content . clientHeight ;
old _time = current _time ;
if ( scroll _top < target _top ) {
scroll _content . scrollTop = scroll _top + current _step ;
this . _ffz _smooth _animation = requestAnimationFrame ( smoothAnimation ) ;
2018-07-03 18:18:39 -04:00
} else {
2018-07-03 18:39:00 -04:00
// We've reached the bottom.
scroll _content . scrollTop = target _top ;
this . ffz _is _smooth _scrolling = false ;
2018-07-03 18:18:39 -04:00
}
2018-07-03 18:39:00 -04:00
2018-07-03 18:18:39 -04:00
} else {
2018-07-03 18:39:00 -04:00
// The frame happened so quick since last update that we haven't moved a full pixel.
// Just wait.
this . _ffz _smooth _animation = requestAnimationFrame ( smoothAnimation ) ;
2018-07-03 18:18:39 -04:00
}
}
2018-07-03 18:39:00 -04:00
2018-07-03 18:18:39 -04:00
smoothAnimation ( ) ;
}
2017-11-16 15:54:58 -05:00
cls . prototype . ffzInstallHandler = function ( ) {
if ( this . _ffz _handleScroll )
return ;
const t = this ;
2019-04-30 15:18:29 -04:00
this . _doScroll = function ( ) {
if ( ! t . ffz _freeze _enabled || ! t . state . ffzFrozen ) {
if ( t . ffz _smooth _scroll )
t . smoothScrollBottom ( ) ;
2018-07-03 18:39:00 -04:00
else
2019-04-30 15:18:29 -04:00
t . _old _scroll ( ) ;
2018-07-03 18:18:39 -04:00
}
2018-01-15 20:40:54 -05:00
}
2019-04-30 15:18:29 -04:00
this . _old _scroll = this . scrollToBottom ;
this . scrollToBottom = function ( ) {
if ( this . _ffz _animation )
cancelAnimationFrame ( this . _ffz _animation ) ;
this . _ffz _animation = requestAnimationFrame ( t . _doScroll ) ;
}
2018-01-15 20:40:54 -05:00
this . _ffz _handleScroll = this . handleScrollEvent ;
2017-11-16 15:54:58 -05:00
this . handleScrollEvent = function ( e ) {
// If we're frozen because of FFZ, do not allow a mouse click to update
// the auto-scrolling state. That just gets annoying.
if ( e . type === 'mousedown' && t . ffz _frozen )
return ;
2017-11-22 15:39:38 -05:00
if ( t . scroll && e . type === 'touchmove' ) {
t . scroll . scrollContent . scrollHeight - t . scroll . scrollContent . scrollTop - t . scroll . scrollContent . offsetHeight <= 10 ? t . setState ( {
isAutoScrolling : ! 0
} ) : t . setState ( {
isAutoScrolling : ! 1
} )
}
2017-11-16 15:54:58 -05:00
return t . _ffz _handleScroll ( e ) ;
}
const scroller = this . scroll && this . scroll . scrollContent ;
if ( scroller ) {
scroller . removeEventListener ( 'mousedown' , this . _ffz _handleScroll ) ;
scroller . addEventListener ( 'mousedown' , this . handleScrollEvent ) ;
2017-11-22 15:39:38 -05:00
scroller . addEventListener ( 'touchmove' , this . handleScrollEvent ) ;
2017-11-16 15:54:58 -05:00
}
2017-11-14 04:12:10 -05:00
}
cls . prototype . ffzEnableFreeze = function ( ) {
2018-02-22 18:38:13 -05:00
const node = t . fine . getChildNode ( this ) ;
2017-11-14 04:12:10 -05:00
if ( ! node || this . ffz _freeze _enabled )
return ;
this . ffz _freeze _enabled = true ;
2017-11-15 14:05:58 -05:00
if ( t . freeze > 1 ) {
document . body . addEventListener ( 'keydown' ,
this . _ffz _key = this . ffzKey . bind ( this ) ) ;
2017-11-14 04:12:10 -05:00
2017-11-15 14:05:58 -05:00
document . body . addEventListener ( 'keyup' , this . _ffz _key ) ;
}
2017-11-14 04:12:10 -05:00
node . addEventListener ( 'mousemove' ,
this . _ffz _mousemove = this . ffzMouseMove . bind ( this ) ) ;
node . addEventListener ( 'mouseleave' ,
this . _ffz _mouseleave = this . ffzMouseLeave . bind ( this ) ) ;
}
cls . prototype . ffzDisableFreeze = function ( ) {
this . ffz _freeze _enabled = false ;
if ( this . ffz _frozen )
this . ffzUnfreeze ( ) ;
if ( this . _ffz _outside ) {
clearTimeout ( this . _ffz _outside ) ;
this . _ffz _outside = null ;
}
2018-02-22 18:38:13 -05:00
const node = t . fine . getChildNode ( this ) ;
2017-11-14 04:12:10 -05:00
if ( ! node )
return ;
2017-11-16 15:54:58 -05:00
this . _ffz _freeze _visible = false ;
2017-11-14 04:12:10 -05:00
if ( this . _ffz _freeze _indicator ) {
2017-12-01 15:36:18 -05:00
this . _ffz _freeze _indicator . remove ( ) ;
2017-11-14 04:12:10 -05:00
this . _ffz _freeze _indicator = null ;
}
if ( this . _ffz _key ) {
document . body . removeEventListener ( 'keyup' , this . _ffz _key ) ;
document . body . removeEventListener ( 'keydown' , this . _ffz _key ) ;
this . _ffz _key = null ;
}
if ( this . _ffz _mousemove ) {
node . removeEventListener ( 'mousemove' , this . _ffz _mousemove ) ;
this . _ffz _mousemove = null ;
}
if ( this . _ffz _mouseleave ) {
node . removeEventListener ( 'mouseleave' , this . _ffz _mouseleave ) ;
this . _ffz _mouseleave = null ;
}
}
cls . prototype . ffzKey = function ( e ) {
if ( e . altKey === this . ffz _alt &&
2017-11-16 15:54:58 -05:00
e . shiftKey === this . ffz _shift &&
e . ctrlKey === this . ffz _ctrl &&
e . metaKey === this . ffz _meta )
return ;
2017-11-14 04:12:10 -05:00
this . ffz _alt = e . altKey ;
this . ffz _shift = e . shiftKey ;
this . ffz _ctrl = e . ctrlKey ;
this . ffz _meta = e . metaKey ;
2019-05-16 14:46:26 -04:00
this . ffzUpdateKeys ( ) ;
2017-11-14 04:12:10 -05:00
if ( this . ffz _outside || t . freeze < 2 )
return ;
const should _freeze = this . ffzShouldBeFrozen ( ) ,
changed = should _freeze !== this . ffz _frozen ;
if ( changed )
if ( should _freeze )
this . ffzFreeze ( ) ;
else
this . ffzUnfreeze ( ) ;
}
2019-05-16 14:46:26 -04:00
cls . prototype . ffzUpdateKeys = function ( ) {
if ( ! this . _ffz _key _update )
this . _ffz _key _update = requestAnimationFrame ( ( ) => this . ffz _updateKeys ( ) ) ;
}
cls . prototype . ffz _updateKeys = function ( ) {
cancelAnimationFrame ( this . _ffz _key _update ) ;
this . _ffz _key _update = null ;
if ( ! t . use _keys && this . ffz _use _keys === t . use _keys )
return ;
if ( ! this . scroll || ! this . scroll . root )
return ;
this . ffz _use _keys = t . use _keys ;
this . scroll . root . classList . toggle ( 'ffz--keys' , t . use _keys ) ;
const ds = this . scroll . root . dataset ;
if ( ! t . use _keys ) {
delete ds . alt ;
delete ds . ctrl ;
delete ds . shift ;
delete ds . meta ;
} else {
ds . alt = ! this . ffz _outside && this . ffz _alt ;
ds . ctrl = ! this . ffz _outside && this . ffz _ctrl ;
ds . shift = ! this . ffz _outside && this . ffz _shift ;
ds . meta = ! this . ffz _outside && this . ffz _meta ;
}
}
2017-11-14 04:12:10 -05:00
cls . prototype . ffzMouseMove = function ( e ) {
this . ffz _last _move = Date . now ( ) ;
2019-05-16 14:46:26 -04:00
const was _outside = this . ffz _outside ;
2017-11-14 04:12:10 -05:00
this . ffz _outside = false ;
if ( this . _ffz _outside ) {
clearTimeout ( this . _ffz _outside ) ;
this . _ffz _outside = null ;
}
// If nothing of interest has happened, stop.
if ( e . altKey === this . ffz _alt &&
2017-11-16 15:54:58 -05:00
e . shiftKey === this . ffz _shift &&
e . ctrlKey === this . ffz _ctrl &&
e . metaKey === this . ffz _meta &&
e . screenY === this . ffz _sy &&
2019-05-16 14:46:26 -04:00
e . screenX === this . ffz _sx ) {
if ( was _outside )
this . ffzUpdateKeys ( ) ;
2017-11-16 15:54:58 -05:00
return ;
2019-05-16 14:46:26 -04:00
}
2017-11-14 04:12:10 -05:00
this . ffz _alt = e . altKey ;
this . ffz _shift = e . shiftKey ;
this . ffz _ctrl = e . ctrlKey ;
this . ffz _meta = e . metaKey ;
this . ffz _sy = e . screenY ;
this . ffz _sx = e . screenX ;
2019-05-16 14:46:26 -04:00
this . ffzUpdateKeys ( ) ;
2017-11-14 04:12:10 -05:00
const should _freeze = this . ffzShouldBeFrozen ( ) ,
changed = should _freeze !== this . ffz _frozen ;
if ( changed )
if ( should _freeze )
this . ffzFreeze ( ) ;
else
this . ffzUnfreeze ( ) ;
}
2017-11-16 15:54:58 -05:00
cls . prototype . ffzMouseLeave = function ( ) {
2017-11-14 04:12:10 -05:00
this . ffz _outside = true ;
if ( this . _ffz _outside )
clearTimeout ( this . _ffz _outside ) ;
this . _ffz _outside = setTimeout ( ( ) => this . ffzMaybeUnfreeze ( ) , 64 ) ;
2019-05-16 14:46:26 -04:00
this . ffzUpdateKeys ( ) ;
2017-11-14 04:12:10 -05:00
}
2018-07-03 18:18:39 -04:00
cls . prototype . ffzSetSmoothScroll = function ( value ) {
this . ffz _smooth _scroll = value ;
}
2017-11-14 04:12:10 -05:00
for ( const inst of instances )
this . onMount ( inst ) ;
} ) ;
this . ChatScroller . on ( 'mount' , this . onMount , this ) ;
this . ChatScroller . on ( 'unmount' , this . onUnmount , this ) ;
2017-11-16 15:54:58 -05:00
this . ChatScroller . on ( 'update' , inst => {
const should _show = inst . ffz _freeze _enabled && inst . state . ffzFrozen && inst . state . isAutoScrolling ,
changed = should _show !== inst . _ffz _freeze _visible ;
if ( changed )
if ( should _show )
inst . ffzShowFrozen ( ) ;
else
inst . ffzHideFrozen ( ) ;
} ) ;
2017-11-14 04:12:10 -05:00
}
onMount ( inst ) {
2017-11-16 15:54:58 -05:00
inst . ffzInstallHandler ( ) ;
2017-11-14 04:12:10 -05:00
if ( this . freeze !== 0 )
inst . ffzEnableFreeze ( ) ;
2018-07-03 18:18:39 -04:00
inst . ffzSetSmoothScroll ( this . smoothScroll ) ;
2017-11-14 04:12:10 -05:00
}
2017-11-16 15:54:58 -05:00
onUnmount ( inst ) { // eslint-disable-line class-methods-use-this
2017-11-14 04:12:10 -05:00
inst . ffzDisableFreeze ( ) ;
}
}