diff --git a/src/components/Chat.jsx b/src/components/Chat.jsx
index 6e0bad1..3c6d623 100644
--- a/src/components/Chat.jsx
+++ b/src/components/Chat.jsx
@@ -13,23 +13,21 @@ import { MAX_CHAT_MESSAGES } from '../core/constants';
import type { State } from '../reducers';
import ChatInput from './ChatInput';
import { saveSelection, restoreSelection } from '../utils/storeSelection';
-import { colorFromText, splitCoordsInString } from '../core/utils';
+import { colorFromText, splitChatMessage } from '../core/utils';
-function ChatMessage({ name, text, country }) {
- if (!name || !text) {
+function ChatMessage({ name, msgArray, country }) {
+ if (!name || !msgArray) {
return null;
}
- const msgText = text.trim();
const isInfo = (name === 'info');
let className = 'msg';
if (isInfo) {
className += ' info';
- } else if (text.charAt(0) === '>') {
+ } else if (msgArray[0][1].charAt(0) === '>') {
className += ' greentext';
}
- const splitMsg = splitCoordsInString(msgText);
return (
@@ -60,26 +58,35 @@ function ChatMessage({ name, text, country }) {
)
}
{
- splitMsg.map((txt, i) => {
- if (i % 2 === 0) {
+ msgArray.map((msgPart) => {
+ const [type, txt] = msgPart;
+ if (type === 't') {
+ return ({txt});
+ } if (type === 'c') {
+ return ({txt});
+ } if (type === 'p') {
+ return ({txt});
+ } if (type === 'm') {
return (
- {txt}
-
+ className="mention"
+ style={{
+ color: colorFromText(txt),
+ }}
+ >{txt}
);
}
- return ({txt});
+ return null;
})
}
);
}
-const Chat = ({ chatMessages, chatChannel }) => {
+const Chat = ({ chatMessages, chatChannel, ownName }) => {
const listRef = useRef();
const [selection, setSelection] = useState(null);
+ const [nameRegExp, setNameRegExp] = useState(null);
const { stayScrolled } = useStayScrolled(listRef, {
initialScroll: Infinity,
});
@@ -94,7 +101,14 @@ const Chat = ({ chatMessages, chatChannel }) => {
if (channelMessages.length === MAX_CHAT_MESSAGES) {
restoreSelection(selection);
}
- });
+ }, [channelMessages]);
+
+ useEffect(() => {
+ const regExp = (ownName)
+ ? new RegExp(`(^|\\s+)(@${ownName})(\\s+|$)`, 'g')
+ : null;
+ setNameRegExp(regExp);
+ }, [ownName]);
return (
@@ -109,7 +123,7 @@ const Chat = ({ chatMessages, chatChannel }) => {
channelMessages.map((message) => (
))
@@ -121,9 +135,9 @@ const Chat = ({ chatMessages, chatChannel }) => {
};
function mapStateToProps(state: State) {
- const { chatMessages } = state.user;
+ const { chatMessages, name } = state.user;
const { chatChannel } = state.gui;
- return { chatMessages, chatChannel };
+ return { chatMessages, chatChannel, ownName: name };
}
export default connect(mapStateToProps)(Chat);
diff --git a/src/core/utils.js b/src/core/utils.js
index 15df479..ff1edf1 100644
--- a/src/core/utils.js
+++ b/src/core/utils.js
@@ -227,10 +227,55 @@ export function colorFromText(str: string) {
return `#${'00000'.substring(0, 6 - c.length)}${c}`;
}
+/*
+ * splits chat message into array of what it represents
+ * [[type, text],[type, text], ...]
+ * type:
+ * 't': text
+ * 'p': ping
+ * 'c': coordinates
+ * 'm': mention of somebody else
+ * nameRegExp has to be in the form of:
+ new RegExp(`(^|\\s+)(@${ownName})(\\s+|$)`, 'g');
+ */
const linkRegExp = /(#[a-z]*,-?[0-9]*,-?[0-9]*(,-?[0-9]+)?)/gi;
-export function splitCoordsInString(text) {
- const arr = text
- .split(linkRegExp)
- .filter((val, ind) => ((ind % 3) !== 2));
+const linkRegExpFilter = (val, ind) => ((ind % 3) !== 2);
+const mentionRegExp = /(^|\s+)(@\S+)(\s+|$)/g;
+const spaceFilter = (val) => (val !== ' ');
+
+function splitChatMessageRegexp(
+ msgArray,
+ regExp,
+ ident,
+ filter = () => true,
+) {
+ return msgArray.map((msgPart) => {
+ const [type, part] = msgPart;
+ if (type !== 't') {
+ return [msgPart];
+ }
+ return part
+ .split(regExp)
+ .filter(filter)
+ .map((stri, i) => {
+ if (i % 2 === 0) {
+ return ['t', stri];
+ }
+ return [ident, stri];
+ })
+ .filter((el) => !!el)
+ }).flat(1);
+}
+
+export function splitChatMessage(message, nameRegExp = null) {
+ if (!message) {
+ return null;
+ }
+ let arr = [['t', message.trim()]];
+ arr = splitChatMessageRegexp(arr, linkRegExp, 'c', linkRegExpFilter);
+ if (nameRegExp) {
+ arr = splitChatMessageRegexp(arr, nameRegExp, 'p', spaceFilter);
+ }
+ arr = splitChatMessageRegexp(arr, mentionRegExp, 'm', spaceFilter);
return arr;
}
diff --git a/src/styles/default.css b/src/styles/default.css
index 9d860de..3ccdbc1 100644
--- a/src/styles/default.css
+++ b/src/styles/default.css
@@ -403,6 +403,18 @@ tr:nth-child(even) {
.msg.greentext{
color: green;
}
+.ping {
+ background-color: #ffff87;
+ border-style: solid;
+ border-color: black;
+ border-width: 1px;
+ color: #1d1c1c;
+ border-radius: 6px;
+}
+.mention, .ping {
+ margin-left: 5px;
+ margin-right: 5px;
+}
#chatlink {
position: absolute;
font-weight: bold;