diff --git a/app/mobile/src/session/conversation/topicItem/TopicItem.jsx b/app/mobile/src/session/conversation/topicItem/TopicItem.jsx
index d590eaf7..46bccc1c 100644
--- a/app/mobile/src/session/conversation/topicItem/TopicItem.jsx
+++ b/app/mobile/src/session/conversation/topicItem/TopicItem.jsx
@@ -162,8 +162,8 @@ export function TopicItem({ item, focused, focus, hosting, remove, update, block
)}
- { state.message && !state.sealed && (
- { state.message }
+ { state.clickable && !state.sealed && (
+ { state.clickable }
)}
{ state.sealed && (
sealed message
diff --git a/app/mobile/src/session/conversation/topicItem/useTopicItem.hook.js b/app/mobile/src/session/conversation/topicItem/useTopicItem.hook.js
index 7be7e10a..d3b5b4a1 100644
--- a/app/mobile/src/session/conversation/topicItem/useTopicItem.hook.js
+++ b/app/mobile/src/session/conversation/topicItem/useTopicItem.hook.js
@@ -20,6 +20,7 @@ export function useTopicItem(item, hosting, remove, contentKey) {
logo: null,
timestamp: null,
message: null,
+ clickable: null,
carousel: false,
carouselIndex: 0,
width: null,
@@ -92,12 +93,13 @@ export function useTopicItem(item, hosting, remove, contentKey) {
}
}
- let parsed, sealed, message, assets, fontSize, fontColor;
+ let parsed, sealed, message, clickable, assets, fontSize, fontColor;
if (dataType === 'superbasictopic') {
try {
sealed = false;
parsed = JSON.parse(data);
- message = clickableText(parsed.text);
+ message = parsed?.text;
+ clickable = clickableText(parsed.text);
assets = parsed.assets;
if (parsed.textSize === 'small') {
fontSize = 10;
@@ -140,7 +142,8 @@ export function useTopicItem(item, hosting, remove, contentKey) {
if (unsealed) {
sealed = false;
parsed = unsealed.message;
- message = clickableText(parsed?.text);
+ message = parsed?.text;
+ clickable = clickableText(parsed?.text);
if (parsed?.textSize === 'small') {
fontSize = 10;
}
@@ -179,7 +182,7 @@ export function useTopicItem(item, hosting, remove, contentKey) {
const editable = guid === identity?.guid && parsed;
const deletable = editable || hosting;
- updateState({ logo, name, nameSet, known, sealed, message, fontSize, fontColor, timestamp, transform, status, assets, deletable, editable, editData: parsed, editMessage: message, editType: dataType });
+ updateState({ logo, name, nameSet, known, sealed, message, clickable, fontSize, fontColor, timestamp, transform, status, assets, deletable, editable, editData: parsed, editMessage: message, editType: dataType });
}, [conversation.state, card.state, account.state, item, contentKey]);
const unsealTopic = async (topicId, revision, topicDetail) => {
@@ -206,7 +209,7 @@ export function useTopicItem(item, hosting, remove, contentKey) {
let clickable = [];
let group = '';
- const words = text == null ? '' : text.split(' ');
+ const words = text == null ? [''] : text.split(' ');
words.forEach((word, index) => {
if (!!pattern.test(word)) {
clickable.push({ group });
diff --git a/net/web/src/session/conversation/topicItem/TopicItem.jsx b/net/web/src/session/conversation/topicItem/TopicItem.jsx
index 4ab16f06..0136eb9b 100644
--- a/net/web/src/session/conversation/topicItem/TopicItem.jsx
+++ b/net/web/src/session/conversation/topicItem/TopicItem.jsx
@@ -7,7 +7,6 @@ import { Space, Skeleton, Button, Modal, Input } from 'antd';
import { ExclamationCircleOutlined, DeleteOutlined, EditOutlined, FireOutlined, PictureOutlined } from '@ant-design/icons';
import { Carousel } from 'carousel/Carousel';
import { useTopicItem } from './useTopicItem.hook';
-import * as DOMPurify from 'dompurify';
export function TopicItem({ host, sealed, topic, update, remove }) {
@@ -124,7 +123,7 @@ export function TopicItem({ host, sealed, topic, update, remove }) {
)}
{ !sealed && !state.editing && (
)}
{ state.editing && (
diff --git a/net/web/src/session/conversation/useConversation.hook.js b/net/web/src/session/conversation/useConversation.hook.js
index 58f84f89..ff1608b4 100644
--- a/net/web/src/session/conversation/useConversation.hook.js
+++ b/net/web/src/session/conversation/useConversation.hook.js
@@ -9,6 +9,7 @@ import { ProfileContext } from 'context/ProfileContext';
import { isUnsealed, getChannelSeals, getContentKey, encryptTopicSubject } from 'context/sealUtil';
import { decryptTopicSubject } from 'context/sealUtil';
import { getProfileByGuid } from 'context/cardUtil';
+import * as DOMPurify from 'dompurify';
export function useConversation(cardId, channelId) {
@@ -140,17 +141,21 @@ export function useConversation(cardId, channelId) {
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment locator
- let clickable = '';
- const words = text == null ? '' : text.split(' ');
- words.forEach(word => {
+ let group = '';
+ let clickable = [];
+ const words = text == null ? '' : DOMPurify.sanitize(text).split(' ');
+ words.forEach((word, index) => {
if (!!pattern.test(word)) {
- clickable += `${word} `;
+ clickable.push({ group });
+ group = '';
+ clickable.push({ `${word} ` });
}
else {
- clickable += `${word} `;
+ group += `${word} `;
}
})
- return `${clickable}
`;
+ clickable.push({ group });
+ return { clickable }
;
};
const syncTopic = (item, value) => {
@@ -210,14 +215,16 @@ export function useConversation(cardId, channelId) {
if (detail.dataType === 'superbasictopic') {
const message = JSON.parse(detail.data);
item.assets = message.assets;
- item.text = clickableText(message.text);
+ item.text = message.text;
+ item.clickable = clickableText(message.text);
item.textColor = message.textColor ? message.textColor : '#444444';
item.textSize = message.textSize ? message.textSize : 14;
}
if (detail.dataType === 'sealedtopic' && state.contentKey) {
const subject = decryptTopicSubject(detail.data, state.contentKey);
item.assets = subject.message.assets;
- item.text = clickableText(subject.message.text);
+ item.text = subject.message.text;
+ item.clickable = clickableText(subject.message.text);
item.textColor = subject.message.textColor ? subject.message.textColor : '#444444';
item.textSize = subject.message.textSize ? subject.message.textSize : 14;
}