fix text selection in chat
fix auto-scrolling in chat
This commit is contained in:
parent
b53ff19876
commit
69552fbf10
|
@ -3,18 +3,27 @@
|
||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useRef, useLayoutEffect } from 'react';
|
import React, {
|
||||||
|
useRef, useLayoutEffect, useState, useEffect,
|
||||||
|
} from 'react';
|
||||||
import useStayScrolled from 'react-stay-scrolled';
|
import useStayScrolled from 'react-stay-scrolled';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { MAX_CHAT_MESSAGES } from '../core/constants';
|
||||||
import type { State } from '../reducers';
|
import type { State } from '../reducers';
|
||||||
import ChatInput from './ChatInput';
|
import ChatInput from './ChatInput';
|
||||||
|
import { saveSelection, restoreSelection } from '../utils/storeSelection';
|
||||||
import { colorFromText, splitCoordsInString } from '../core/utils';
|
import { colorFromText, splitCoordsInString } from '../core/utils';
|
||||||
|
|
||||||
|
|
||||||
function ChatMessage({ name, text, country }) {
|
function ChatMessage({ name, text, country }) {
|
||||||
|
if (!name || !text) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const msgText = text.trim();
|
const msgText = text.trim();
|
||||||
let className = 'msg';
|
|
||||||
const isInfo = (name === 'info');
|
const isInfo = (name === 'info');
|
||||||
|
let className = 'msg';
|
||||||
if (isInfo) {
|
if (isInfo) {
|
||||||
className += ' info';
|
className += ' info';
|
||||||
} else if (text.charAt(0) === '>') {
|
} else if (text.charAt(0) === '>') {
|
||||||
|
@ -27,28 +36,25 @@ function ChatMessage({ name, text, country }) {
|
||||||
{
|
{
|
||||||
(!isInfo)
|
(!isInfo)
|
||||||
&& (
|
&& (
|
||||||
<img
|
<span>
|
||||||
alt=""
|
<img
|
||||||
title={country}
|
alt=""
|
||||||
src={`${window.assetserver}/cf/${country}.gif`}
|
title={country}
|
||||||
onError={(e) => {
|
src={`${window.assetserver}/cf/${country}.gif`}
|
||||||
e.target.onerror = null;
|
onError={(e) => {
|
||||||
e.target.src = './cf/xx.gif';
|
e.target.onerror = null;
|
||||||
}}
|
e.target.src = './cf/xx.gif';
|
||||||
/>
|
}}
|
||||||
)
|
/>
|
||||||
}
|
<span
|
||||||
{
|
className="chatname"
|
||||||
(!isInfo)
|
style={{
|
||||||
&& (
|
color: colorFromText(name),
|
||||||
<span
|
}}
|
||||||
className="chatname"
|
>
|
||||||
style={{
|
|
||||||
color: colorFromText(name),
|
{name}
|
||||||
}}
|
</span>
|
||||||
>
|
|
||||||
|
|
||||||
{name}
|
|
||||||
:
|
:
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
@ -73,6 +79,7 @@ function ChatMessage({ name, text, country }) {
|
||||||
|
|
||||||
const Chat = ({ chatMessages, chatChannel }) => {
|
const Chat = ({ chatMessages, chatChannel }) => {
|
||||||
const listRef = useRef();
|
const listRef = useRef();
|
||||||
|
const [selection, setSelection] = useState(null);
|
||||||
const { stayScrolled } = useStayScrolled(listRef, {
|
const { stayScrolled } = useStayScrolled(listRef, {
|
||||||
initialScroll: Infinity,
|
initialScroll: Infinity,
|
||||||
});
|
});
|
||||||
|
@ -81,11 +88,23 @@ const Chat = ({ chatMessages, chatChannel }) => {
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
stayScrolled();
|
stayScrolled();
|
||||||
}, [channelMessages.length]);
|
}, [channelMessages.slice(-1)]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (channelMessages.length === MAX_CHAT_MESSAGES) {
|
||||||
|
restoreSelection(selection);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
|
||||||
<ul className="chatarea" ref={listRef} style={{ flexGrow: 1 }}>
|
<ul
|
||||||
|
className="chatarea"
|
||||||
|
ref={listRef}
|
||||||
|
style={{ flexGrow: 1 }}
|
||||||
|
onMouseUp={() => { setSelection(saveSelection); }}
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
{
|
{
|
||||||
channelMessages.map((message) => (
|
channelMessages.map((message) => (
|
||||||
<ChatMessage
|
<ChatMessage
|
||||||
|
|
|
@ -91,3 +91,4 @@ export const MONTH = 30 * DAY;
|
||||||
|
|
||||||
// available Chat Channels
|
// available Chat Channels
|
||||||
export const CHAT_CHANNELS = ['en', 'int'];
|
export const CHAT_CHANNELS = ['en', 'int'];
|
||||||
|
export const MAX_CHAT_MESSAGES = 100;
|
||||||
|
|
|
@ -44,6 +44,8 @@ async function exportVox(
|
||||||
canvas,
|
canvas,
|
||||||
centerPoint,
|
centerPoint,
|
||||||
) {
|
) {
|
||||||
|
// TODO deactivated cause its not finished
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
const { size: canvasSize, colors } = canvas;
|
const { size: canvasSize, colors } = canvas;
|
||||||
// round to chunk with its -x and -y corner closest to centerPoint
|
// round to chunk with its -x and -y corner closest to centerPoint
|
||||||
const [xc,, yc] = centerPoint.map((z) => {
|
const [xc,, yc] = centerPoint.map((z) => {
|
||||||
|
@ -94,6 +96,8 @@ async function exportVox(
|
||||||
// 4 * 256 palette content (rgba * 256 colors)
|
// 4 * 256 palette content (rgba * 256 colors)
|
||||||
const rgbaChunkSize = 4 * 256;
|
const rgbaChunkSize = 4 * 256;
|
||||||
const rgbaChunkLength = 4 + 4 + 4 + rgbaChunkSize;
|
const rgbaChunkLength = 4 + 4 + 4 + rgbaChunkSize;
|
||||||
|
// TODO deactivated cause its not finished
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
const rgbaPadding = [256, 256, 256, 256];
|
const rgbaPadding = [256, 256, 256, 256];
|
||||||
// Main Chunk
|
// Main Chunk
|
||||||
// 4 bytes MAIN
|
// 4 bytes MAIN
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
/* @flow */
|
/* @flow */
|
||||||
|
|
||||||
|
import { MAX_CHAT_MESSAGES } from '../core/constants';
|
||||||
|
|
||||||
import type { Action } from '../actions/types';
|
import type { Action } from '../actions/types';
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,7 +129,7 @@ export default function user(
|
||||||
} = action;
|
} = action;
|
||||||
const chatMessages = state.chatMessages.slice();
|
const chatMessages = state.chatMessages.slice();
|
||||||
let channelMessages = chatMessages[channel];
|
let channelMessages = chatMessages[channel];
|
||||||
if (channelMessages.length > 50) {
|
if (channelMessages.length > MAX_CHAT_MESSAGES) {
|
||||||
channelMessages = channelMessages.slice(-50);
|
channelMessages = channelMessages.slice(-50);
|
||||||
}
|
}
|
||||||
channelMessages = channelMessages.concat([
|
channelMessages = channelMessages.concat([
|
||||||
|
|
27
src/utils/storeSelection.js
Normal file
27
src/utils/storeSelection.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function saveSelection() {
|
||||||
|
if (window.getSelection) {
|
||||||
|
const sel = window.getSelection();
|
||||||
|
if (sel.getRangeAt && sel.rangeCount) {
|
||||||
|
return sel.getRangeAt(0);
|
||||||
|
}
|
||||||
|
} else if (document.selection && document.selection.createRange) {
|
||||||
|
return document.selection.createRange();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function restoreSelection(range) {
|
||||||
|
if (range) {
|
||||||
|
if (window.getSelection) {
|
||||||
|
const sel = window.getSelection();
|
||||||
|
sel.removeAllRanges();
|
||||||
|
sel.addRange(range);
|
||||||
|
} else if (document.selection && range.select) {
|
||||||
|
range.select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user