Skip to content

Commit 4e5c896

Browse files
Move to react for newlines, emoji, and links in message body
1 parent 721935b commit 4e5c896

File tree

15 files changed

+399
-28
lines changed

15 files changed

+399
-28
lines changed

background.html

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
<meta name="viewport" content="width=device-width, initial-scale=1">
99
<meta http-equiv="Content-Security-Policy"
1010
content="default-src 'none';
11+
child-src 'self';
1112
connect-src 'self' https: wss:;
12-
script-src 'self';
13-
style-src 'self' 'unsafe-inline';
14-
img-src 'self' blob: data:;
1513
font-src 'self';
14+
frame-src 'none';
15+
img-src 'self' blob: data:;
1616
media-src 'self' blob:;
17-
child-src 'self';
1817
object-src 'none'"
18+
script-src 'self';
19+
style-src 'self' 'unsafe-inline';
1920
>
2021
<title>Signal</title>
2122
<link href='images/icon_128.png' rel='shortcut icon'>
@@ -283,7 +284,7 @@ <h3>{{ welcomeToSignal }}</h3>
283284
{{ #hasBody }}
284285
<div class='content' dir='auto'>
285286
{{ #message }}
286-
<div class='body'>{{ message }}</div>
287+
<div class='body'></div>
287288
{{ /message }}
288289
</div>
289290
{{ /hasBody }}
@@ -375,7 +376,7 @@ <h3 class='name' dir='auto'>
375376
<span class='unread-count'>{{ unreadCount }}</span>
376377
{{ /unreadCount }}
377378
{{ #last_message }}
378-
<p class='last-message' dir='auto'> {{ last_message }} </p>
379+
<p class='last-message' dir='auto'></p>
379380
{{ /last_message }}
380381
</div>
381382
</script>

js/signal.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const { LightboxGallery } = require('../ts/components/LightboxGallery');
2323
const {
2424
MediaGallery,
2525
} = require('../ts/components/conversation/media-gallery/MediaGallery');
26+
const { MessageBody } = require('../ts/components/conversation/MessageBody');
2627
const { Quote } = require('../ts/components/conversation/Quote');
2728

2829
// Migrations
@@ -58,6 +59,7 @@ exports.setup = (options = {}) => {
5859
Lightbox,
5960
LightboxGallery,
6061
MediaGallery,
62+
MessageBody,
6163
Types: {
6264
Message: MediaGalleryMessage,
6365
},

js/views/conversation_list_item_view.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,14 @@
5555
},
5656

5757
render: function() {
58+
const lastMessage = this.model.get('lastMessage');
59+
5860
this.$el.html(
5961
Mustache.render(
6062
_.result(this, 'template', ''),
6163
{
6264
title: this.model.getTitle(),
63-
last_message: this.model.get('lastMessage'),
65+
last_message: Boolean(lastMessage),
6466
last_message_timestamp: this.model.get('timestamp'),
6567
number: this.model.getNumber(),
6668
avatar: this.model.getAvatar(),
@@ -74,7 +76,23 @@
7476
this.timeStampView.update();
7577

7678
emoji_util.parse(this.$('.name'));
77-
emoji_util.parse(this.$('.last-message'));
79+
80+
if (lastMessage) {
81+
if (this.bodyView) {
82+
this.bodyView.remove();
83+
this.bodyView = null;
84+
}
85+
this.bodyView = new Whisper.ReactWrapperView({
86+
className: 'body-wrapper',
87+
Component: window.Signal.Components.MessageBody,
88+
props: {
89+
text: lastMessage,
90+
disableJumbomoji: true,
91+
disableLinks: true,
92+
},
93+
});
94+
this.$('.last-message').append(this.bodyView.el);
95+
}
7896

7997
var unread = this.model.get('unreadCount');
8098
if (unread > 0) {

js/views/conversation_view.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1293,7 +1293,7 @@
12931293
className: 'quote-wrapper',
12941294
Component: window.Signal.Components.Quote,
12951295
props: Object.assign({}, props, {
1296-
text: props.text ? window.emoji.signalReplace(props.text) : null,
1296+
text: props.text,
12971297
onClose: () => {
12981298
this.setQuoteMessage(null);
12991299
},

js/views/message_view.js

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919

2020
window.Whisper = window.Whisper || {};
2121

22-
const URL_REGEX = /(^|[\s\n]|<br\/?>)((?:https?|ftp):\/\/[-A-Z0-9\u00A0-\uD7FF\uE000-\uFDCF\uFDF0-\uFFFD+\u0026\u2019@#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026@#/%=~()_|])/gi;
23-
2422
const ErrorIconView = Whisper.View.extend({
2523
templateName: 'error-icon',
2624
className: 'error-icon-container',
@@ -440,7 +438,7 @@
440438
className: 'quote-wrapper',
441439
Component: window.Signal.Components.Quote,
442440
props: Object.assign({}, props, {
443-
text: props.text ? window.emoji.signalReplace(props.text) : null,
441+
text: props.text,
444442
}),
445443
});
446444
this.$('.inner-bubble').prepend(this.quoteView.el);
@@ -566,11 +564,13 @@
566564
const hasAttachments = attachments && attachments.length > 0;
567565
const hasBody = this.hasTextContents();
568566

567+
const messageBody = this.model.get('body');
568+
569569
this.$el.html(
570570
Mustache.render(
571571
_.result(this, 'template', ''),
572572
{
573-
message: this.model.get('body'),
573+
message: Boolean(messageBody),
574574
hasBody,
575575
timestamp: this.model.get('sent_at'),
576576
sender: (contact && contact.getTitle()) || '',
@@ -589,17 +589,19 @@
589589

590590
this.renderControl();
591591

592-
const body = this.$('.body');
593-
594-
emoji_util.parse(body);
595-
596-
if (body.length > 0) {
597-
const escapedBody = body.html();
598-
body.html(
599-
escapedBody
600-
.replace(/\n/g, '<br>')
601-
.replace(URL_REGEX, "$1<a href='$2' target='_blank'>$2</a>")
602-
);
592+
if (messageBody) {
593+
if (this.bodyView) {
594+
this.bodyView.remove();
595+
this.bodyView = null;
596+
}
597+
this.bodyView = new Whisper.ReactWrapperView({
598+
className: 'body-wrapper',
599+
Component: window.Signal.Components.MessageBody,
600+
props: {
601+
text: messageBody,
602+
},
603+
});
604+
this.$('.body').append(this.bodyView.el);
603605
}
604606

605607
this.renderSent();

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"dependencies": {
4545
"@sindresorhus/is": "^0.8.0",
4646
"@types/google-libphonenumber": "^7.4.14",
47+
"@types/linkify-it": "^2.0.3",
4748
"archiver": "^2.1.1",
4849
"blob-util": "^1.3.0",
4950
"blueimp-canvas-to-blob": "^3.14.0",

stylesheets/_global.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ $avatar-size: 44px;
399399

400400
p {
401401
overflow-x: hidden;
402+
overflow-y: hidden;
403+
height: 1.2em;
402404
text-overflow: ellipsis;
403405
}
404406

test/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ <h3>{{ welcomeToSignal }}</h3>
211211
{{ #hasBody }}
212212
<div class='content' dir='auto'>
213213
{{ #message }}
214-
<div class='body'>{{ message }}</div>
214+
<div class='body'></div>
215215
{{ /message }}
216216
</div>
217217
{{ /hasBody }}
@@ -298,7 +298,7 @@ <h3 class='name' dir='auto'> {{ title }} </h3>
298298
<span class='unread-count'>{{ unreadCount }}</span>
299299
{{ /unreadCount }}
300300
{{ #last_message }}
301-
<p class='last-message' dir='auto'> {{ last_message }} </p>
301+
<p class='last-message' dir='auto'></p>
302302
{{ /last_message }}
303303
</div>
304304
</script>

test/styleguide/legacy_templates.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ window.Whisper.View.Templates = {
4242
{{ #hasBody }}
4343
<div class='content' dir='auto'>
4444
{{ #message }}
45-
<div class='body'>{{ message }}</div>
45+
<div class='body'></div>
4646
{{ /message }}
4747
</div>
4848
{{ /hasBody }}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React from 'react';
2+
3+
interface Props {
4+
text: string;
5+
}
6+
7+
export class AddNewLines extends React.Component<Props, {}> {
8+
public render() {
9+
const { text } = this.props;
10+
const results: Array<any> = [];
11+
const FIND_NEWLINES = /\n/g;
12+
13+
let match = FIND_NEWLINES.exec(text);
14+
let last = 0;
15+
let count = 1;
16+
17+
if (!match) {
18+
return <span>{text}</span>;
19+
}
20+
21+
while (match) {
22+
if (last < match.index) {
23+
const textWithNoNewline = text.slice(last, match.index);
24+
results.push(<span key={count++}>{textWithNoNewline}</span>);
25+
}
26+
27+
results.push(<br key={count++} />);
28+
29+
// @ts-ignore
30+
last = FIND_NEWLINES.lastIndex;
31+
match = FIND_NEWLINES.exec(text);
32+
}
33+
34+
if (last < text.length) {
35+
results.push(<span key={count++}>{text.slice(last)}</span>);
36+
}
37+
38+
return <span>{results}</span>;
39+
}
40+
}

0 commit comments

Comments
 (0)