image reply & invalid content fails, otherwise OK
This commit is contained in:
+6
-105
@@ -815,7 +815,7 @@ i.search {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.info-box > span {
|
.info-box > span {
|
||||||
line-height: 1.5rem;
|
line-height: 1.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-box .cancel {
|
.info-box .cancel {
|
||||||
@@ -2181,106 +2181,6 @@ ul.tabbar li.active > a {
|
|||||||
color: #D84315!important;
|
color: #D84315!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Colors of user mentions */
|
|
||||||
.mn-light-color0 {
|
|
||||||
color: #ef9a9a;
|
|
||||||
}
|
|
||||||
.mn-light-color1 {
|
|
||||||
color: #90caf9;
|
|
||||||
}
|
|
||||||
.mn-light-color2 {
|
|
||||||
color: #b0bec5;
|
|
||||||
}
|
|
||||||
.mn-light-color3 {
|
|
||||||
color: #b39ddb;
|
|
||||||
}
|
|
||||||
.mn-light-color4 {
|
|
||||||
color: #ffab91;
|
|
||||||
}
|
|
||||||
.mn-light-color5 {
|
|
||||||
color: #a5d6a7;
|
|
||||||
}
|
|
||||||
.mn-light-color6 {
|
|
||||||
color: #eeeeee;
|
|
||||||
}
|
|
||||||
.mn-light-color7 {
|
|
||||||
color: #e6ee9c;
|
|
||||||
}
|
|
||||||
.mn-light-color8 {
|
|
||||||
color: #c5e1a5;
|
|
||||||
}
|
|
||||||
.mn-light-color9 {
|
|
||||||
color: #f0e57d;
|
|
||||||
}
|
|
||||||
.mn-light-color10 {
|
|
||||||
color: #f48fb1;
|
|
||||||
}
|
|
||||||
.mn-light-color11 {
|
|
||||||
color: #9fa8da;
|
|
||||||
}
|
|
||||||
.mn-light-color12 {
|
|
||||||
color: #ffe082;
|
|
||||||
}
|
|
||||||
.mn-light-color13 {
|
|
||||||
color: #bcaaa4;
|
|
||||||
}
|
|
||||||
.mn-light-color14 {
|
|
||||||
color: #80deea;
|
|
||||||
}
|
|
||||||
.mn-light-color15 {
|
|
||||||
color: #ce93d8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Darker version of user mention colors */
|
|
||||||
.mn-dark-color0 {
|
|
||||||
color: #C62828;
|
|
||||||
}
|
|
||||||
.mn-dark-color1 {
|
|
||||||
color: #AD1457;
|
|
||||||
}
|
|
||||||
.mn-dark-color2 {
|
|
||||||
color: #6A1B9A;
|
|
||||||
}
|
|
||||||
.mn-dark-color3 {
|
|
||||||
color: #4527A0;
|
|
||||||
}
|
|
||||||
.mn-dark-color4 {
|
|
||||||
color: #283593;
|
|
||||||
}
|
|
||||||
.mn-dark-color5 {
|
|
||||||
color: #1565C0;
|
|
||||||
}
|
|
||||||
.mn-dark-color6 {
|
|
||||||
color: #0277BD;
|
|
||||||
}
|
|
||||||
.mn-dark-color7 {
|
|
||||||
color: #00838F;
|
|
||||||
}
|
|
||||||
.mn-dark-color8 {
|
|
||||||
color: #00695C;
|
|
||||||
}
|
|
||||||
.mn-dark-color9 {
|
|
||||||
color: #2E7D32;
|
|
||||||
}
|
|
||||||
.mn-dark-color10 {
|
|
||||||
color: #558B2F;
|
|
||||||
}
|
|
||||||
.mn-dark-color11 {
|
|
||||||
color: #9E9D24;
|
|
||||||
}
|
|
||||||
.mn-dark-color12 {
|
|
||||||
color: #F9A825;
|
|
||||||
}
|
|
||||||
.mn-dark-color13 {
|
|
||||||
color: #FF8F00;
|
|
||||||
}
|
|
||||||
.mn-dark-color14 {
|
|
||||||
color: #EF6C00;
|
|
||||||
}
|
|
||||||
.mn-dark-color15 {
|
|
||||||
color: #D84315;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Material icons resized from the default 24pt */
|
/* Material icons resized from the default 24pt */
|
||||||
.material-icons {
|
.material-icons {
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
@@ -2590,6 +2490,7 @@ ul.tabbar li.active > a {
|
|||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-box .bubble .reply-quote {
|
.chat-box .bubble .reply-quote {
|
||||||
@@ -2604,10 +2505,6 @@ ul.tabbar li.active > a {
|
|||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-quote-header {
|
|
||||||
color: #039be5;
|
|
||||||
}
|
|
||||||
|
|
||||||
#reply-quote-preview {
|
#reply-quote-preview {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -2624,3 +2521,7 @@ ul.tabbar li.active > a {
|
|||||||
min-width: 2.4rem;
|
min-width: 2.4rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mention {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -58,7 +58,7 @@ export function letterTileColorId(userId) {
|
|||||||
// params:
|
// params:
|
||||||
// - {string} id: user or topic ID
|
// - {string} id: user or topic ID
|
||||||
// - {boolean} light: light or dark version of the color.
|
// - {boolean} light: light or dark version of the color.
|
||||||
// - {boolean} fg: foreground or background color.
|
// - {boolean} fg: foreground (text) or background color.
|
||||||
export function idToColorClass(id, light, fg) {
|
export function idToColorClass(id, light, fg) {
|
||||||
return (light ? 'lt-' : 'dk-') + (fg ? 'fg-' : 'bg-') + letterTileColorId(id);
|
return (light ? 'lt-' : 'dk-') + (fg ? 'fg-' : 'bg-') + letterTileColorId(id);
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-209
@@ -19,9 +19,9 @@ import UploadingImage from '../widgets/uploading-image.jsx'
|
|||||||
|
|
||||||
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY, MESSAGES_PAGE,
|
import { DEFAULT_P2P_ACCESS_MODE, IMAGE_PREVIEW_DIM, KEYPRESS_DELAY, MESSAGES_PAGE,
|
||||||
MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE, READ_DELAY,
|
MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE, READ_DELAY,
|
||||||
IMAGE_THUMBNAIL_DIM, BROKEN_IMAGE_SIZE, REM_SIZE } from '../config.js';
|
IMAGE_THUMBNAIL_DIM } from '../config.js';
|
||||||
import { SUPPORTED_IMAGE_FORMATS, blobToBase64, base64ToBlob, filePasted, fileToBase64,
|
import { SUPPORTED_IMAGE_FORMATS, blobToBase64, base64ToBlob, filePasted, fileToBase64,
|
||||||
imageScaled, makeImageUrl, fitImageSize } from '../lib/blob-helpers.js';
|
imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
||||||
import HashNavigation from '../lib/navigation.js';
|
import HashNavigation from '../lib/navigation.js';
|
||||||
import { bytesToHumanSize, shortDateFormat, letterTileColorId } from '../lib/strformat.js';
|
import { bytesToHumanSize, shortDateFormat, letterTileColorId } from '../lib/strformat.js';
|
||||||
import { sanitizeImageUrl } from '../lib/utils.js';
|
import { sanitizeImageUrl } from '../lib/utils.js';
|
||||||
@@ -66,6 +66,11 @@ const messages = defineMessages({
|
|||||||
defaultMessage: 'Attachment',
|
defaultMessage: 'Attachment',
|
||||||
description: 'Comment for attachment in drafty preview'
|
description: 'Comment for attachment in drafty preview'
|
||||||
},
|
},
|
||||||
|
drafty_image: {
|
||||||
|
id: 'drafty_image',
|
||||||
|
defaultMessage: 'Picture',
|
||||||
|
description: 'Comment for embedded images in drafty preview'
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Checks if the access permissions are granted but not yet accepted.
|
// Checks if the access permissions are granted but not yet accepted.
|
||||||
@@ -679,7 +684,7 @@ class MessagesView extends React.Component {
|
|||||||
if (typeof msg == 'string') {
|
if (typeof msg == 'string') {
|
||||||
msg = Drafty.parse(msg);
|
msg = Drafty.parse(msg);
|
||||||
}
|
}
|
||||||
msg = Drafty.attachQuote(msg, this.state.reply.content);
|
msg = Drafty.append(this.state.reply.content, msg);
|
||||||
this.setState({reply: null});
|
this.setState({reply: null});
|
||||||
}
|
}
|
||||||
this.props.sendMessage(msg, uploadCompletionPromise, uploader, head);
|
this.props.sendMessage(msg, uploadCompletionPromise, uploader, head);
|
||||||
@@ -841,54 +846,48 @@ class MessagesView extends React.Component {
|
|||||||
uploader.cancel();
|
uploader.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePickReply(m) {
|
handlePickReply(seq, content) {
|
||||||
this.setState({reply: null});
|
this.setState({reply: null});
|
||||||
if (m) {
|
if (!seq || !content) {
|
||||||
let cont = m.content
|
return;
|
||||||
if (cont) {
|
|
||||||
if (typeof cont == 'string') {
|
|
||||||
cont = Drafty.init(cont);
|
|
||||||
}
|
}
|
||||||
cont = Drafty.preview(cont, 30, quotePreviewFmt);
|
|
||||||
|
if (typeof content == 'string') {
|
||||||
|
content = Drafty.init(content);
|
||||||
|
}
|
||||||
|
content = Drafty.preview(content, 30);
|
||||||
|
|
||||||
// Get the author.
|
// Get the author.
|
||||||
let header;
|
|
||||||
const seq = m.seq;
|
|
||||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||||
const m0 = topic.findMessage(seq);
|
const msg = topic.findMessage(seq);
|
||||||
let thisFrom;
|
let senderName, senderId;
|
||||||
if (m0) {
|
if (msg) {
|
||||||
thisFrom = m0.from || 'chan';
|
senderId = msg.from || 'chan';
|
||||||
if (thisFrom != this.props.myUserId) {
|
if (senderId != this.props.myUserId) {
|
||||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||||
const user = topic.userDesc(thisFrom);
|
const user = topic.userDesc(senderId);
|
||||||
if (user && user.public) {
|
if (user && user.public) {
|
||||||
header = user.public.fn;
|
senderName = user.public.fn;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
header = this.props.myUserName;
|
senderName = this.props.myUserName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header = Drafty.init(header || '');
|
|
||||||
// Make small image previews.
|
// Make small image previews.
|
||||||
const ents = [];
|
const ents = [];
|
||||||
if (cont.ent) {
|
Drafty.entities(content, (data, idx, tp) => {
|
||||||
Drafty.entities(cont, (data, idx, tp) => {
|
|
||||||
if (tp == 'IM') {
|
if (tp == 'IM') {
|
||||||
ents.push({
|
ents.push({
|
||||||
tp: tp,
|
tp: tp,
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn all images into thumbnails.
|
// Turn all images into thumbnails.
|
||||||
const promises = [];
|
const promises = ents.map((ex) => {
|
||||||
ents.map((ex) => {
|
return new Promise((resolve, reject) => {
|
||||||
let p = new Promise((resolve, reject) => {
|
|
||||||
const handleFailure = () => {
|
const handleFailure = () => {
|
||||||
ex.data.val = '';
|
ex.data.val = '';
|
||||||
ex.data.name = '';
|
ex.data.name = '';
|
||||||
@@ -940,8 +939,6 @@ class MessagesView extends React.Component {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
promises.push(p);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all(promises)
|
Promise.all(promises)
|
||||||
@@ -950,13 +947,13 @@ class MessagesView extends React.Component {
|
|||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
// All done. Create a reply quote.
|
// All done. Create a reply quote.
|
||||||
const msg = Drafty.createQuote(header, cont, letterTileColorId(thisFrom));
|
this.setState({
|
||||||
this.setState({reply: {content: msg, seq: m.seq}});
|
reply: {
|
||||||
|
content: Drafty.createQuote(senderName, senderId, content),
|
||||||
|
seq: seq
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCancelReply() {
|
handleCancelReply() {
|
||||||
@@ -999,7 +996,6 @@ class MessagesView extends React.Component {
|
|||||||
content={this.state.imagePreview}
|
content={this.state.imagePreview}
|
||||||
tinode={this.props.tinode}
|
tinode={this.props.tinode}
|
||||||
replyTo={this.state.reply}
|
replyTo={this.state.reply}
|
||||||
formatter={draftyFormatter}
|
|
||||||
onCancelReply={this.handleCancelReply}
|
onCancelReply={this.handleCancelReply}
|
||||||
onClose={this.handleClosePreview}
|
onClose={this.handleClosePreview}
|
||||||
onSendMessage={this.sendImageAttachment} />
|
onSendMessage={this.sendImageAttachment} />
|
||||||
@@ -1018,7 +1014,6 @@ class MessagesView extends React.Component {
|
|||||||
content={this.state.docPreview}
|
content={this.state.docPreview}
|
||||||
tinode={this.props.tinode}
|
tinode={this.props.tinode}
|
||||||
replyTo={this.state.reply}
|
replyTo={this.state.reply}
|
||||||
formatter={draftyFormatter}
|
|
||||||
onCancelReply={this.handleCancelReply}
|
onCancelReply={this.handleCancelReply}
|
||||||
onClose={this.handleClosePreview}
|
onClose={this.handleClosePreview}
|
||||||
onSendMessage={this.sendFileAttachment} />
|
onSendMessage={this.sendFileAttachment} />
|
||||||
@@ -1105,7 +1100,6 @@ class MessagesView extends React.Component {
|
|||||||
pickReply={this.handlePickReply}
|
pickReply={this.handlePickReply}
|
||||||
replyToSeq={replyToSeq}
|
replyToSeq={replyToSeq}
|
||||||
onQuoteClick={this.handleQuoteClick}
|
onQuoteClick={this.handleQuoteClick}
|
||||||
formatter={draftyFormatter}
|
|
||||||
ref={ref}
|
ref={ref}
|
||||||
userIsWriter={this.state.isWriter}
|
userIsWriter={this.state.isWriter}
|
||||||
key={msg.seq} />
|
key={msg.seq} />
|
||||||
@@ -1212,7 +1206,6 @@ class MessagesView extends React.Component {
|
|||||||
onError={this.props.onError}
|
onError={this.props.onError}
|
||||||
replyTo={this.state.reply}
|
replyTo={this.state.reply}
|
||||||
onQuoteClick={this.handleQuoteClick}
|
onQuoteClick={this.handleQuoteClick}
|
||||||
formatter={draftyFormatter}
|
|
||||||
onCancelReply={this.handleCancelReply} />}
|
onCancelReply={this.handleCancelReply} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -1224,172 +1217,4 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Transforms styles (and corresponding entities) for formatting reply quotes.
|
|
||||||
function quotePreviewFmt(fmt, ent) {
|
|
||||||
let tp = fmt.tp;
|
|
||||||
if (!tp) {
|
|
||||||
if (!ent || !ent.tp) {
|
|
||||||
return [null, null];
|
|
||||||
}
|
|
||||||
tp = ent.tp;
|
|
||||||
}
|
|
||||||
const new_fmt = {at: fmt.at, len: fmt.len, tp: fmt.tp};
|
|
||||||
switch (tp) {
|
|
||||||
case 'BR':
|
|
||||||
// Replace new line with a space.
|
|
||||||
return [null, null];
|
|
||||||
case 'HL':
|
|
||||||
return [new_fmt, ent];
|
|
||||||
case 'LN':
|
|
||||||
// Disable links in previews.
|
|
||||||
return [null, null];
|
|
||||||
case 'IM':
|
|
||||||
// Keep images as is.
|
|
||||||
return [new_fmt, ent];
|
|
||||||
case 'BN':
|
|
||||||
new_fmt.tp = null;
|
|
||||||
return [new_fmt, { tp: 'IC', data: { orig: 'BN', name: 'button'}}];
|
|
||||||
case 'FM':
|
|
||||||
new_fmt.tp = null;
|
|
||||||
return [new_fmt, {tp: 'IC', data: { orig: 'FM', name: 'form'}}];
|
|
||||||
case 'RW':
|
|
||||||
return [null, null];
|
|
||||||
case 'EX':
|
|
||||||
// Make it an icon.
|
|
||||||
new_fmt.tp = null;
|
|
||||||
if (new_fmt.at == -1) {
|
|
||||||
// Render it normally.
|
|
||||||
new_fmt.at = 0;
|
|
||||||
}
|
|
||||||
return [new_fmt, {tp: 'IC', data: { orig: 'EX', name: 'attachment'}}];
|
|
||||||
case 'QQ':
|
|
||||||
// Quote/citation.
|
|
||||||
return [null,null];
|
|
||||||
default:
|
|
||||||
return [new_fmt, ent];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Converts Drafty elements into React classes.
|
|
||||||
// 'this' is set by the caller.
|
|
||||||
function draftyFormatter(style, data, values, key) {
|
|
||||||
if (style == 'EX') {
|
|
||||||
// attachments are handled elsewhere.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let el = Drafty.tagName(style);
|
|
||||||
if (el) {
|
|
||||||
const { formatMessage } = this.props.intl;
|
|
||||||
let attr = Drafty.attrValue(style, data) || {};
|
|
||||||
attr.key = key;
|
|
||||||
switch (style) {
|
|
||||||
case 'HL':
|
|
||||||
// Highlighted text. Assign class name.
|
|
||||||
attr.className = 'highlight';
|
|
||||||
break;
|
|
||||||
case 'IM':
|
|
||||||
// Additional processing for images
|
|
||||||
if (data) {
|
|
||||||
attr.className = 'inline-image';
|
|
||||||
const dim = fitImageSize(data.width, data.height,
|
|
||||||
this.props.hasOwnProperty('viewportWidth') ? Math.min(this.props.viewportWidth - REM_SIZE * 6.5, REM_SIZE * 34.5) : REM_SIZE * 34.5,
|
|
||||||
REM_SIZE * 24, false) ||
|
|
||||||
{dstWidth: BROKEN_IMAGE_SIZE, dstHeight: BROKEN_IMAGE_SIZE};
|
|
||||||
attr.style = {
|
|
||||||
width: dim.dstWidth + 'px',
|
|
||||||
height: dim.dstHeight + 'px',
|
|
||||||
// Looks like a Chrome bug: broken image does not respect 'width' and 'height'.
|
|
||||||
minWidth: dim.dstWidth + 'px',
|
|
||||||
minHeight: dim.dstHeight + 'px'
|
|
||||||
};
|
|
||||||
if (!Drafty.isProcessing(data)) {
|
|
||||||
attr.src = this.props.tinode.authorizeURL(sanitizeImageUrl(attr.src));
|
|
||||||
attr.alt = data.name;
|
|
||||||
if (attr.src) {
|
|
||||||
if (Math.max(data.width || 0, data.height || 0) > IMAGE_THUMBNAIL_DIM) {
|
|
||||||
// Allow previews for large enough images.
|
|
||||||
attr.onClick = this.handleImagePreview;
|
|
||||||
attr.className += ' image-clickable';
|
|
||||||
}
|
|
||||||
attr.loading = 'lazy';
|
|
||||||
} else {
|
|
||||||
attr.src = 'img/broken_image.png';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Use custom element instead of <img>.
|
|
||||||
el = UploadingImage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Image element cannot have content.
|
|
||||||
values = null;
|
|
||||||
break;
|
|
||||||
case 'BN':
|
|
||||||
// Button
|
|
||||||
attr.onClick = this.handleFormButtonClick;
|
|
||||||
let inner = React.Children.map(values, (child) => {
|
|
||||||
return typeof child == 'string' ? child : undefined;
|
|
||||||
});
|
|
||||||
if (!inner || inner.length == 0) {
|
|
||||||
inner = [attr.name]
|
|
||||||
}
|
|
||||||
// Get text which will be sent back when the button is clicked.
|
|
||||||
attr['data-title'] = inner.join('');
|
|
||||||
break;
|
|
||||||
case 'MN':
|
|
||||||
// Mention
|
|
||||||
if (data && data.hasOwnProperty('colorId')) {
|
|
||||||
attr.className = 'mn-dark-color' + data.colorId;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'FM':
|
|
||||||
// Form
|
|
||||||
attr.className = 'bot-form';
|
|
||||||
break;
|
|
||||||
case 'RW':
|
|
||||||
// Form element formatting is dependent on element content.
|
|
||||||
break;
|
|
||||||
case 'QQ':
|
|
||||||
// Quote/citation.
|
|
||||||
attr.className = 'reply-quote'
|
|
||||||
attr.onClick = this.handleQuoteClick;
|
|
||||||
break;
|
|
||||||
case 'IC':
|
|
||||||
// Icon.
|
|
||||||
if (data.name == 'button') {
|
|
||||||
attr.className = 'flat-button faux';
|
|
||||||
} else {
|
|
||||||
const icons = {
|
|
||||||
form: {
|
|
||||||
name: 'dashboard', title: 'drafty_form'
|
|
||||||
},
|
|
||||||
attachment: {
|
|
||||||
name: 'attachment', title: 'drafty_attachment'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const icon = icons[data.name];
|
|
||||||
el = React.Fragment;
|
|
||||||
if (icon) {
|
|
||||||
const key = data.orig.toLowerCase();
|
|
||||||
values = [<i key={key} className="material-icons">{icon.name}</i>,
|
|
||||||
formatMessage(messages[icon.title])].concat(' ', values || []);
|
|
||||||
} else {
|
|
||||||
values = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (el == '_UNKN') {
|
|
||||||
// Unknown element.
|
|
||||||
el = React.Fragment;
|
|
||||||
values = [<i className="material-icons gray">extension</i>, ' '].concat(values || []);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return React.createElement(el, attr, values);
|
|
||||||
} else {
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default injectIntl(MessagesView);
|
export default injectIntl(MessagesView);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import Attachment from './attachment.jsx';
|
|||||||
import LetterTile from './letter-tile.jsx';
|
import LetterTile from './letter-tile.jsx';
|
||||||
import ReceivedMarker from './received-marker.jsx'
|
import ReceivedMarker from './received-marker.jsx'
|
||||||
|
|
||||||
|
import { fullFormatter, quoteFormatter } from '../lib/formatters.js';
|
||||||
import { sanitizeImageUrl, sanitizeUrl } from '../lib/utils.js';
|
import { sanitizeImageUrl, sanitizeUrl } from '../lib/utils.js';
|
||||||
|
|
||||||
class BaseChatMessage extends React.PureComponent {
|
class BaseChatMessage extends React.PureComponent {
|
||||||
@@ -27,6 +28,15 @@ class BaseChatMessage extends React.PureComponent {
|
|||||||
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
||||||
|
|
||||||
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
||||||
|
|
||||||
|
this.formatterContext = {
|
||||||
|
getFormatter: (tp) => { return tp == 'QQ' ? quoteFormatter : null; },
|
||||||
|
viewportWidth: this.props.viewportWidth,
|
||||||
|
authorizeURL: this.props.tinode.authorizeURL,
|
||||||
|
onImagePreview: this.handleImagePreview,
|
||||||
|
onFormButtonClick: this.handleFormButtonClick,
|
||||||
|
onQuoteClick: this.handleQuoteClick
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleImagePreview(e) {
|
handleImagePreview(e) {
|
||||||
@@ -117,7 +127,7 @@ class BaseChatMessage extends React.PureComponent {
|
|||||||
onError={this.props.onError}
|
onError={this.props.onError}
|
||||||
key={i} />);
|
key={i} />);
|
||||||
}, this);
|
}, this);
|
||||||
const tree = Drafty.format(content, this.props.formatter, this);
|
const tree = Drafty.format(content, fullFormatter, this.formatterContext);
|
||||||
content = React.createElement(React.Fragment, null, tree);
|
content = React.createElement(React.Fragment, null, tree);
|
||||||
} else if (this.props.deleted) {
|
} else if (this.props.deleted) {
|
||||||
// Message represents a range of deleted messages.
|
// Message represents a range of deleted messages.
|
||||||
|
|||||||
+4
-80
@@ -1,6 +1,6 @@
|
|||||||
// A single topic or user.
|
// A single topic or user.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
import ContactBadges from './contact-badges.jsx';
|
import ContactBadges from './contact-badges.jsx';
|
||||||
import LetterTile from './letter-tile.jsx';
|
import LetterTile from './letter-tile.jsx';
|
||||||
@@ -9,26 +9,9 @@ import UnreadBadge from './unread-badge.jsx';
|
|||||||
|
|
||||||
import { Drafty } from 'tinode-sdk';
|
import { Drafty } from 'tinode-sdk';
|
||||||
|
|
||||||
|
import { previewFormatter } from '../lib/formatters.js';
|
||||||
import { deliveryMarker } from '../lib/utils.js';
|
import { deliveryMarker } from '../lib/utils.js';
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
drafty_image: {
|
|
||||||
id: 'drafty_image',
|
|
||||||
defaultMessage: 'Picture',
|
|
||||||
description: 'Comment for embedded images in drafty preview'
|
|
||||||
},
|
|
||||||
drafty_form: {
|
|
||||||
id: 'drafty_form',
|
|
||||||
defaultMessage: 'Form: ',
|
|
||||||
description: 'Comment for form in drafty preview'
|
|
||||||
},
|
|
||||||
drafty_attachment: {
|
|
||||||
id: 'drafty_attachment',
|
|
||||||
defaultMessage: 'Attachment',
|
|
||||||
description: 'Comment for attachment in drafty preview'
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
class Contact extends React.Component {
|
class Contact extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -89,7 +72,8 @@ class Contact extends React.Component {
|
|||||||
const subtitle = this.props.preview ?
|
const subtitle = this.props.preview ?
|
||||||
(typeof this.props.preview == 'string' ? this.props.preview :
|
(typeof this.props.preview == 'string' ? this.props.preview :
|
||||||
Drafty.isValid(this.props.preview) ?
|
Drafty.isValid(this.props.preview) ?
|
||||||
React.createElement(React.Fragment, null, Drafty.format(this.props.preview, draftyFormatter, this)) :
|
React.createElement(React.Fragment, null, Drafty.format(this.props.preview, previewFormatter,
|
||||||
|
{formatMessage: this.props.intl.formatMessage})) :
|
||||||
<><i className="material-icons gray">error_outline</i> <i className="gray">
|
<><i className="material-icons gray">error_outline</i> <i className="gray">
|
||||||
<FormattedMessage id="invalid_content"
|
<FormattedMessage id="invalid_content"
|
||||||
defaultMessage="invalid content" description="Shown when message is unreadable" /></i>
|
defaultMessage="invalid content" description="Shown when message is unreadable" /></i>
|
||||||
@@ -134,64 +118,4 @@ class Contact extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Converts Drafty object into a one-line preview.
|
|
||||||
function draftyFormatter(style, data, values, key) {
|
|
||||||
let el = Drafty.tagName(style);
|
|
||||||
const attr = { key: key };
|
|
||||||
if (el) {
|
|
||||||
const { formatMessage } = this.props.intl;
|
|
||||||
switch (style) {
|
|
||||||
case 'BR':
|
|
||||||
// Replace new line with a space.
|
|
||||||
el = React.Fragment;
|
|
||||||
values = [' '];
|
|
||||||
break;
|
|
||||||
case 'HL':
|
|
||||||
// Make highlight less prominent in preview.
|
|
||||||
attr.className = 'highlight preview';
|
|
||||||
break;
|
|
||||||
case 'LN':
|
|
||||||
case 'MN':
|
|
||||||
// Disable links in previews.
|
|
||||||
el = 'span';
|
|
||||||
break;
|
|
||||||
case 'IM':
|
|
||||||
// Replace image with '[icon] Image'.
|
|
||||||
el = React.Fragment;
|
|
||||||
values = [<i key="im" className="material-icons">photo</i>, formatMessage(messages.drafty_image)];
|
|
||||||
break;
|
|
||||||
case 'BN':
|
|
||||||
el = 'span';
|
|
||||||
attr.className = 'flat-button faux';
|
|
||||||
break;
|
|
||||||
case 'FM':
|
|
||||||
el = React.Fragment;
|
|
||||||
values = [<i key="fm" className="material-icons">dashboard</i>,
|
|
||||||
formatMessage(messages.drafty_form)].concat(' ', values || []);
|
|
||||||
break;
|
|
||||||
case 'RW':
|
|
||||||
el = React.Fragment;
|
|
||||||
break;
|
|
||||||
case 'EX':
|
|
||||||
if (data && data.mime == 'application/json') {
|
|
||||||
// Ignore JSON attachments: they are form response payloads.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
el = React.Fragment;
|
|
||||||
values = [<i key="ex" className="material-icons">attachment</i>, formatMessage(messages.drafty_attachment)];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (el == '_UNKN') {
|
|
||||||
el = React.Fragment;
|
|
||||||
values = [<i key="unkn" className="material-icons">extension</i>, ' '].concat(values || []);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return React.createElement(el, attr, values);
|
|
||||||
} else {
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default injectIntl(Contact);
|
export default injectIntl(Contact);
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ class ContextMenu extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
replyToMessage(params, errorHandler) {
|
replyToMessage(params, errorHandler) {
|
||||||
params.pickReply({ seq: params.seq, content: params.content });
|
params.pickReply(params.seq, params.content, errorHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ export default class DocPreview extends React.PureComponent {
|
|||||||
noInput={true}
|
noInput={true}
|
||||||
tinode={this.props.tinode}
|
tinode={this.props.tinode}
|
||||||
replyTo={this.props.replyTo}
|
replyTo={this.props.replyTo}
|
||||||
formatter={this.props.formatter}
|
|
||||||
onCancelReply={this.props.onCancelReply}
|
onCancelReply={this.props.onCancelReply}
|
||||||
onSendMessage={this.handleSendDoc}
|
onSendMessage={this.handleSendDoc}
|
||||||
onError={this.props.onError} />
|
onError={this.props.onError} />
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ export default class ImagePreview extends React.PureComponent {
|
|||||||
acceptBlank={true}
|
acceptBlank={true}
|
||||||
tinode={this.props.tinode}
|
tinode={this.props.tinode}
|
||||||
replyTo={this.props.replyTo}
|
replyTo={this.props.replyTo}
|
||||||
formatter={this.props.formatter}
|
|
||||||
onCancelReply={this.props.onCancelReply}
|
onCancelReply={this.props.onCancelReply}
|
||||||
onSendMessage={this.handleSendImage}
|
onSendMessage={this.handleSendImage}
|
||||||
onError={this.props.onError} />
|
onError={this.props.onError} />
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Drafty } from 'tinode-sdk';
|
|||||||
|
|
||||||
import { KEYPRESS_DELAY } from '../config.js';
|
import { KEYPRESS_DELAY } from '../config.js';
|
||||||
import { filePasted } from '../lib/blob-helpers.js';
|
import { filePasted } from '../lib/blob-helpers.js';
|
||||||
|
import { quoteFormatter } from '../lib/formatters.js';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
messaging_disabled: {
|
messaging_disabled: {
|
||||||
@@ -160,10 +161,12 @@ class SendMessage extends React.PureComponent {
|
|||||||
formatMessage(messages[this.props.messagePrompt]) :
|
formatMessage(messages[this.props.messagePrompt]) :
|
||||||
formatMessage(messages.type_new_message));
|
formatMessage(messages.type_new_message));
|
||||||
|
|
||||||
let quote = null;
|
const quote = this.props.replyTo ?
|
||||||
if (this.props.replyTo) {
|
Drafty.format(this.props.replyTo.content, quoteFormatter, {
|
||||||
quote = Drafty.format(this.props.replyTo.content, this.props.formatter, this);
|
formatMessage: formatMessage,
|
||||||
}
|
authorizeURL: this.props.tinode.authorizeURL
|
||||||
|
}) :
|
||||||
|
null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="send-message-wrapper">
|
<div id="send-message-wrapper">
|
||||||
|
|||||||
+348
-379
@@ -349,6 +349,287 @@ function base64ToBlob(str, mime) {
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./src/lib/formatters.js":
|
||||||
|
/*!*******************************!*\
|
||||||
|
!*** ./src/lib/formatters.js ***!
|
||||||
|
\*******************************/
|
||||||
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||||
|
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||||
|
/* harmony export */ "fullFormatter": () => (/* binding */ fullFormatter),
|
||||||
|
/* harmony export */ "previewFormatter": () => (/* binding */ previewFormatter),
|
||||||
|
/* harmony export */ "quoteFormatter": () => (/* binding */ quoteFormatter)
|
||||||
|
/* harmony export */ });
|
||||||
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
|
||||||
|
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
||||||
|
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react-intl */ "react-intl");
|
||||||
|
/* harmony import */ var react_intl__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_intl__WEBPACK_IMPORTED_MODULE_1__);
|
||||||
|
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
|
||||||
|
/* harmony import */ var _blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./blob-helpers.js */ "./src/lib/blob-helpers.js");
|
||||||
|
/* harmony import */ var _strformat_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./strformat.js */ "./src/lib/strformat.js");
|
||||||
|
/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./utils.js */ "./src/lib/utils.js");
|
||||||
|
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
|
||||||
|
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_6__);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
||||||
|
drafty_form: {
|
||||||
|
id: "drafty_form",
|
||||||
|
defaultMessage: [{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Form:"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
drafty_attachment: {
|
||||||
|
id: "drafty_attachment",
|
||||||
|
defaultMessage: [{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Attachment"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
drafty_image: {
|
||||||
|
id: "drafty_image",
|
||||||
|
defaultMessage: [{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Picture"
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleImageData(el, data, attr) {
|
||||||
|
if (!data) {
|
||||||
|
attr.src = 'img/broken_image.png';
|
||||||
|
attr.style = {
|
||||||
|
width: _config_js__WEBPACK_IMPORTED_MODULE_2__.BROKEN_IMAGE_SIZE + 'px',
|
||||||
|
height: _config_js__WEBPACK_IMPORTED_MODULE_2__.BROKEN_IMAGE_SIZE + 'px',
|
||||||
|
minWidth: _config_js__WEBPACK_IMPORTED_MODULE_2__.BROKEN_IMAGE_SIZE + 'px',
|
||||||
|
minHeight: _config_js__WEBPACK_IMPORTED_MODULE_2__.BROKEN_IMAGE_SIZE + 'px'
|
||||||
|
};
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr.className = 'inline-image';
|
||||||
|
const dim = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_3__.fitImageSize)(data.width, data.height, this.viewportWidth > 0 ? Math.min(this.viewportWidth - _config_js__WEBPACK_IMPORTED_MODULE_2__.REM_SIZE * 6.5, _config_js__WEBPACK_IMPORTED_MODULE_2__.REM_SIZE * 34.5) : _config_js__WEBPACK_IMPORTED_MODULE_2__.REM_SIZE * 34.5, _config_js__WEBPACK_IMPORTED_MODULE_2__.REM_SIZE * 24, false) || {
|
||||||
|
dstWidth: _config_js__WEBPACK_IMPORTED_MODULE_2__.BROKEN_IMAGE_SIZE,
|
||||||
|
dstHeight: _config_js__WEBPACK_IMPORTED_MODULE_2__.BROKEN_IMAGE_SIZE
|
||||||
|
};
|
||||||
|
attr.style = {
|
||||||
|
width: dim.dstWidth + 'px',
|
||||||
|
height: dim.dstHeight + 'px',
|
||||||
|
minWidth: dim.dstWidth + 'px',
|
||||||
|
minHeight: dim.dstHeight + 'px'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.isProcessing(data)) {
|
||||||
|
attr.src = this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_5__.sanitizeImageUrl)(attr.src));
|
||||||
|
attr.alt = data.name;
|
||||||
|
|
||||||
|
if (attr.src) {
|
||||||
|
if (Math.max(data.width || 0, data.height || 0) > _config_js__WEBPACK_IMPORTED_MODULE_2__.IMAGE_THUMBNAIL_DIM) {
|
||||||
|
attr.onClick = this.onImagePreview;
|
||||||
|
attr.className += ' image-clickable';
|
||||||
|
}
|
||||||
|
|
||||||
|
attr.loading = 'lazy';
|
||||||
|
} else {
|
||||||
|
attr.src = 'img/broken_image.png';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
el = UploadingImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fullFormatter(style, data, values, key) {
|
||||||
|
if (style == 'EX') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.tagName(style);
|
||||||
|
|
||||||
|
if (el) {
|
||||||
|
const attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.attrValue(style, data) || {};
|
||||||
|
attr.key = key;
|
||||||
|
|
||||||
|
switch (style) {
|
||||||
|
case 'HL':
|
||||||
|
attr.className = 'highlight';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'IM':
|
||||||
|
el = handleImageData.call(this, el, data, attr);
|
||||||
|
values = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'BN':
|
||||||
|
attr.onClick = this.onFormButtonClick;
|
||||||
|
let inner = react__WEBPACK_IMPORTED_MODULE_0___default().Children.map(values, child => {
|
||||||
|
return typeof child == 'string' ? child : undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!inner || inner.length == 0) {
|
||||||
|
inner = [attr.name];
|
||||||
|
}
|
||||||
|
|
||||||
|
attr['data-title'] = inner.join('');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'MN':
|
||||||
|
if (data && data.hasOwnProperty('colorId')) {
|
||||||
|
attr.className = 'mn-dark-color' + data.colorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'FM':
|
||||||
|
attr.className = 'bot-form';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'RW':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'QQ':
|
||||||
|
attr.className = 'reply-quote';
|
||||||
|
attr.onClick = this.onQuoteClick;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (el == '_UNKN') {
|
||||||
|
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
||||||
|
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
|
className: "material-icons gray"
|
||||||
|
}, "extension"), ' '].concat(values || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values);
|
||||||
|
} else {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
function previewFormatter(style, data, values, key) {
|
||||||
|
let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.tagName(style);
|
||||||
|
const attr = {
|
||||||
|
key: key
|
||||||
|
};
|
||||||
|
|
||||||
|
if (el) {
|
||||||
|
switch (style) {
|
||||||
|
case 'BR':
|
||||||
|
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
||||||
|
values = [' '];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'HL':
|
||||||
|
attr.className = 'highlight preview';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'LN':
|
||||||
|
case 'MN':
|
||||||
|
el = 'span';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'IM':
|
||||||
|
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
||||||
|
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
|
key: "im",
|
||||||
|
className: "material-icons"
|
||||||
|
}, "photo"), this.formatMessage(messages.drafty_image)];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'BN':
|
||||||
|
el = 'span';
|
||||||
|
attr.className = 'flat-button faux';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'FM':
|
||||||
|
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
||||||
|
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
|
key: "fm",
|
||||||
|
className: "material-icons"
|
||||||
|
}, "dashboard"), this.formatMessage(messages.drafty_form)].concat(' ', values || []);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'RW':
|
||||||
|
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'EX':
|
||||||
|
if (data && data.mime == 'application/json') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
||||||
|
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
|
key: "ex",
|
||||||
|
className: "material-icons"
|
||||||
|
}, "attachment"), this.formatMessage(messages.drafty_attachment)];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (el == '_UNKN') {
|
||||||
|
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
||||||
|
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
|
key: "unkn",
|
||||||
|
className: "material-icons"
|
||||||
|
}, "extension"), ' '].concat(values || []);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values);
|
||||||
|
} else {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
function quoteFormatter(style, data, values, key) {
|
||||||
|
if (['BR', 'IM', 'MN', 'QQ'].includes(style)) {
|
||||||
|
let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.tagName(style);
|
||||||
|
const attr = tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.attrValue(style, data) || {};
|
||||||
|
attr.key = key;
|
||||||
|
|
||||||
|
switch (style) {
|
||||||
|
case 'IM':
|
||||||
|
el = handleImageData.call(this, el, data, attr);
|
||||||
|
values = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'MN':
|
||||||
|
el = 'span';
|
||||||
|
attr.className = 'mention';
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
attr.className += ' ' + (0,_strformat_js__WEBPACK_IMPORTED_MODULE_4__.idToColorClass)(data.val, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'QQ':
|
||||||
|
attr.className = 'reply-quote';
|
||||||
|
attr.onClick = this.onQuoteClick;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
return previewFormatter.call(this, style, data, values, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ "./src/lib/host-name.js":
|
/***/ "./src/lib/host-name.js":
|
||||||
/*!******************************!*\
|
/*!******************************!*\
|
||||||
!*** ./src/lib/host-name.js ***!
|
!*** ./src/lib/host-name.js ***!
|
||||||
@@ -2843,6 +3124,13 @@ const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
|||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Attachment"
|
"value": "Attachment"
|
||||||
}]
|
}]
|
||||||
|
},
|
||||||
|
drafty_image: {
|
||||||
|
id: "drafty_image",
|
||||||
|
defaultMessage: [{
|
||||||
|
"type": 0,
|
||||||
|
"value": "Picture"
|
||||||
|
}]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2870,6 +3158,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
this.state = MessagesView.getDerivedStateFromProps(props, {});
|
this.state = MessagesView.getDerivedStateFromProps(props, {});
|
||||||
this.leave = this.leave.bind(this);
|
this.leave = this.leave.bind(this);
|
||||||
this.sendMessage = this.sendMessage.bind(this);
|
this.sendMessage = this.sendMessage.bind(this);
|
||||||
|
this.retrySend = this.retrySend.bind(this);
|
||||||
this.sendImageAttachment = this.sendImageAttachment.bind(this);
|
this.sendImageAttachment = this.sendImageAttachment.bind(this);
|
||||||
this.sendFileAttachment = this.sendFileAttachment.bind(this);
|
this.sendFileAttachment = this.sendFileAttachment.bind(this);
|
||||||
this.sendKeyPress = this.sendKeyPress.bind(this);
|
this.sendKeyPress = this.sendKeyPress.bind(this);
|
||||||
@@ -3138,7 +3427,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
this.props.onNewTopicCreated(this.props.topic, ctrl.topic);
|
this.props.onNewTopicCreated(this.props.topic, ctrl.topic);
|
||||||
topic.queuedMessages(pub => {
|
topic.queuedMessages(pub => {
|
||||||
if (!pub._sending && topic.isSubscribed()) {
|
if (!pub._sending && topic.isSubscribed()) {
|
||||||
this.sendMessage(pub);
|
this.retrySend(pub);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
@@ -3490,7 +3779,7 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
msg = Drafty.parse(msg);
|
msg = Drafty.parse(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = Drafty.attachQuote(msg, this.state.reply.content);
|
msg = Drafty.append(this.state.reply.content, msg);
|
||||||
this.setState({
|
this.setState({
|
||||||
reply: null
|
reply: null
|
||||||
});
|
});
|
||||||
@@ -3499,6 +3788,10 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
this.props.sendMessage(msg, uploadCompletionPromise, uploader, head);
|
this.props.sendMessage(msg, uploadCompletionPromise, uploader, head);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retrySend(pub) {
|
||||||
|
this.props.sendMessage(pub.content, undefined, undefined, pub.head);
|
||||||
|
}
|
||||||
|
|
||||||
sendFileAttachment(file) {
|
sendFileAttachment(file) {
|
||||||
const maxInbandAttachmentSize = this.props.tinode.getServerLimit('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0;
|
const maxInbandAttachmentSize = this.props.tinode.getServerLimit('maxMessageSize', _config_js__WEBPACK_IMPORTED_MODULE_15__.MAX_INBAND_ATTACHMENT_SIZE) * 0.75 - 1024 | 0;
|
||||||
|
|
||||||
@@ -3633,58 +3926,50 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
uploader.cancel();
|
uploader.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePickReply(m) {
|
handlePickReply(seq, content) {
|
||||||
this.setState({
|
this.setState({
|
||||||
reply: null
|
reply: null
|
||||||
});
|
});
|
||||||
|
|
||||||
if (m) {
|
if (!seq || !content) {
|
||||||
let cont = m.content;
|
return;
|
||||||
|
|
||||||
if (cont) {
|
|
||||||
if (typeof cont == 'string') {
|
|
||||||
cont = Drafty.init(cont);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cont = Drafty.preview(cont, 30, quotePreviewFmt);
|
if (typeof content == 'string') {
|
||||||
let header;
|
content = Drafty.init(content);
|
||||||
const seq = m.seq;
|
}
|
||||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
|
||||||
const m0 = topic.findMessage(seq);
|
|
||||||
let thisFrom;
|
|
||||||
|
|
||||||
if (m0) {
|
content = Drafty.preview(content, 30);
|
||||||
thisFrom = m0.from || 'chan';
|
|
||||||
|
|
||||||
if (thisFrom != this.props.myUserId) {
|
|
||||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||||
const user = topic.userDesc(thisFrom);
|
const msg = topic.findMessage(seq);
|
||||||
|
let senderName, senderId;
|
||||||
|
|
||||||
|
if (msg) {
|
||||||
|
senderId = msg.from || 'chan';
|
||||||
|
|
||||||
|
if (senderId != this.props.myUserId) {
|
||||||
|
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||||
|
const user = topic.userDesc(senderId);
|
||||||
|
|
||||||
if (user && user.public) {
|
if (user && user.public) {
|
||||||
header = user.public.fn;
|
senderName = user.public.fn;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
header = this.props.myUserName;
|
senderName = this.props.myUserName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header = Drafty.init(header || '');
|
|
||||||
const ents = [];
|
const ents = [];
|
||||||
|
Drafty.entities(content, (data, idx, tp) => {
|
||||||
if (cont.ent) {
|
|
||||||
Drafty.entities(cont, (data, idx, tp) => {
|
|
||||||
if (tp == 'IM') {
|
if (tp == 'IM') {
|
||||||
ents.push({
|
ents.push({
|
||||||
tp: tp,
|
tp: tp,
|
||||||
data: data
|
data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, this);
|
});
|
||||||
}
|
const promises = ents.map(ex => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
const promises = [];
|
|
||||||
ents.map(ex => {
|
|
||||||
let p = new Promise((resolve, reject) => {
|
|
||||||
const handleFailure = () => {
|
const handleFailure = () => {
|
||||||
ex.data.val = '';
|
ex.data.val = '';
|
||||||
ex.data.name = '';
|
ex.data.name = '';
|
||||||
@@ -3731,22 +4016,17 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
promises.push(p);
|
|
||||||
});
|
});
|
||||||
Promise.all(promises).catch(err => {
|
Promise.all(promises).catch(err => {
|
||||||
this.props.onError(err, 'err');
|
this.props.onError(err, 'err');
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
const msg = Drafty.createQuote(header, cont, (0,_lib_strformat_js__WEBPACK_IMPORTED_MODULE_18__.letterTileColorId)(thisFrom));
|
|
||||||
this.setState({
|
this.setState({
|
||||||
reply: {
|
reply: {
|
||||||
content: msg,
|
content: Drafty.createQuote(senderName, senderId, content),
|
||||||
seq: m.seq
|
seq: seq
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCancelReply() {
|
handleCancelReply() {
|
||||||
@@ -3799,7 +4079,6 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
content: this.state.imagePreview,
|
content: this.state.imagePreview,
|
||||||
tinode: this.props.tinode,
|
tinode: this.props.tinode,
|
||||||
replyTo: this.state.reply,
|
replyTo: this.state.reply,
|
||||||
formatter: draftyFormatter,
|
|
||||||
onCancelReply: this.handleCancelReply,
|
onCancelReply: this.handleCancelReply,
|
||||||
onClose: this.handleClosePreview,
|
onClose: this.handleClosePreview,
|
||||||
onSendMessage: this.sendImageAttachment
|
onSendMessage: this.sendImageAttachment
|
||||||
@@ -3814,7 +4093,6 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
content: this.state.docPreview,
|
content: this.state.docPreview,
|
||||||
tinode: this.props.tinode,
|
tinode: this.props.tinode,
|
||||||
replyTo: this.state.reply,
|
replyTo: this.state.reply,
|
||||||
formatter: draftyFormatter,
|
|
||||||
onCancelReply: this.handleCancelReply,
|
onCancelReply: this.handleCancelReply,
|
||||||
onClose: this.handleClosePreview,
|
onClose: this.handleClosePreview,
|
||||||
onSendMessage: this.sendFileAttachment
|
onSendMessage: this.sendFileAttachment
|
||||||
@@ -3915,7 +4193,6 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
pickReply: this.handlePickReply,
|
pickReply: this.handlePickReply,
|
||||||
replyToSeq: replyToSeq,
|
replyToSeq: replyToSeq,
|
||||||
onQuoteClick: this.handleQuoteClick,
|
onQuoteClick: this.handleQuoteClick,
|
||||||
formatter: draftyFormatter,
|
|
||||||
ref: ref,
|
ref: ref,
|
||||||
userIsWriter: this.state.isWriter,
|
userIsWriter: this.state.isWriter,
|
||||||
key: msg.seq
|
key: msg.seq
|
||||||
@@ -4040,7 +4317,6 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
onError: this.props.onError,
|
onError: this.props.onError,
|
||||||
replyTo: this.state.reply,
|
replyTo: this.state.reply,
|
||||||
onQuoteClick: this.handleQuoteClick,
|
onQuoteClick: this.handleQuoteClick,
|
||||||
formatter: draftyFormatter,
|
|
||||||
onCancelReply: this.handleCancelReply
|
onCancelReply: this.handleCancelReply
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -4055,218 +4331,6 @@ class MessagesView extends (react__WEBPACK_IMPORTED_MODULE_0___default().Compone
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
function quotePreviewFmt(fmt, ent) {
|
|
||||||
let tp = fmt.tp;
|
|
||||||
|
|
||||||
if (!tp) {
|
|
||||||
if (!ent || !ent.tp) {
|
|
||||||
return [null, null];
|
|
||||||
}
|
|
||||||
|
|
||||||
tp = ent.tp;
|
|
||||||
}
|
|
||||||
|
|
||||||
const new_fmt = {
|
|
||||||
at: fmt.at,
|
|
||||||
len: fmt.len,
|
|
||||||
tp: fmt.tp
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (tp) {
|
|
||||||
case 'BR':
|
|
||||||
return [null, null];
|
|
||||||
|
|
||||||
case 'HL':
|
|
||||||
return [new_fmt, ent];
|
|
||||||
|
|
||||||
case 'LN':
|
|
||||||
return [null, null];
|
|
||||||
|
|
||||||
case 'IM':
|
|
||||||
return [new_fmt, ent];
|
|
||||||
|
|
||||||
case 'BN':
|
|
||||||
new_fmt.tp = null;
|
|
||||||
return [new_fmt, {
|
|
||||||
tp: 'IC',
|
|
||||||
data: {
|
|
||||||
orig: 'BN',
|
|
||||||
name: 'button'
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
|
|
||||||
case 'FM':
|
|
||||||
new_fmt.tp = null;
|
|
||||||
return [new_fmt, {
|
|
||||||
tp: 'IC',
|
|
||||||
data: {
|
|
||||||
orig: 'FM',
|
|
||||||
name: 'form'
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
|
|
||||||
case 'RW':
|
|
||||||
return [null, null];
|
|
||||||
|
|
||||||
case 'EX':
|
|
||||||
new_fmt.tp = null;
|
|
||||||
|
|
||||||
if (new_fmt.at == -1) {
|
|
||||||
new_fmt.at = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [new_fmt, {
|
|
||||||
tp: 'IC',
|
|
||||||
data: {
|
|
||||||
orig: 'EX',
|
|
||||||
name: 'attachment'
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
|
|
||||||
case 'QQ':
|
|
||||||
return [null, null];
|
|
||||||
|
|
||||||
default:
|
|
||||||
return [new_fmt, ent];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function draftyFormatter(style, data, values, key) {
|
|
||||||
if (style == 'EX') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let el = Drafty.tagName(style);
|
|
||||||
|
|
||||||
if (el) {
|
|
||||||
const {
|
|
||||||
formatMessage
|
|
||||||
} = this.props.intl;
|
|
||||||
let attr = Drafty.attrValue(style, data) || {};
|
|
||||||
attr.key = key;
|
|
||||||
|
|
||||||
switch (style) {
|
|
||||||
case 'HL':
|
|
||||||
attr.className = 'highlight';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'IM':
|
|
||||||
if (data) {
|
|
||||||
attr.className = 'inline-image';
|
|
||||||
const dim = (0,_lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_16__.fitImageSize)(data.width, data.height, this.props.hasOwnProperty('viewportWidth') ? Math.min(this.props.viewportWidth - _config_js__WEBPACK_IMPORTED_MODULE_15__.REM_SIZE * 6.5, _config_js__WEBPACK_IMPORTED_MODULE_15__.REM_SIZE * 34.5) : _config_js__WEBPACK_IMPORTED_MODULE_15__.REM_SIZE * 34.5, _config_js__WEBPACK_IMPORTED_MODULE_15__.REM_SIZE * 24, false) || {
|
|
||||||
dstWidth: _config_js__WEBPACK_IMPORTED_MODULE_15__.BROKEN_IMAGE_SIZE,
|
|
||||||
dstHeight: _config_js__WEBPACK_IMPORTED_MODULE_15__.BROKEN_IMAGE_SIZE
|
|
||||||
};
|
|
||||||
attr.style = {
|
|
||||||
width: dim.dstWidth + 'px',
|
|
||||||
height: dim.dstHeight + 'px',
|
|
||||||
minWidth: dim.dstWidth + 'px',
|
|
||||||
minHeight: dim.dstHeight + 'px'
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!Drafty.isProcessing(data)) {
|
|
||||||
attr.src = this.props.tinode.authorizeURL((0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_19__.sanitizeImageUrl)(attr.src));
|
|
||||||
attr.alt = data.name;
|
|
||||||
|
|
||||||
if (attr.src) {
|
|
||||||
if (Math.max(data.width || 0, data.height || 0) > _config_js__WEBPACK_IMPORTED_MODULE_15__.IMAGE_THUMBNAIL_DIM) {
|
|
||||||
attr.onClick = this.handleImagePreview;
|
|
||||||
attr.className += ' image-clickable';
|
|
||||||
}
|
|
||||||
|
|
||||||
attr.loading = 'lazy';
|
|
||||||
} else {
|
|
||||||
attr.src = 'img/broken_image.png';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
el = _widgets_uploading_image_jsx__WEBPACK_IMPORTED_MODULE_14__.default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
values = null;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'BN':
|
|
||||||
attr.onClick = this.handleFormButtonClick;
|
|
||||||
let inner = react__WEBPACK_IMPORTED_MODULE_0___default().Children.map(values, child => {
|
|
||||||
return typeof child == 'string' ? child : undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!inner || inner.length == 0) {
|
|
||||||
inner = [attr.name];
|
|
||||||
}
|
|
||||||
|
|
||||||
attr['data-title'] = inner.join('');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'MN':
|
|
||||||
if (data && data.hasOwnProperty('colorId')) {
|
|
||||||
attr.className = 'mn-dark-color' + data.colorId;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'FM':
|
|
||||||
attr.className = 'bot-form';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'RW':
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'QQ':
|
|
||||||
attr.className = 'reply-quote';
|
|
||||||
attr.onClick = this.handleQuoteClick;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'IC':
|
|
||||||
if (data.name == 'button') {
|
|
||||||
attr.className = 'flat-button faux';
|
|
||||||
} else {
|
|
||||||
const icons = {
|
|
||||||
form: {
|
|
||||||
name: 'dashboard',
|
|
||||||
title: 'drafty_form'
|
|
||||||
},
|
|
||||||
attachment: {
|
|
||||||
name: 'attachment',
|
|
||||||
title: 'drafty_attachment'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const icon = icons[data.name];
|
|
||||||
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
|
||||||
|
|
||||||
if (icon) {
|
|
||||||
const key = data.orig.toLowerCase();
|
|
||||||
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
|
||||||
key: key,
|
|
||||||
className: "material-icons"
|
|
||||||
}, icon.name), formatMessage(messages[icon.title])].concat(' ', values || []);
|
|
||||||
} else {
|
|
||||||
values = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (el == '_UNKN') {
|
|
||||||
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
|
||||||
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
|
||||||
className: "material-icons gray"
|
|
||||||
}, "extension"), ' '].concat(values || []);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values);
|
|
||||||
} else {
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
;
|
;
|
||||||
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(MessagesView));
|
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(MessagesView));
|
||||||
|
|
||||||
@@ -7489,7 +7553,8 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
/* harmony import */ var _attachment_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./attachment.jsx */ "./src/widgets/attachment.jsx");
|
/* harmony import */ var _attachment_jsx__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./attachment.jsx */ "./src/widgets/attachment.jsx");
|
||||||
/* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx");
|
/* harmony import */ var _letter_tile_jsx__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./letter-tile.jsx */ "./src/widgets/letter-tile.jsx");
|
||||||
/* harmony import */ var _received_marker_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./received-marker.jsx */ "./src/widgets/received-marker.jsx");
|
/* harmony import */ var _received_marker_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./received-marker.jsx */ "./src/widgets/received-marker.jsx");
|
||||||
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
|
/* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js");
|
||||||
|
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
|
||||||
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||||
|
|
||||||
|
|
||||||
@@ -7500,6 +7565,7 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComponent) {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -7516,6 +7582,16 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
|||||||
this.handleContextClick = this.handleContextClick.bind(this);
|
this.handleContextClick = this.handleContextClick.bind(this);
|
||||||
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
this.handleCancelUpload = this.handleCancelUpload.bind(this);
|
||||||
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
this.handleQuoteClick = this.handleQuoteClick.bind(this);
|
||||||
|
this.formatterContext = {
|
||||||
|
getFormatter: tp => {
|
||||||
|
return tp == 'QQ' ? _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__.quoteFormatter : null;
|
||||||
|
},
|
||||||
|
viewportWidth: this.props.viewportWidth,
|
||||||
|
authorizeURL: this.props.tinode.authorizeURL,
|
||||||
|
onImagePreview: this.handleImagePreview,
|
||||||
|
onFormButtonClick: this.handleFormButtonClick,
|
||||||
|
onQuoteClick: this.handleQuoteClick
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
handleImagePreview(e) {
|
handleImagePreview(e) {
|
||||||
@@ -7542,7 +7618,7 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e.target.dataset.act == 'url') {
|
if (e.target.dataset.act == 'url') {
|
||||||
data.ref = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_6__.sanitizeUrl)(e.target.dataset.ref) || 'about:blank';
|
data.ref = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.sanitizeUrl)(e.target.dataset.ref) || 'about:blank';
|
||||||
}
|
}
|
||||||
|
|
||||||
const text = e.target.dataset.title || 'unknown';
|
const text = e.target.dataset.title || 'unknown';
|
||||||
@@ -7614,7 +7690,7 @@ class BaseChatMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().Pure
|
|||||||
key: i
|
key: i
|
||||||
}));
|
}));
|
||||||
}, this);
|
}, this);
|
||||||
const tree = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(content, this.props.formatter, this);
|
const tree = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_6__.fullFormatter, this.formatterContext);
|
||||||
content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tree);
|
content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tree);
|
||||||
} else if (this.props.deleted) {
|
} else if (this.props.deleted) {
|
||||||
content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
content = react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
@@ -8239,7 +8315,9 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
/* harmony import */ var _unread_badge_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./unread-badge.jsx */ "./src/widgets/unread-badge.jsx");
|
/* harmony import */ var _unread_badge_jsx__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./unread-badge.jsx */ "./src/widgets/unread-badge.jsx");
|
||||||
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
|
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! tinode-sdk */ "tinode-sdk");
|
||||||
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_6__);
|
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_6__);
|
||||||
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
|
/* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js");
|
||||||
|
/* harmony import */ var _lib_utils_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../lib/utils.js */ "./src/lib/utils.js");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -8248,29 +8326,6 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const messages = (0,react_intl__WEBPACK_IMPORTED_MODULE_1__.defineMessages)({
|
|
||||||
drafty_image: {
|
|
||||||
id: "drafty_image",
|
|
||||||
defaultMessage: [{
|
|
||||||
"type": 0,
|
|
||||||
"value": "Picture"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
drafty_form: {
|
|
||||||
id: "drafty_form",
|
|
||||||
defaultMessage: [{
|
|
||||||
"type": 0,
|
|
||||||
"value": "Form:"
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
drafty_attachment: {
|
|
||||||
id: "drafty_attachment",
|
|
||||||
defaultMessage: [{
|
|
||||||
"type": 0,
|
|
||||||
"value": "Attachment"
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
class Contact extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) {
|
class Contact extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -8360,7 +8415,9 @@ class Contact extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const subtitle = this.props.preview ? typeof this.props.preview == 'string' ? this.props.preview : tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.isValid(this.props.preview) ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.format(this.props.preview, draftyFormatter, this)) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
const subtitle = this.props.preview ? typeof this.props.preview == 'string' ? this.props.preview : tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.isValid(this.props.preview) ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.format(this.props.preview, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_7__.previewFormatter, {
|
||||||
|
formatMessage: this.props.intl.formatMessage
|
||||||
|
})) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
className: "material-icons gray"
|
className: "material-icons gray"
|
||||||
}, "error_outline"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
}, "error_outline"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
className: "gray"
|
className: "gray"
|
||||||
@@ -8371,7 +8428,7 @@ class Contact extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) {
|
|||||||
"value": "invalid content"
|
"value": "invalid content"
|
||||||
}]
|
}]
|
||||||
}))) : this.props.comment;
|
}))) : this.props.comment;
|
||||||
const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__.deliveryMarker)(this.props.received);
|
const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_8__.deliveryMarker)(this.props.received);
|
||||||
const marker = icon ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
const marker = icon ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
||||||
className: 'material-icons small space-right' + (icon.color ? ' ' + icon.color : '')
|
className: 'material-icons small space-right' + (icon.color ? ' ' + icon.color : '')
|
||||||
}, icon.name) : null;
|
}, icon.name) : null;
|
||||||
@@ -8417,89 +8474,6 @@ class Contact extends (react__WEBPACK_IMPORTED_MODULE_0___default().Component) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
function draftyFormatter(style, data, values, key) {
|
|
||||||
let el = tinode_sdk__WEBPACK_IMPORTED_MODULE_6__.Drafty.tagName(style);
|
|
||||||
const attr = {
|
|
||||||
key: key
|
|
||||||
};
|
|
||||||
|
|
||||||
if (el) {
|
|
||||||
const {
|
|
||||||
formatMessage
|
|
||||||
} = this.props.intl;
|
|
||||||
|
|
||||||
switch (style) {
|
|
||||||
case 'BR':
|
|
||||||
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
|
||||||
values = [' '];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'HL':
|
|
||||||
attr.className = 'highlight preview';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'LN':
|
|
||||||
case 'MN':
|
|
||||||
el = 'span';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'IM':
|
|
||||||
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
|
||||||
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
|
||||||
key: "im",
|
|
||||||
className: "material-icons"
|
|
||||||
}, "photo"), formatMessage(messages.drafty_image)];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'BN':
|
|
||||||
el = 'span';
|
|
||||||
attr.className = 'flat-button faux';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'FM':
|
|
||||||
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
|
||||||
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
|
||||||
key: "fm",
|
|
||||||
className: "material-icons"
|
|
||||||
}, "dashboard"), formatMessage(messages.drafty_form)].concat(' ', values || []);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'RW':
|
|
||||||
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'EX':
|
|
||||||
if (data && data.mime == 'application/json') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
|
||||||
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
|
||||||
key: "ex",
|
|
||||||
className: "material-icons"
|
|
||||||
}, "attachment"), formatMessage(messages.drafty_attachment)];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (el == '_UNKN') {
|
|
||||||
el = (react__WEBPACK_IMPORTED_MODULE_0___default().Fragment);
|
|
||||||
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
|
|
||||||
key: "unkn",
|
|
||||||
className: "material-icons"
|
|
||||||
}, "extension"), ' '].concat(values || []);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement(el, attr, values);
|
|
||||||
} else {
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
;
|
;
|
||||||
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(Contact));
|
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_intl__WEBPACK_IMPORTED_MODULE_1__.injectIntl)(Contact));
|
||||||
|
|
||||||
@@ -8955,10 +8929,7 @@ class ContextMenu extends (react__WEBPACK_IMPORTED_MODULE_0___default().Componen
|
|||||||
}
|
}
|
||||||
|
|
||||||
replyToMessage(params, errorHandler) {
|
replyToMessage(params, errorHandler) {
|
||||||
params.pickReply({
|
params.pickReply(params.seq, params.content, errorHandler);
|
||||||
seq: params.seq,
|
|
||||||
content: params.content
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -9340,7 +9311,6 @@ class DocPreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCompo
|
|||||||
noInput: true,
|
noInput: true,
|
||||||
tinode: this.props.tinode,
|
tinode: this.props.tinode,
|
||||||
replyTo: this.props.replyTo,
|
replyTo: this.props.replyTo,
|
||||||
formatter: this.props.formatter,
|
|
||||||
onCancelReply: this.props.onCancelReply,
|
onCancelReply: this.props.onCancelReply,
|
||||||
onSendMessage: this.handleSendDoc,
|
onSendMessage: this.handleSendDoc,
|
||||||
onError: this.props.onError
|
onError: this.props.onError
|
||||||
@@ -10000,7 +9970,6 @@ class ImagePreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
|
|||||||
acceptBlank: true,
|
acceptBlank: true,
|
||||||
tinode: this.props.tinode,
|
tinode: this.props.tinode,
|
||||||
replyTo: this.props.replyTo,
|
replyTo: this.props.replyTo,
|
||||||
formatter: this.props.formatter,
|
|
||||||
onCancelReply: this.props.onCancelReply,
|
onCancelReply: this.props.onCancelReply,
|
||||||
onSendMessage: this.handleSendImage,
|
onSendMessage: this.handleSendImage,
|
||||||
onError: this.props.onError
|
onError: this.props.onError
|
||||||
@@ -11274,6 +11243,8 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__);
|
/* harmony import */ var tinode_sdk__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(tinode_sdk__WEBPACK_IMPORTED_MODULE_2__);
|
||||||
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
|
/* harmony import */ var _config_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../config.js */ "./src/config.js");
|
||||||
/* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js");
|
/* harmony import */ var _lib_blob_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../lib/blob-helpers.js */ "./src/lib/blob-helpers.js");
|
||||||
|
/* harmony import */ var _lib_formatters_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../lib/formatters.js */ "./src/lib/formatters.js");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -11451,12 +11422,10 @@ class SendMessage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureComp
|
|||||||
formatMessage
|
formatMessage
|
||||||
} = this.props.intl;
|
} = this.props.intl;
|
||||||
const prompt = this.props.disabled ? formatMessage(messages.messaging_disabled) : this.props.messagePrompt ? formatMessage(messages[this.props.messagePrompt]) : formatMessage(messages.type_new_message);
|
const prompt = this.props.disabled ? formatMessage(messages.messaging_disabled) : this.props.messagePrompt ? formatMessage(messages[this.props.messagePrompt]) : formatMessage(messages.type_new_message);
|
||||||
let quote = null;
|
const quote = this.props.replyTo ? tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(this.props.replyTo.content, _lib_formatters_js__WEBPACK_IMPORTED_MODULE_5__.quoteFormatter, {
|
||||||
|
formatMessage: formatMessage,
|
||||||
if (this.props.replyTo) {
|
authorizeURL: this.props.tinode.authorizeURL
|
||||||
quote = tinode_sdk__WEBPACK_IMPORTED_MODULE_2__.Drafty.format(this.props.replyTo.content, this.props.formatter, this);
|
}) : null;
|
||||||
}
|
|
||||||
|
|
||||||
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
id: "send-message-wrapper"
|
id: "send-message-wrapper"
|
||||||
}, quote ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
}, quote ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+36
-29
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user