diff --git a/package.json b/package.json index 1aec96c5..c1250e3f 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.31.3", + "version": "4.31.4", "description": "FrankerFaceZ is a Twitch enhancement suite.", "private": true, "license": "Apache-2.0", diff --git a/src/modules/chat/emotes.js b/src/modules/chat/emotes.js index a7f1bcd9..3c81719b 100644 --- a/src/modules/chat/emotes.js +++ b/src/modules/chat/emotes.js @@ -498,6 +498,8 @@ export default class Emotes extends Module { if ( ! line || ! opener ) return; + const rect = target.getBoundingClientRect(); + opener.onShowEmoteCard({ channelID: line.props.channelID || '', channelLogin: line.props.channelLogin || '', @@ -505,7 +507,8 @@ export default class Emotes extends Module { emoteCode: target.alt, sourceID: 'chat', referrerID: '', - initialTopOffset: target.getBoundingClientRect().bottom + initialTopOffset: rect.bottom, + initialBottomOffset: rect.top }); return true; diff --git a/src/modules/main_menu/components/experiments.vue b/src/modules/main_menu/components/experiments.vue index 8c8bf48d..0a662175 100644 --- a/src/modules/main_menu/components/experiments.vue +++ b/src/modules/main_menu/components/experiments.vue @@ -237,7 +237,7 @@ export default { data() { return { code: pick_random(CODES), - experiments_locked: true, //this.item.is_locked(), + experiments_locked: this.item.is_locked(), sort_by: 1, unused: false, unique_id: this.item.unique_id(), diff --git a/src/sites/twitch-twilight/modules/chat/input.jsx b/src/sites/twitch-twilight/modules/chat/input.jsx index ff2540cf..008086ff 100644 --- a/src/sites/twitch-twilight/modules/chat/input.jsx +++ b/src/sites/twitch-twilight/modules/chat/input.jsx @@ -6,11 +6,44 @@ import Module from 'utilities/module'; import { findReactFragment } from 'utilities/dom'; +import { FFZEvent } from 'utilities/events'; +import { getTwitchEmoteSrcSet, has, getTwitchEmoteURL } from 'utilities/object'; import { TWITCH_POINTS_SETS, TWITCH_GLOBAL_SETS, TWITCH_PRIME_SETS, KNOWN_CODES, REPLACEMENTS, REPLACEMENT_BASE, KEYS } from 'utilities/constants'; import Twilight from 'site'; -import { FFZEvent } from 'src/utilities/events'; -import { getTwitchEmoteSrcSet, getTwitchEmoteURL } from 'src/utilities/object'; + +function getNodeText(node) { + if ( ! node ) + return ''; + + if ( node.type === 'emote' ) + return node.emoteName; + + if ( node.type === 'text' ) + return node.text; + + if ( Array.isArray(node.children) ) + return node.children.map(getNodeText).join(''); + + return ''; +} + +function getNodeOffset(nodes, path) { + let offset = 0, pidx = 0, n = nodes; + + while(pidx < path.length) { + const p = path[pidx]; + + for(let i = 0; i < p; i++) + offset += getNodeText(n[i]).length; + + n = Array.isArray(n[p]) ? n[p] : n[p]?.children; + pidx++; + } + + return offset; +} + export default class Input extends Module { constructor(...args) { @@ -329,6 +362,46 @@ export default class Input extends Module { inst.tempInput = ''; inst.messageHistoryPos = -1; + inst.ffzGetValue = function() { + if ( inst.chatInputRef && typeof inst.chatInputRef.value === 'string' ) + return inst.chatInputRef.value; + + if ( inst.state.value && typeof inst.state.value === 'string' ) + return inst.state.value; + + return ''; + } + + inst.ffzGetSelection = function() { + if ( typeof inst.chatInputRef?.selectionEnd === 'number' ) { + return [inst.chatInputRef.selectionStart, inst.chatInputRef.selectionEnd] + } + + if ( inst.chatInputRef?.state?.slateEditor ) { + const editor = inst.chatInputRef.state.slateEditor, + sel = editor.selection, + nodes = editor.children; + + if ( ! sel?.anchor?.path || ! sel?.focus?.path ) + return [0,0]; + + const first = getNodeOffset(nodes, sel.anchor.path) + sel.anchor.offset, + second = getNodeOffset(nodes, sel.focus.path) + sel.focus.offset; + + if ( first < second ) + return [first, second]; + else + return [second, first]; + } + + return [0,0]; + } + + inst.ffzSetSelection = function(start, end) { + if ( inst.chatInputRef?.setSelectionRange ) + inst.chatInputRef.setSelectionRange(start, end); + } + inst.onKeyDown = function(event) { try { const code = event.charCode || event.keyCode; @@ -339,33 +412,40 @@ export default class Input extends Module { return; } - if ( inst.autocompleteInputRef && t.chat.context.get('chat.mru.enabled') && ! event.shiftKey && ! event.ctrlKey && ! event.altKey ) { + const val = inst.ffzGetValue(); + + if ( inst.autocompleteInputRef && inst.chatInputRef && t.chat.context.get('chat.mru.enabled') && ! event.shiftKey && ! event.ctrlKey && ! event.altKey ) { + const sel = inst.ffzGetSelection(); + // Arrow Up - if ( code === 38 && inst.chatInputRef.selectionStart === 0 ) { + if ( code === 38 && sel[0] === 0 && sel[1] === 0 ) { if ( ! inst.messageHistory.length ) return; - if ( inst.chatInputRef.value && inst.messageHistoryPos === -1 ) - inst.tempInput = inst.chatInputRef.value; + if ( val && inst.messageHistoryPos === -1 ) + inst.tempInput = val; if ( inst.messageHistoryPos < inst.messageHistory.length - 1 ) { inst.messageHistoryPos++; inst.autocompleteInputRef.setValue(inst.messageHistory[inst.messageHistoryPos]); + inst.ffzSetSelection(0); } return; // Arrow Down - } else if ( code === 40 && inst.chatInputRef.selectionStart == inst.chatInputRef.value.length ) { + } else if ( code === 40 && sel[0] >= val.length && sel[1] === sel[0] ) { if ( ! inst.messageHistory.length ) return; if ( inst.messageHistoryPos > 0 ) { inst.messageHistoryPos--; inst.autocompleteInputRef.setValue(inst.messageHistory[inst.messageHistoryPos]); + inst.ffzSetSelection(inst.messageHistory[inst.messageHistoryPos].length); } else if ( inst.messageHistoryPos === 0 ) { inst.autocompleteInputRef.setValue(inst.tempInput); + inst.ffzSetSelection(inst.tempInput.length); inst.messageHistoryPos = -1; } @@ -392,9 +472,12 @@ export default class Input extends Module { inst.onMessageSend = function(event) { try { if ( t.chat.context.get('chat.mru.enabled') ) { - if (! inst.messageHistory.length || inst.messageHistory[0] !== inst.chatInputRef.value) { - inst.messageHistory.unshift(inst.chatInputRef.value); - inst.messageHistory = inst.messageHistory.slice(0, 20); + const val = inst.ffzGetValue(); + if (val && val.length) { + if (! inst.messageHistory.length || inst.messageHistory[0] !== val) { + inst.messageHistory.unshift(val); + inst.messageHistory = inst.messageHistory.slice(0, 20); + } } inst.messageHistoryPos = -1; inst.tempInput = '';