diff --git a/src/main.js b/src/main.js index 04ccad1d..94c092c9 100644 --- a/src/main.js +++ b/src/main.js @@ -151,7 +151,7 @@ ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}` FrankerFaceZ.Logger = Logger; const VER = FrankerFaceZ.version_info = { - major: 4, minor: 3, revision: 1, + major: 4, minor: 3, revision: 2, commit: __git_commit__, build: __webpack_hash__, toString: () => diff --git a/src/modules/chat/actions/index.jsx b/src/modules/chat/actions/index.jsx index d93794b4..bef558bb 100644 --- a/src/modules/chat/actions/index.jsx +++ b/src/modules/chat/actions/index.jsx @@ -331,6 +331,7 @@ export default class Actions extends Module { manual: true, live: false, html: true, + hover_events: true, tooltipClass: 'ffz-action-balloon tw-balloon tw-block tw-border tw-elevation-1 tw-border-radius-small tw-c-background-base', arrowClass: 'tw-balloon__tail tw-overflow-hidden tw-absolute', @@ -350,10 +351,18 @@ export default class Actions extends Module { }, content, - onShow: (t, tip) => - setTimeout(() => { - target._ffz_outside = new ClickOutside(tip.outer, destroy) - }), + onShow: async (t, tip) => { + await tip.waitForDom(); + target._ffz_outside = new ClickOutside(tip.outer, destroy) + }, + + onMove: (target, tip, event) => { + this.emit('tooltips:mousemove', target, tip, event) + }, + + onLeave: (target, tip, event) => { + this.emit('tooltips:leave', target, tip, event); + }, onHide: destroy }); diff --git a/src/modules/tooltips.js b/src/modules/tooltips.js index 3fa4f525..9cd32b20 100644 --- a/src/modules/tooltips.js +++ b/src/modules/tooltips.js @@ -45,6 +45,7 @@ export default class TooltipProvider extends Module { delayShow: this.checkDelayShow.bind(this), content: this.process.bind(this), interactive: this.checkInteractive.bind(this), + hover_events: this.checkHoverEvents.bind(this), popper: { placement: 'top', modifiers: { @@ -55,6 +56,14 @@ export default class TooltipProvider extends Module { boundariesElement: container } } + }, + + onHover: (target, tip, event) => { + this.emit(':hover', target, tip, event) + }, + + onLeave: (target, tip, event) => { + this.emit(':leave', target, tip, event); } }); @@ -95,6 +104,16 @@ export default class TooltipProvider extends Module { return false; } + checkHoverEvents(target, tip) { + const type = target.dataset.tooltipType, + handler = this.types[type]; + + if ( has(handler, 'hover_events') ) + return maybe_call(handler.hover_events, null, target, tip); + + return false; + } + process(target, tip) { const type = target.dataset.tooltipType || 'text', handler = this.types[type]; @@ -103,7 +122,7 @@ export default class TooltipProvider extends Module { return [ createElement('strong', null, 'Unhandled Tooltip Type'), createElement('code', { - className: 'block pd-t-05 border-t mg-t-05', + className: 'tw-block pd-t-05 border-t mg-t-05', style: { fontFamily: 'monospace', textAlign: 'left' diff --git a/src/sites/twitch-twilight/modules/chat/scroller.js b/src/sites/twitch-twilight/modules/chat/scroller.js index 16f494e9..27d8b303 100644 --- a/src/sites/twitch-twilight/modules/chat/scroller.js +++ b/src/sites/twitch-twilight/modules/chat/scroller.js @@ -15,6 +15,8 @@ const SCROLL_EVENTS = [ 'DOMMouseScroll' ]; +let last_id = 0; + export default class Scroller extends Module { constructor(...args) { super(...args); @@ -221,6 +223,11 @@ export default class Scroller extends Module { this._ffz_installed = true; const inst = this; + this._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; @@ -443,6 +450,28 @@ export default class Scroller extends Module { this.ffzUpdateKeyTags(); } + cls.prototype.ffzTooltipHover = function(target, tip, event) { + if ( target[this._ffz_accessor] == null ) { + const scroller = this.scroll && this.scroll.scrollContent; + target[this._ffz_accessor] = scroller ? scroller.contains(target) : false; + } + + if ( target[this._ffz_accessor] ) + this.ffzMouseMove(event); + } + + cls.prototype.ffzTooltipLeave = function(target) { + if ( this.ffz_outside ) + return; + + if ( target[this._ffz_accessor] == null ) { + const scroller = this.scroll && this.scroll.scrollContent; + target[this._ffz_accessor] = scroller ? scroller.contains(target) : false; + } + + if ( target[this._ffz_accessor] ) + this.ffzMouseLeave(); + } // Keyboard Stuff @@ -509,7 +538,7 @@ export default class Scroller extends Module { } cls.prototype.listFooter = function() { - let msg; + let msg, cls = ''; if ( this.state.isPaused ) { const f = t.pause, reason = f === 2 ? t.i18n.t('key.ctrl', 'Ctrl Key') : @@ -523,6 +552,7 @@ export default class Scroller extends Module { t.i18n.t('key.mouse', 'Mouse Movement'); msg = t.i18n.t('chat.paused', '(Chat Paused Due to {reason})', {reason}); + cls = 'ffz--freeze-indicator'; } else if ( this.state.isAutoScrolling ) return null; @@ -530,7 +560,7 @@ export default class Scroller extends Module { msg = t.i18n.t('chat.messages-below', 'More messages below.'); 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', + 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)); } @@ -615,6 +645,9 @@ export default class Scroller extends Module { } onUnmount(inst) { // eslint-disable-line class-methods-use-this + this.off('tooltips:mousemove', inst.ffzTooltipHover, inst); + this.off('tooltips:leave', inst.ffzTooltipLeave, inst); + window.removeEventListener('keydown', inst.ffzHandleKey); window.removeEventListener('keyup', inst.ffzHandleKey); } diff --git a/src/sites/twitch-twilight/modules/directory/game.jsx b/src/sites/twitch-twilight/modules/directory/game.jsx index 755b1be4..9a48dd24 100644 --- a/src/sites/twitch-twilight/modules/directory/game.jsx +++ b/src/sites/twitch-twilight/modules/directory/game.jsx @@ -23,7 +23,7 @@ export default class Game extends SiteModule { this.GameHeader = this.fine.define( 'game-header', - n => n.props && n.props.data && n.renderDropsAvailable, + n => n.props && n.props.data && n.getBannerImage && n.getCategoryDisplayNameAndFollowButton, ['dir-game-index', 'dir-community', 'dir-game-videos', 'dir-game-clips', 'dir-game-details'] ); @@ -75,7 +75,7 @@ export default class Game extends SiteModule { if ( get('data.game', inst.props) == null || ! container || ! container.querySelector ) return; - const buttons = container.querySelector('.tw-flex > .tw-inline-flex'); + const buttons = container.querySelector('.tw-flex > .tw-flex-column'); if ( ! buttons ) return; @@ -107,7 +107,7 @@ export default class Game extends SiteModule { }; block_btn = (